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 return ammAlice.ammAccount();
27 else if (v == Bogie)
28 return bogie;
29 else
30 return std::nullopt;
31 };
32
33 // Invalid tokens pair
34 testAMM([&](AMM& ammAlice, Env&) {
35 Account const gw("gw");
36 auto const USD = gw["USD"];
37 auto const jv = ammAlice.ammRpcInfo({}, {}, USD.issue(), USD.issue());
38 BEAST_EXPECT(jv[jss::error_message] == "Account not found.");
39 });
40
41 // Invalid LP account id
42 testAMM([&](AMM& ammAlice, Env&) {
43 auto const jv = ammAlice.ammRpcInfo(bogie.id());
44 BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
45 });
46
47 std::vector<std::tuple<std::optional<Issue>, std::optional<Issue>, TestAccount, bool>> const invalidParams = {
48 {xrpIssue(), std::nullopt, None, false},
49 {std::nullopt, USD.issue(), None, false},
50 {xrpIssue(), std::nullopt, Alice, false},
51 {std::nullopt, USD.issue(), Alice, false},
52 {xrpIssue(), USD.issue(), Alice, false},
54
55 // Invalid parameters
56 testAMM([&](AMM& ammAlice, Env&) {
57 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams)
58 {
59 auto const jv = ammAlice.ammRpcInfo(
60 std::nullopt, std::nullopt, iss1, iss2, accountId(ammAlice, acct), ignoreParams);
61 BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
62 }
63 });
64
65 // Invalid parameters *and* invalid LP account, default API version
66 testAMM([&](AMM& ammAlice, Env&) {
67 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams)
68 {
69 auto const jv = ammAlice.ammRpcInfo(
70 bogie, //
72 iss1,
73 iss2,
74 accountId(ammAlice, acct),
75 ignoreParams);
76 BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
77 }
78 });
79
80 // Invalid parameters *and* invalid LP account, API version 3
81 testAMM([&](AMM& ammAlice, Env&) {
82 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams)
83 {
84 auto const jv = ammAlice.ammRpcInfo(
85 bogie, //
87 iss1,
88 iss2,
89 accountId(ammAlice, acct),
90 ignoreParams,
91 3);
92 BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
93 }
94 });
95
96 // Invalid AMM account id
97 testAMM([&](AMM& ammAlice, Env&) {
98 auto const jv = ammAlice.ammRpcInfo(std::nullopt, std::nullopt, std::nullopt, std::nullopt, bogie.id());
99 BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
100 });
101
103 invalidParamsBadAccount = {
104 {xrpIssue(), std::nullopt, None, false},
105 {std::nullopt, USD.issue(), None, false},
106 {xrpIssue(), std::nullopt, Bogie, false},
107 {std::nullopt, USD.issue(), Bogie, false},
108 {xrpIssue(), USD.issue(), Bogie, false},
109 {std::nullopt, std::nullopt, None, true}};
110
111 // Invalid parameters *and* invalid AMM account, default API version
112 testAMM([&](AMM& ammAlice, Env&) {
113 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParamsBadAccount)
114 {
115 auto const jv = ammAlice.ammRpcInfo(
116 std::nullopt, std::nullopt, iss1, iss2, accountId(ammAlice, acct), ignoreParams);
117 BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
118 }
119 });
120
121 // Invalid parameters *and* invalid AMM account, API version 3
122 testAMM([&](AMM& ammAlice, Env&) {
123 for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParamsBadAccount)
124 {
125 auto const jv = ammAlice.ammRpcInfo(
126 std::nullopt, std::nullopt, iss1, iss2, accountId(ammAlice, acct), ignoreParams, 3);
127 BEAST_EXPECT(
128 jv[jss::error_message] ==
129 (acct == Bogie ? std::string("Account malformed.") : std::string("Invalid parameters.")));
130 }
131 });
132 }
133
134 void
136 {
137 testcase("RPC simple");
138
139 using namespace jtx;
140 testAMM([&](AMM& ammAlice, Env&) {
141 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(XRP(10000), USD(10000), IOUAmount{10000000, 0}));
142 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
143 XRP(10000), USD(10000), IOUAmount{10000000, 0}, std::nullopt, std::nullopt, ammAlice.ammAccount()));
144 });
145 }
146
147 void
149 {
150 testcase("Vote and Bid");
151
152 using namespace jtx;
153 testAMM(
154 [&](AMM& ammAlice, Env& env) {
155 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(XRP(10000), USD(10000), IOUAmount{10000000, 0}));
157 votes.insert({alice.human(), 0});
158 for (int i = 0; i < 7; ++i)
159 {
161 votes.insert({a.human(), 50 * (i + 1)});
162 if (!features[fixAMMv1_3])
163 fund(env, gw, {a}, {USD(10000)}, Fund::Acct);
164 else
165 fund(env, gw, {a}, {USD(10001)}, Fund::Acct);
166 ammAlice.deposit(a, 10000000);
167 ammAlice.vote(a, 50 * (i + 1));
168 }
169 BEAST_EXPECT(ammAlice.expectTradingFee(175));
170 Account ed("ed");
171 Account bill("bill");
172 env.fund(XRP(1000), bob, ed, bill);
173 env(ammAlice.bid({.bidMin = 100, .authAccounts = {carol, bob, ed, bill}}));
174 if (!features[fixAMMv1_3])
175 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
176 XRP(80000),
177 USD(80000),
178 IOUAmount{79994400},
181 ammAlice.ammAccount()));
182 else
183 BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
184 XRPAmount(80000000005),
185 STAmount{USD, UINT64_C(80'000'00000000005), -11},
186 IOUAmount{79994400},
189 ammAlice.ammAccount()));
190 for (auto i = 0; i < 2; ++i)
191 {
192 std::unordered_set<std::string> authAccounts = {
193 carol.human(), bob.human(), ed.human(), bill.human()};
194 auto const ammInfo = i
195 ? ammAlice.ammRpcInfo()
196 : ammAlice.ammRpcInfo(
198 auto const& amm = ammInfo[jss::amm];
199 try
200 {
201 // votes
202 auto const voteSlots = amm[jss::vote_slots];
203 auto votesCopy = votes;
204 for (std::uint8_t i = 0; i < 8; ++i)
205 {
206 if (!BEAST_EXPECT(
207 votes[voteSlots[i][jss::account].asString()] ==
208 voteSlots[i][jss::trading_fee].asUInt() &&
209 voteSlots[i][jss::vote_weight].asUInt() == 12500))
210 return;
211 votes.erase(voteSlots[i][jss::account].asString());
212 }
213 if (!BEAST_EXPECT(votes.empty()))
214 return;
215 votes = votesCopy;
216
217 // bid
218 auto const auctionSlot = amm[jss::auction_slot];
219 for (std::uint8_t i = 0; i < 4; ++i)
220 {
221 if (!BEAST_EXPECT(
222 authAccounts.contains(auctionSlot[jss::auth_accounts][i][jss::account].asString())))
223 return;
224 authAccounts.erase(auctionSlot[jss::auth_accounts][i][jss::account].asString());
225 }
226 if (!BEAST_EXPECT(authAccounts.empty()))
227 return;
228 BEAST_EXPECT(
229 auctionSlot[jss::account].asString() == alice.human() &&
230 auctionSlot[jss::discounted_fee].asUInt() == 17 &&
231 auctionSlot[jss::price][jss::value].asString() == "5600" &&
232 auctionSlot[jss::price][jss::currency].asString() ==
233 to_string(ammAlice.lptIssue().currency) &&
234 auctionSlot[jss::price][jss::issuer].asString() == to_string(ammAlice.lptIssue().account));
235 }
236 catch (std::exception const& e)
237 {
238 fail(e.what(), __FILE__, __LINE__);
239 }
240 }
241 },
243 0,
245 {features});
246 }
247
248 void
250 {
251 using namespace jtx;
252 testAMM([&](AMM& ammAlice, Env& env) {
253 env(fset(gw, asfGlobalFreeze));
254 env.close();
255 auto test = [&](bool freeze) {
256 auto const info = ammAlice.ammRpcInfo();
257 BEAST_EXPECT(info[jss::amm][jss::asset2_frozen].asBool() == freeze);
258 };
259 test(true);
260 env(fclear(gw, asfGlobalFreeze));
261 env.close();
262 test(false);
263 });
264 }
265
266 void
268 {
269 using namespace jtx;
270 testcase("Invalid amm field");
271
272 testAMM([&](AMM& amm, Env&) {
273 auto const resp = amm.ammRpcInfo(std::nullopt, jss::validated.c_str(), std::nullopt, std::nullopt, gw);
274 BEAST_EXPECT(resp.isMember("error") && resp["error"] == "actNotFound");
275 });
276 }
277
278 void
279 run() override
280 {
281 using namespace jtx;
282 auto const all = testable_amendments();
283 testErrors();
284 testSimpleRpc();
285 testVoteAndBid(all);
286 testVoteAndBid(all - fixAMMv1_3);
287 testFreeze();
288 testInvalidAmmField();
289 }
290};
291
292BEAST_DEFINE_TESTSUITE(AMMInfo, rpc, xrpl);
293
294} // namespace test
295} // namespace xrpl
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:148
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:517
Floating point representation of amounts with high dynamic range.
Definition IOUAmount.h:26
Currency currency
Definition Issue.h:16
AccountID account
Definition Issue.h:17
void run() override
Runs the suite.
void testVoteAndBid(FeatureBitset features)
jtx::Account const gw
Definition AMMTest.h:60
jtx::Account const bob
Definition AMMTest.h:63
jtx::Account const alice
Definition AMMTest.h:62
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:61
Convenience class to test AMM functionality.
Definition AMM.h:105
bool expectTradingFee(std::uint16_t fee) const
Definition AMM.cpp:229
Issue lptIssue() const
Definition AMM.h:304
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:496
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:243
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:314
AccountID const & ammAccount() const
Definition AMM.h:298
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:115
Json::Value bid(BidArg const &arg)
Definition AMM.cpp:523
Immutable cryptographic account descriptor.
Definition Account.h:20
std::string const & human() const
Returns the human readable public key.
Definition Account.h:95
AccountID id() const
Returns the Account ID.
Definition Account.h:88
A transaction testing environment.
Definition Env.h:98
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:97
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:260
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
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:90
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:102
FeatureBitset testable_amendments()
Definition Env.h:55
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:6
constexpr std::uint32_t asfGlobalFreeze
Definition TxFlags.h:64
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition Issue.h:98
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:598
T to_string(T... args)
T what(T... args)