rippled
Loading...
Searching...
No Matches
AMMInfo_test.cpp
1#include <test/jtx.h>
2#include <test/jtx/AMM.h>
3#include <test/jtx/AMMTest.h>
4
5#include <xrpl/protocol/jss.h>
6
7#include <unordered_map>
8
9namespace xrpl {
10namespace test {
11
13{
14public:
15 void
17 {
18 testcase("Errors");
19
20 using namespace jtx;
21
22 Account const bogie("bogie");
23 enum TestAccount { None, Alice, Bogie };
24 auto accountId = [&](AMM const& ammAlice, TestAccount v) -> std::optional<AccountID> {
25 if (v == Alice)
26 {
27 return ammAlice.ammAccount();
28 }
29 if (v == Bogie)
30 {
31 return bogie;
32 }
33
34 return std::nullopt;
35 };
36
37 // Invalid tokens pair
38 testAMM([&](AMM& ammAlice, Env&) {
39 Account const gw("gw");
40 auto const USD = gw["USD"];
41 auto const jv = ammAlice.ammRpcInfo({}, {}, USD.issue(), USD.issue());
42 BEAST_EXPECT(jv[jss::error_message] == "Account not found.");
43 });
44
45 // Invalid LP account id
46 testAMM([&](AMM& ammAlice, Env&) {
47 auto const jv = ammAlice.ammRpcInfo(bogie.id());
48 BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
49 });
50
52 invalidParams = {
53 {xrpIssue(), std::nullopt, None, false},
54 {std::nullopt, USD.issue(), None, false},
55 {xrpIssue(), std::nullopt, Alice, false},
56 {std::nullopt, USD.issue(), Alice, false},
57 {xrpIssue(), USD.issue(), Alice, false},
59
60 // Invalid parameters
61 testAMM([&](AMM& ammAlice, Env&) {
62 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams)
63 {
64 auto const jv = ammAlice.ammRpcInfo(
67 iss1,
68 iss2,
69 accountId(ammAlice, acct),
70 ignoreParams);
71 BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
72 }
73 });
74
75 // Invalid parameters *and* invalid LP account, default API version
76 testAMM([&](AMM& ammAlice, Env&) {
77 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams)
78 {
79 auto const jv = ammAlice.ammRpcInfo(
80 bogie, //
82 iss1,
83 iss2,
84 accountId(ammAlice, acct),
85 ignoreParams);
86 BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
87 }
88 });
89
90 // Invalid parameters *and* invalid LP account, API version 3
91 testAMM([&](AMM& ammAlice, Env&) {
92 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams)
93 {
94 auto const jv = ammAlice.ammRpcInfo(
95 bogie, //
97 iss1,
98 iss2,
99 accountId(ammAlice, acct),
100 ignoreParams,
101 3);
102 BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
103 }
104 });
105
106 // Invalid AMM account id
107 testAMM([&](AMM& ammAlice, Env&) {
108 auto const jv = ammAlice.ammRpcInfo(
110 BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
111 });
112
114 invalidParamsBadAccount = {
115 {xrpIssue(), std::nullopt, None, false},
116 {std::nullopt, USD.issue(), None, false},
117 {xrpIssue(), std::nullopt, Bogie, false},
118 {std::nullopt, USD.issue(), Bogie, false},
119 {xrpIssue(), USD.issue(), Bogie, false},
120 {std::nullopt, std::nullopt, None, true}};
121
122 // Invalid parameters *and* invalid AMM account, default API version
123 testAMM([&](AMM& ammAlice, Env&) {
124 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParamsBadAccount)
125 {
126 auto const jv = ammAlice.ammRpcInfo(
129 iss1,
130 iss2,
131 accountId(ammAlice, acct),
132 ignoreParams);
133 BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
134 }
135 });
136
137 // Invalid parameters *and* invalid AMM account, API version 3
138 testAMM([&](AMM& ammAlice, Env&) {
139 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParamsBadAccount)
140 {
141 auto const jv = ammAlice.ammRpcInfo(
144 iss1,
145 iss2,
146 accountId(ammAlice, acct),
147 ignoreParams,
148 3);
149 BEAST_EXPECT(
150 jv[jss::error_message] ==
151 (acct == Bogie ? std::string("Account malformed.")
152 : std::string("Invalid parameters.")));
153 }
154 });
155 }
156
157 void
159 {
160 testcase("RPC simple");
161
162 using namespace jtx;
163 testAMM([&](AMM& ammAlice, Env&) {
164 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(XRP(10000), USD(10000), IOUAmount{10000000, 0}));
165 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
166 XRP(10000),
167 USD(10000),
168 IOUAmount{10000000, 0},
171 ammAlice.ammAccount()));
172 });
173 }
174
175 void
177 {
178 testcase("Vote and Bid");
179
180 using namespace jtx;
181 testAMM(
182 [&](AMM& ammAlice, Env& env) {
183 BEAST_EXPECT(
184 ammAlice.expectAmmRpcInfo(XRP(10000), USD(10000), IOUAmount{10000000, 0}));
186 votes.insert({alice.human(), 0});
187 for (int i = 0; i < 7; ++i)
188 {
190 votes.insert({a.human(), 50 * (i + 1)});
191 if (!features[fixAMMv1_3])
192 {
193 fund(env, gw, {a}, {USD(10000)}, Fund::Acct);
194 }
195 else
196 {
197 fund(env, gw, {a}, {USD(10001)}, Fund::Acct);
198 }
199 ammAlice.deposit(a, 10000000);
200 ammAlice.vote(a, 50 * (i + 1));
201 }
202 BEAST_EXPECT(ammAlice.expectTradingFee(175));
203 Account ed("ed");
204 Account bill("bill");
205 env.fund(XRP(1000), bob, ed, bill);
206 env(ammAlice.bid({.bidMin = 100, .authAccounts = {carol, bob, ed, bill}}));
207 if (!features[fixAMMv1_3])
208 {
209 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
210 XRP(80000),
211 USD(80000),
212 IOUAmount{79994400},
215 ammAlice.ammAccount()));
216 }
217 else
218 {
219 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
220 XRPAmount(80000000005),
221 STAmount{USD, UINT64_C(80'000'00000000005), -11},
222 IOUAmount{79994400},
225 ammAlice.ammAccount()));
226 }
227 for (auto i = 0; i < 2; ++i)
228 {
229 std::unordered_set<std::string> authAccounts = {
230 carol.human(), bob.human(), ed.human(), bill.human()};
231 auto const ammInfo = i ? ammAlice.ammRpcInfo()
232 : ammAlice.ammRpcInfo(
237 ammAlice.ammAccount());
238 auto const& amm = ammInfo[jss::amm];
239 try
240 {
241 // votes
242 auto const voteSlots = amm[jss::vote_slots];
243 auto votesCopy = votes;
244 for (std::uint8_t i = 0; i < 8; ++i)
245 {
246 if (!BEAST_EXPECT(
247 votes[voteSlots[i][jss::account].asString()] ==
248 voteSlots[i][jss::trading_fee].asUInt() &&
249 voteSlots[i][jss::vote_weight].asUInt() == 12500))
250 return;
251 votes.erase(voteSlots[i][jss::account].asString());
252 }
253 if (!BEAST_EXPECT(votes.empty()))
254 return;
255 votes = votesCopy;
256
257 // bid
258 auto const auctionSlot = amm[jss::auction_slot];
259 for (std::uint8_t i = 0; i < 4; ++i)
260 {
261 if (!BEAST_EXPECT(authAccounts.contains(
262 auctionSlot[jss::auth_accounts][i][jss::account].asString())))
263 return;
264 authAccounts.erase(
265 auctionSlot[jss::auth_accounts][i][jss::account].asString());
266 }
267 if (!BEAST_EXPECT(authAccounts.empty()))
268 return;
269 BEAST_EXPECT(
270 auctionSlot[jss::account].asString() == alice.human() &&
271 auctionSlot[jss::discounted_fee].asUInt() == 17 &&
272 auctionSlot[jss::price][jss::value].asString() == "5600" &&
273 auctionSlot[jss::price][jss::currency].asString() ==
274 to_string(ammAlice.lptIssue().currency) &&
275 auctionSlot[jss::price][jss::issuer].asString() ==
276 to_string(ammAlice.lptIssue().account));
277 }
278 catch (std::exception const& e)
279 {
280 fail(e.what(), __FILE__, __LINE__);
281 }
282 }
283 },
285 0,
287 {features});
288 }
289
290 void
292 {
293 using namespace jtx;
294 testAMM([&](AMM& ammAlice, Env& env) {
295 env(fset(gw, asfGlobalFreeze));
296 env.close();
297 auto test = [&](bool freeze) {
298 auto const info = ammAlice.ammRpcInfo();
299 BEAST_EXPECT(info[jss::amm][jss::asset2_frozen].asBool() == freeze);
300 };
301 test(true);
302 env(fclear(gw, asfGlobalFreeze));
303 env.close();
304 test(false);
305 });
306 }
307
308 void
310 {
311 using namespace jtx;
312 testcase("Invalid amm field");
313
314 testAMM([&](AMM& amm, Env&) {
315 auto const resp = amm.ammRpcInfo(
316 std::nullopt, jss::validated.c_str(), std::nullopt, std::nullopt, gw);
317 BEAST_EXPECT(resp.isMember("error") && resp["error"] == "actNotFound");
318 });
319 }
320
321 void
322 run() override
323 {
324 using namespace jtx;
325 auto const all = testable_amendments();
326 testErrors();
327 testSimpleRpc();
328 testVoteAndBid(all);
329 testVoteAndBid(all - fixAMMv1_3);
330 testFreeze();
331 testInvalidAmmField();
332 }
333};
334
335BEAST_DEFINE_TESTSUITE(AMMInfo, rpc, xrpl);
336
337} // namespace test
338} // namespace xrpl
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:519
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:25
Currency currency
Definition Issue.h:15
AccountID account
Definition Issue.h:16
void run() override
Runs the suite.
void testVoteAndBid(FeatureBitset features)
jtx::Account const gw
Definition AMMTest.h:59
jtx::Account const bob
Definition AMMTest.h:62
void testAMM(std::function< void(jtx::AMM &, jtx::Env &)> const &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:84
jtx::Account const alice
Definition AMMTest.h:61
jtx::Account const carol
Definition AMMTest.h:60
Convenience class to test AMM functionality.
bool expectTradingFee(std::uint16_t fee) const
Definition AMM.cpp:284
void vote(std::optional< Account > const &account, std::uint32_t feeVal, std::optional< std::uint32_t > const &flags=std::nullopt, std::optional< jtx::seq > const &seq=std::nullopt, std::optional< std::pair< Issue, Issue > > const &assets=std::nullopt, std::optional< ter > const &ter=std::nullopt)
Definition AMM.cpp:619
bool expectAmmRpcInfo(STAmount const &asset1, STAmount const &asset2, IOUAmount const &balance, std::optional< AccountID > const &account=std::nullopt, std::optional< std::string > const &ledger_index=std::nullopt, std::optional< AccountID > const &ammAccount=std::nullopt) const
Definition AMM.cpp:298
IOUAmount deposit(std::optional< Account > const &account, LPToken tokens, std::optional< STAmount > const &asset1InDetails=std::nullopt, std::optional< std::uint32_t > const &flags=std::nullopt, std::optional< ter > const &ter=std::nullopt)
Definition AMM.cpp:373
AccountID const & ammAccount() const
Json::Value ammRpcInfo(std::optional< AccountID > const &account=std::nullopt, std::optional< std::string > const &ledgerIndex=std::nullopt, std::optional< Issue > issue1=std::nullopt, std::optional< Issue > issue2=std::nullopt, std::optional< AccountID > const &ammAccount=std::nullopt, bool ignoreParams=false, unsigned apiVersion=RPC::apiInvalidVersion) const
Send amm_info RPC command.
Definition AMM.cpp:144
Json::Value bid(BidArg const &arg)
Definition AMM.cpp:646
Immutable cryptographic account descriptor.
Definition Account.h:19
std::string const & human() const
Returns the human readable public key.
Definition Account.h:94
AccountID id() const
Returns the Account ID.
Definition Account.h:87
A transaction testing environment.
Definition Env.h:122
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:100
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:270
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition rpc.h:15
T contains(T... args)
T empty(T... args)
T erase(T... args)
T insert(T... args)
T is_same_v
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:18
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:95
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:101
FeatureBitset testable_amendments()
Definition Env.h:78
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:10
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition Issue.h:97
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
T to_string(T... args)
T what(T... args)