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.
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.
std::optional< STObject > object
The STObject if the parse was successful.
jtx::Account const alice
Definition AMMTest.h:77
jtx::Account const gw
Definition AMMTest.h:75
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={testable_amendments()})
testAMM() funds 30,000XRP and 30,000IOU for each non-XRP asset to Alice and Carol
Definition AMMTest.cpp:103
jtx::Account const carol
Definition AMMTest.h:76
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:121
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:320
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:289
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 is_same_v
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.
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:111
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.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
STAmount amountFromJson(SField const &name, Json::Value const &v)
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
SField const sfGeneric
@ jtCLIENT
Definition Job.h:45
std::optional< std::pair< STAmount, STAmount > > pool
Definition AMMTest.h:40
T value(T... args)