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