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