rippled
Loading...
Searching...
No Matches
AMMTest.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2023 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx/AMM.h>
21#include <test/jtx/AMMTest.h>
22#include <test/jtx/CaptureLogs.h>
23#include <test/jtx/Env.h>
24#include <test/jtx/pay.h>
25
26#include <xrpld/rpc/RPCHandler.h>
27#include <xrpld/rpc/detail/RPCHelpers.h>
28
29#include <xrpl/protocol/STParsedJSON.h>
30#include <xrpl/resource/Fees.h>
31
32namespace ripple {
33namespace test {
34namespace jtx {
35
36void
38 jtx::Env& env,
39 jtx::Account const& gw,
40 std::vector<jtx::Account> const& accounts,
41 std::vector<STAmount> const& amts,
42 Fund how)
43{
44 fund(env, gw, accounts, XRP(30000), amts, how);
45}
46
47void
49 jtx::Env& env,
50 std::vector<jtx::Account> const& accounts,
51 STAmount const& xrp,
52 std::vector<STAmount> const& amts,
53 Fund how)
54{
55 for (auto const& account : accounts)
56 {
57 if (how == Fund::All || how == Fund::Acct)
58 {
59 env.fund(xrp, account);
60 }
61 }
62 env.close();
63 for (auto const& account : accounts)
64 {
65 for (auto const& amt : amts)
66 {
67 env.trust(amt + amt, account);
68 env(pay(amt.issue().account, account, amt));
69 }
70 }
71 env.close();
72}
73
74void
76 jtx::Env& env,
77 jtx::Account const& gw,
78 std::vector<jtx::Account> const& accounts,
79 STAmount const& xrp,
80 std::vector<STAmount> const& amts,
81 Fund how)
82{
83 if (how == Fund::All || how == Fund::Gw)
84 env.fund(xrp, gw);
85 env.close();
86 fund(env, accounts, xrp, amts, how);
87}
88
90 : gw("gateway")
91 , carol("carol")
92 , alice("alice")
93 , bob("bob")
94 , USD(gw["USD"])
95 , EUR(gw["EUR"])
96 , GBP(gw["GBP"])
97 , BTC(gw["BTC"])
98 , BAD(jtx::IOU(gw, badCurrency()))
99{
100}
101
102void
104 std::function<void(jtx::AMM&, jtx::Env&)>&& cb,
106 std::uint16_t tfee,
108 std::vector<FeatureBitset> const& vfeatures)
109{
110 testAMM(
111 std::move(cb),
113 .pool = pool, .tfee = tfee, .ter = ter, .features = vfeatures});
114}
115
116void
118 std::function<void(jtx::AMM&, jtx::Env&)>&& cb,
119 TestAMMArg const& arg)
120{
121 using namespace jtx;
122
123 std::string logs;
124
125 for (auto const& features : arg.features)
126 {
127 Env env{
128 *this,
129 features,
130 arg.noLog ? std::make_unique<CaptureLogs>(&logs) : nullptr};
131
132 auto const [asset1, asset2] =
133 arg.pool ? *arg.pool : std::make_pair(XRP(10000), USD(10000));
134 auto tofund = [&](STAmount const& a) -> STAmount {
135 if (a.native())
136 {
137 auto const defXRP = XRP(30000);
138 if (a <= defXRP)
139 return defXRP;
140 return a + XRP(1000);
141 }
142 auto const defIOU = STAmount{a.issue(), 30000};
143 if (a <= defIOU)
144 return defIOU;
145 return a + STAmount{a.issue(), 1000};
146 };
147 auto const toFund1 = tofund(asset1);
148 auto const toFund2 = tofund(asset2);
149 BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2);
150
151 if (!asset1.native() && !asset2.native())
152 fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All);
153 else if (asset1.native())
154 fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All);
155 else if (asset2.native())
156 fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All);
157
158 AMM ammAlice(
159 env,
160 alice,
161 asset1,
162 asset2,
163 CreateArg{.log = false, .tfee = arg.tfee, .err = arg.ter});
164 if (BEAST_EXPECT(
165 ammAlice.expectBalances(asset1, asset2, ammAlice.tokens())))
166 cb(ammAlice, env);
167 }
168}
169
172{
173 return env.current()->fees().accountReserve(count);
174}
175
178{
179 return env.current()->fees().increment;
180}
181
184{
185 // These tests were originally written with search parameters that are
186 // different from the current defaults. This function creates an env
187 // with the search parameters that the tests were written for.
188 return Env(*this, envconfig([](std::unique_ptr<Config> cfg) {
189 cfg->PATH_SEARCH_OLD = 7;
190 cfg->PATH_SEARCH = 7;
191 cfg->PATH_SEARCH_MAX = 10;
192 return cfg;
193 }));
194}
195
198 jtx::Env& env,
199 jtx::Account const& src,
200 jtx::Account const& dst,
201 STAmount const& saDstAmount,
202 std::optional<STAmount> const& saSendMax,
203 std::optional<Currency> const& saSrcCurrency)
204{
205 using namespace jtx;
206
207 auto& app = env.app();
210
211 RPC::JsonContext context{
212 {env.journal,
213 app,
214 loadType,
215 app.getOPs(),
216 app.getLedgerMaster(),
217 c,
219 {},
220 {},
222 {},
223 {}};
224
226 params[jss::command] = "ripple_path_find";
227 params[jss::source_account] = toBase58(src);
228 params[jss::destination_account] = toBase58(dst);
229 params[jss::destination_amount] = saDstAmount.getJson(JsonOptions::none);
230 if (saSendMax)
231 params[jss::send_max] = saSendMax->getJson(JsonOptions::none);
232 if (saSrcCurrency)
233 {
234 auto& sc = params[jss::source_currencies] = Json::arrayValue;
236 j[jss::currency] = to_string(saSrcCurrency.value());
237 sc.append(j);
238 }
239
240 Json::Value result;
241 gate g;
242 app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) {
243 context.params = std::move(params);
244 context.coro = coro;
245 RPC::doCommand(context, result);
246 g.signal();
247 });
248
249 using namespace std::chrono_literals;
250 BEAST_EXPECT(g.wait_for(5s));
251 BEAST_EXPECT(!result.isMember(jss::error));
252 return result;
253}
254
257 jtx::Env& env,
258 jtx::Account const& src,
259 jtx::Account const& dst,
260 STAmount const& saDstAmount,
261 std::optional<STAmount> const& saSendMax,
262 std::optional<Currency> const& saSrcCurrency)
263{
265 env, src, dst, saDstAmount, saSendMax, saSrcCurrency);
266 BEAST_EXPECT(!result.isMember(jss::error));
267
268 STAmount da;
269 if (result.isMember(jss::destination_amount))
270 da = amountFromJson(sfGeneric, result[jss::destination_amount]);
271
272 STAmount sa;
274 if (result.isMember(jss::alternatives))
275 {
276 auto const& alts = result[jss::alternatives];
277 if (alts.size() > 0)
278 {
279 auto const& path = alts[0u];
280
281 if (path.isMember(jss::source_amount))
282 sa = amountFromJson(sfGeneric, path[jss::source_amount]);
283
284 if (path.isMember(jss::destination_amount))
285 da = amountFromJson(sfGeneric, path[jss::destination_amount]);
286
287 if (path.isMember(jss::paths_computed))
288 {
289 Json::Value p;
290 p["Paths"] = path[jss::paths_computed];
291 STParsedJSONObject po("generic", p);
292 paths = po.object->getFieldPathSet(sfPaths);
293 }
294 }
295 }
296
297 return std::make_tuple(std::move(paths), std::move(sa), std::move(da));
298}
299
300} // namespace jtx
301} // namespace test
302} // namespace ripple
Represents a JSON value.
Definition: json_value.h:149
bool isMember(char const *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:962
std::string const & arg() const
Return the argument associated with the runner.
Definition: suite.h:288
A consumption charge.
Definition: Charge.h:30
An endpoint that consumes resources.
Definition: Consumer.h:35
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition: STAmount.cpp:795
Issue const & issue() const
Definition: STAmount.h:496
Holds the serialized result of parsing an input JSON object.
Definition: STParsedJSON.h:33
std::optional< STObject > object
The STObject if the parse was successful.
Definition: STParsedJSON.h:51
jtx::Account const alice
Definition: AMMTest.h:77
jtx::Account const gw
Definition: AMMTest.h:75
jtx::Account const carol
Definition: AMMTest.h:76
void testAMM(std::function< void(jtx::AMM &, jtx::Env &)> &&cb, std::optional< std::pair< STAmount, STAmount > > const &pool=std::nullopt, std::uint16_t tfee=0, std::optional< jtx::ter > const &ter=std::nullopt, std::vector< FeatureBitset > const &features={supported_amendments()})
testAMM() funds 30,000XRP and 30,000IOU for each non-XRP asset to Alice and Carol
Definition: AMMTest.cpp:103
bool wait_for(std::chrono::duration< Rep, Period > const &rel_time)
Definition: AMMTest.h:129
std::tuple< STPathSet, STAmount, STAmount > find_paths(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax=std::nullopt, std::optional< Currency > const &saSrcCurrency=std::nullopt)
Definition: AMMTest.cpp:256
XRPAmount ammCrtFee(jtx::Env &env) const
Definition: AMMTest.cpp:177
XRPAmount reserve(jtx::Env &env, std::uint32_t count) const
Definition: AMMTest.cpp:171
Json::Value find_paths_request(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax=std::nullopt, std::optional< Currency > const &saSrcCurrency=std::nullopt)
Definition: AMMTest.cpp:197
Convenience class to test AMM functionality.
Definition: AMM.h:124
Immutable cryptographic account descriptor.
Definition: Account.h:39
A transaction testing environment.
Definition: Env.h:121
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:331
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:306
Application & app()
Definition: Env.h:261
beast::Journal const journal
Definition: Env.h:162
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:275
Converts to IOU Issue or STAmount.
Add a path.
Definition: paths.h:58
Set Paths, SendMax on a JTx.
Definition: paths.h:35
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:35
T make_pair(T... args)
T make_tuple(T... args)
@ arrayValue
array value (ordered list)
Definition: json_value.h:44
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:45
Status doCommand(RPC::JsonContext &context, Json::Value &result)
Execute an RPC command and store the results in a Json::Value.
Definition: RPCHandler.cpp:222
static constexpr auto apiVersionIfUnspecified
Definition: ApiVersion.h:58
Charge const feeReferenceRPC
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:30
void fund(jtx::Env &env, jtx::Account const &gw, std::vector< jtx::Account > const &accounts, std::vector< STAmount > const &amts, Fund how)
Definition: AMMTest.cpp:37
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:133
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:1035
SField const sfGeneric
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
@ jtCLIENT
Definition: Job.h:45
std::optional< std::pair< STAmount, STAmount > > pool
Definition: AMMTest.h:40
T value(T... args)