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