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/Env.h>
23#include <test/jtx/pay.h>
24#include <xrpld/rpc/RPCHandler.h>
25#include <xrpld/rpc/detail/RPCHelpers.h>
26#include <xrpl/protocol/STParsedJSON.h>
27#include <xrpl/resource/Fees.h>
28
29namespace ripple {
30namespace test {
31namespace jtx {
32
33void
35 jtx::Env& env,
36 jtx::Account const& gw,
37 std::vector<jtx::Account> const& accounts,
38 std::vector<STAmount> const& amts,
39 Fund how)
40{
41 fund(env, gw, accounts, XRP(30000), amts, how);
42}
43
44void
46 jtx::Env& env,
47 std::vector<jtx::Account> const& accounts,
48 STAmount const& xrp,
49 std::vector<STAmount> const& amts,
50 Fund how)
51{
52 for (auto const& account : accounts)
53 {
54 if (how == Fund::All || how == Fund::Acct)
55 {
56 env.fund(xrp, account);
57 }
58 }
59 env.close();
60 for (auto const& account : accounts)
61 {
62 for (auto const& amt : amts)
63 {
64 env.trust(amt + amt, account);
65 env(pay(amt.issue().account, account, amt));
66 }
67 }
68 env.close();
69}
70
71void
73 jtx::Env& env,
74 jtx::Account const& gw,
75 std::vector<jtx::Account> const& accounts,
76 STAmount const& xrp,
77 std::vector<STAmount> const& amts,
78 Fund how)
79{
80 if (how == Fund::All || how == Fund::Gw)
81 env.fund(xrp, gw);
82 env.close();
83 fund(env, accounts, xrp, amts, how);
84}
85
87 : gw("gateway")
88 , carol("carol")
89 , alice("alice")
90 , bob("bob")
91 , USD(gw["USD"])
92 , EUR(gw["EUR"])
93 , GBP(gw["GBP"])
94 , BTC(gw["BTC"])
95 , BAD(jtx::IOU(gw, badCurrency()))
96{
97}
98
99void
101 std::function<void(jtx::AMM&, jtx::Env&)>&& cb,
103 std::uint16_t tfee,
105 std::vector<FeatureBitset> const& vfeatures)
106{
107 using namespace jtx;
108
109 for (auto const& features : vfeatures)
110 {
111 Env env{*this, features};
112
113 auto const [asset1, asset2] =
114 pool ? *pool : std::make_pair(XRP(10000), USD(10000));
115 auto tofund = [&](STAmount const& a) -> STAmount {
116 if (a.native())
117 {
118 auto const defXRP = XRP(30000);
119 if (a <= defXRP)
120 return defXRP;
121 return a + XRP(1000);
122 }
123 auto const defIOU = STAmount{a.issue(), 30000};
124 if (a <= defIOU)
125 return defIOU;
126 return a + STAmount{a.issue(), 1000};
127 };
128 auto const toFund1 = tofund(asset1);
129 auto const toFund2 = tofund(asset2);
130 BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2);
131
132 if (!asset1.native() && !asset2.native())
133 fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All);
134 else if (asset1.native())
135 fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All);
136 else if (asset2.native())
137 fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All);
138
139 AMM ammAlice(
140 env,
141 alice,
142 asset1,
143 asset2,
144 CreateArg{.log = false, .tfee = tfee, .err = ter});
145 if (BEAST_EXPECT(
146 ammAlice.expectBalances(asset1, asset2, ammAlice.tokens())))
147 cb(ammAlice, env);
148 }
149}
150
153{
154 return env.current()->fees().accountReserve(count);
155}
156
159{
160 return env.current()->fees().increment;
161}
162
165{
166 // These tests were originally written with search parameters that are
167 // different from the current defaults. This function creates an env
168 // with the search parameters that the tests were written for.
169 return Env(*this, envconfig([](std::unique_ptr<Config> cfg) {
170 cfg->PATH_SEARCH_OLD = 7;
171 cfg->PATH_SEARCH = 7;
172 cfg->PATH_SEARCH_MAX = 10;
173 return cfg;
174 }));
175}
176
179 jtx::Env& env,
180 jtx::Account const& src,
181 jtx::Account const& dst,
182 STAmount const& saDstAmount,
183 std::optional<STAmount> const& saSendMax,
184 std::optional<Currency> const& saSrcCurrency)
185{
186 using namespace jtx;
187
188 auto& app = env.app();
191
192 RPC::JsonContext context{
193 {env.journal,
194 app,
195 loadType,
196 app.getOPs(),
197 app.getLedgerMaster(),
198 c,
200 {},
201 {},
203 {},
204 {}};
205
207 params[jss::command] = "ripple_path_find";
208 params[jss::source_account] = toBase58(src);
209 params[jss::destination_account] = toBase58(dst);
210 params[jss::destination_amount] = saDstAmount.getJson(JsonOptions::none);
211 if (saSendMax)
212 params[jss::send_max] = saSendMax->getJson(JsonOptions::none);
213 if (saSrcCurrency)
214 {
215 auto& sc = params[jss::source_currencies] = Json::arrayValue;
217 j[jss::currency] = to_string(saSrcCurrency.value());
218 sc.append(j);
219 }
220
221 Json::Value result;
222 gate g;
223 app.getJobQueue().postCoro(jtCLIENT, "RPC-Client", [&](auto const& coro) {
224 context.params = std::move(params);
225 context.coro = coro;
226 RPC::doCommand(context, result);
227 g.signal();
228 });
229
230 using namespace std::chrono_literals;
231 BEAST_EXPECT(g.wait_for(5s));
232 BEAST_EXPECT(!result.isMember(jss::error));
233 return result;
234}
235
238 jtx::Env& env,
239 jtx::Account const& src,
240 jtx::Account const& dst,
241 STAmount const& saDstAmount,
242 std::optional<STAmount> const& saSendMax,
243 std::optional<Currency> const& saSrcCurrency)
244{
246 env, src, dst, saDstAmount, saSendMax, saSrcCurrency);
247 BEAST_EXPECT(!result.isMember(jss::error));
248
249 STAmount da;
250 if (result.isMember(jss::destination_amount))
251 da = amountFromJson(sfGeneric, result[jss::destination_amount]);
252
253 STAmount sa;
255 if (result.isMember(jss::alternatives))
256 {
257 auto const& alts = result[jss::alternatives];
258 if (alts.size() > 0)
259 {
260 auto const& path = alts[0u];
261
262 if (path.isMember(jss::source_amount))
263 sa = amountFromJson(sfGeneric, path[jss::source_amount]);
264
265 if (path.isMember(jss::destination_amount))
266 da = amountFromJson(sfGeneric, path[jss::destination_amount]);
267
268 if (path.isMember(jss::paths_computed))
269 {
270 Json::Value p;
271 p["Paths"] = path[jss::paths_computed];
272 STParsedJSONObject po("generic", p);
273 paths = po.object->getFieldPathSet(sfPaths);
274 }
275 }
276 }
277
278 return std::make_tuple(std::move(paths), std::move(sa), std::move(da));
279}
280
281} // namespace jtx
282} // namespace test
283} // namespace ripple
Represents a JSON value.
Definition: json_value.h:148
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:949
A consumption charge.
Definition: Charge.h:31
An endpoint that consumes resources.
Definition: Consumer.h:35
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:636
Issue const & issue() const
Definition: STAmount.h:487
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:67
jtx::Account const gw
Definition: AMMTest.h:65
jtx::Account const carol
Definition: AMMTest.h:66
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:100
bool wait_for(std::chrono::duration< Rep, Period > const &rel_time)
Definition: AMMTest.h:114
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:237
XRPAmount ammCrtFee(jtx::Env &env) const
Definition: AMMTest.cpp:158
XRPAmount reserve(jtx::Env &env, std::uint32_t count) const
Definition: AMMTest.cpp:152
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:178
Convenience class to test AMM functionality.
Definition: AMM.h:122
Immutable cryptographic account descriptor.
Definition: Account.h:39
A transaction testing environment.
Definition: Env.h:118
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:326
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:115
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition: Env.cpp:262
Application & app()
Definition: Env.h:256
beast::Journal const journal
Definition: Env.h:159
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:231
Converts to IOU Issue or STAmount.
Add a path.
Definition: paths.h:57
Set Paths, SendMax on a JTx.
Definition: paths.h:34
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:43
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:44
Status doCommand(RPC::JsonContext &context, Json::Value &result)
Execute an RPC command and store the results in a Json::Value.
Definition: RPCHandler.cpp:221
static constexpr auto apiVersionIfUnspecified
Definition: ApiVersion.h:59
Charge const feeReferenceRPC
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
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:34
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:104
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
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:932
SField const sfGeneric
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
@ jtCLIENT
Definition: Job.h:44
T value(T... args)