rippled
AMMInfo_test.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 <ripple/protocol/Feature.h>
21 #include <ripple/protocol/jss.h>
22 #include <test/jtx.h>
23 #include <test/jtx/AMM.h>
24 #include <test/jtx/AMMTest.h>
25 
26 #include <unordered_map>
27 
28 namespace ripple {
29 namespace test {
30 
32 {
33 public:
34  void
36  {
37  testcase("Errors");
38 
39  using namespace jtx;
40  // Invalid tokens pair
41  testAMM([&](AMM& ammAlice, Env&) {
42  Account const gw("gw");
43  auto const USD = gw["USD"];
44  auto const jv =
45  ammAlice.ammRpcInfo({}, {}, USD.issue(), USD.issue());
46  BEAST_EXPECT(jv[jss::error_message] == "Account not found.");
47  });
48 
49  // Invalid LP account id
50  testAMM([&](AMM& ammAlice, Env&) {
51  Account bogie("bogie");
52  auto const jv = ammAlice.ammRpcInfo(bogie.id());
53  BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
54  });
55 
56  // Invalid parameters
57  testAMM([&](AMM& ammAlice, Env&) {
62  bool>>
63  vals = {
64  {xrpIssue(), std::nullopt, std::nullopt, false},
65  {std::nullopt, USD.issue(), std::nullopt, false},
66  {xrpIssue(), std::nullopt, ammAlice.ammAccount(), false},
67  {std::nullopt, USD.issue(), ammAlice.ammAccount(), false},
68  {xrpIssue(), USD.issue(), ammAlice.ammAccount(), false},
69  {std::nullopt, std::nullopt, std::nullopt, true}};
70  for (auto const& [iss1, iss2, acct, ignoreParams] : vals)
71  {
72  auto const jv = ammAlice.ammRpcInfo(
73  std::nullopt, std::nullopt, iss1, iss2, acct, ignoreParams);
74  BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
75  }
76  });
77 
78  // Invalid AMM account id
79  testAMM([&](AMM& ammAlice, Env&) {
80  Account bogie("bogie");
81  auto const jv = ammAlice.ammRpcInfo(
82  std::nullopt,
83  std::nullopt,
84  std::nullopt,
85  std::nullopt,
86  bogie.id());
87  BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
88  });
89  }
90 
91  void
93  {
94  testcase("RPC simple");
95 
96  using namespace jtx;
97  testAMM([&](AMM& ammAlice, Env&) {
98  BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
99  XRP(10000), USD(10000), IOUAmount{10000000, 0}));
100  BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
101  XRP(10000),
102  USD(10000),
103  IOUAmount{10000000, 0},
104  std::nullopt,
105  std::nullopt,
106  ammAlice.ammAccount()));
107  });
108  }
109 
110  void
112  {
113  testcase("Vote and Bid");
114 
115  using namespace jtx;
116  testAMM([&](AMM& ammAlice, Env& env) {
117  BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
118  XRP(10000), USD(10000), IOUAmount{10000000, 0}));
120  votes.insert({alice.human(), 0});
121  for (int i = 0; i < 7; ++i)
122  {
123  Account a(std::to_string(i));
124  votes.insert({a.human(), 50 * (i + 1)});
125  fund(env, gw, {a}, {USD(10000)}, Fund::Acct);
126  ammAlice.deposit(a, 10000000);
127  ammAlice.vote(a, 50 * (i + 1));
128  }
129  BEAST_EXPECT(ammAlice.expectTradingFee(175));
130  Account ed("ed");
131  Account bill("bill");
132  env.fund(XRP(1000), bob, ed, bill);
133  ammAlice.bid(alice, 100, std::nullopt, {carol, bob, ed, bill});
134  BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
135  XRP(80000),
136  USD(80000),
137  IOUAmount{79994400},
138  std::nullopt,
139  std::nullopt,
140  ammAlice.ammAccount()));
141  for (auto i = 0; i < 2; ++i)
142  {
143  std::unordered_set<std::string> authAccounts = {
144  carol.human(), bob.human(), ed.human(), bill.human()};
145  auto const ammInfo = i ? ammAlice.ammRpcInfo()
146  : ammAlice.ammRpcInfo(
147  std::nullopt,
148  std::nullopt,
149  std::nullopt,
150  std::nullopt,
151  ammAlice.ammAccount());
152  auto const& amm = ammInfo[jss::amm];
153  try
154  {
155  // votes
156  auto const voteSlots = amm[jss::vote_slots];
157  auto votesCopy = votes;
158  for (std::uint8_t i = 0; i < 8; ++i)
159  {
160  if (!BEAST_EXPECT(
161  votes[voteSlots[i][jss::account].asString()] ==
162  voteSlots[i][jss::trading_fee].asUInt() &&
163  voteSlots[i][jss::vote_weight].asUInt() ==
164  12500))
165  return;
166  votes.erase(voteSlots[i][jss::account].asString());
167  }
168  if (!BEAST_EXPECT(votes.empty()))
169  return;
170  votes = votesCopy;
171 
172  // bid
173  auto const auctionSlot = amm[jss::auction_slot];
174  for (std::uint8_t i = 0; i < 4; ++i)
175  {
176  if (!BEAST_EXPECT(authAccounts.contains(
177  auctionSlot[jss::auth_accounts][i][jss::account]
178  .asString())))
179  return;
180  authAccounts.erase(
181  auctionSlot[jss::auth_accounts][i][jss::account]
182  .asString());
183  }
184  if (!BEAST_EXPECT(authAccounts.empty()))
185  return;
186  BEAST_EXPECT(
187  auctionSlot[jss::account].asString() == alice.human() &&
188  auctionSlot[jss::discounted_fee].asUInt() == 17 &&
189  auctionSlot[jss::price][jss::value].asString() ==
190  "5600" &&
191  auctionSlot[jss::price][jss::currency].asString() ==
192  to_string(ammAlice.lptIssue().currency) &&
193  auctionSlot[jss::price][jss::issuer].asString() ==
194  to_string(ammAlice.lptIssue().account));
195  }
196  catch (std::exception const& e)
197  {
198  fail(e.what(), __FILE__, __LINE__);
199  }
200  }
201  });
202  }
203 
204  void
206  {
207  using namespace jtx;
208  testAMM([&](AMM& ammAlice, Env& env) {
209  env(fset(gw, asfGlobalFreeze));
210  env.close();
211  auto test = [&](bool freeze) {
212  auto const info = ammAlice.ammRpcInfo();
213  BEAST_EXPECT(
214  info[jss::amm][jss::asset2_frozen].asBool() == freeze);
215  };
216  test(true);
217  env(fclear(gw, asfGlobalFreeze));
218  env.close();
219  test(false);
220  });
221  }
222 
223  void
224  run() override
225  {
226  testErrors();
227  testSimpleRpc();
228  testVoteAndBid();
229  testFreeze();
230  }
231 };
232 
233 BEAST_DEFINE_TESTSUITE(AMMInfo, app, ripple);
234 
235 } // namespace test
236 } // namespace ripple
ripple::test::jtx::AMMTestBase::USD
const jtx::IOU USD
Definition: AMMTest.h:68
ripple::test::AMMInfo_test::testErrors
void testErrors()
Definition: AMMInfo_test.cpp:35
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
std::exception
STL class.
ripple::test::jtx::AMM::ammAccount
AccountID const & ammAccount() const
Definition: AMM.h:255
ripple::test::AMMInfo_test
Definition: AMMInfo_test.cpp:31
std::unordered_set
STL class.
std::vector
STL class.
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
ripple::test::jtx::AMM::vote
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:578
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::test::jtx::AMMTestBase::gw
const jtx::Account gw
Definition: AMMTest.h:64
ripple::test::jtx::AMMTestBase::carol
const jtx::Account carol
Definition: AMMTest.h:65
ripple::test::jtx::AMM::deposit
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:383
ripple::test::jtx::AMMTestBase::alice
const jtx::Account alice
Definition: AMMTest.h:66
std::tuple
ripple::test::jtx::IOU::issue
Issue issue() const
Definition: amount.h:303
ripple::test::jtx::AMM::bid
void bid(std::optional< Account > const &account, std::optional< std::variant< int, IOUAmount, STAmount >> const &bidMin=std::nullopt, std::optional< std::variant< int, IOUAmount, STAmount >> const &bidMax=std::nullopt, std::vector< Account > const &authAccounts={}, 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:599
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:43
ripple::test::jtx::AMM
Convenience class to test AMM functionality.
Definition: AMM.h:62
ripple::test::TrustFlag::freeze
@ freeze
std::unordered_set::contains
T contains(T... args)
ripple::test::jtx::Account::id
AccountID id() const
Returns the Account ID.
Definition: Account.h:106
ripple::test::jtx::AMM::ammRpcInfo
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) const
Send amm_info RPC command.
Definition: AMM.cpp:136
ripple::test::jtx::AMM::expectAmmRpcInfo
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:300
ripple::test::jtx::AMMTestBase::bob
const jtx::Account bob
Definition: AMMTest.h:67
ripple::test::jtx::AMMTestBase
Definition: AMMTest.h:61
ripple::test::jtx::fset
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
std::to_string
T to_string(T... args)
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
std::unordered_map::erase
T erase(T... args)
std::uint8_t
ripple::test::AMMInfo_test::testVoteAndBid
void testVoteAndBid()
Definition: AMMInfo_test.cpp:111
ripple::test::AMMInfo_test::run
void run() override
Definition: AMMInfo_test.cpp:224
ripple::test::jtx::fclear
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition: flags.h:40
ripple::test::jtx::AMM::expectTradingFee
bool expectTradingFee(std::uint16_t fee) const
Definition: AMM.cpp:284
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::unordered_map::insert
T insert(T... args)
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::test::jtx::fund
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::unordered_map::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:105
ripple::asfGlobalFreeze
constexpr std::uint32_t asfGlobalFreeze
Definition: TxFlags.h:80
ripple::test::AMMInfo_test::testFreeze
void testFreeze()
Definition: AMMInfo_test.cpp:205
std::optional
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::test::AMMInfo_test::testSimpleRpc
void testSimpleRpc()
Definition: AMMInfo_test.cpp:92
unordered_map
ripple::test::jtx::AMMTestBase::testAMM
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::optional< FeatureBitset > const &features=std::nullopt)
testAMM() funds 30,000XRP and 30,000IOU for each non-XRP asset to Alice and Carol
Definition: AMMTest.cpp:101
ripple::test::jtx::AMM::lptIssue
Issue lptIssue() const
Definition: AMM.h:261
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::Issue::account
AccountID account
Definition: Issue.h:39
std::exception::what
T what(T... args)
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)