rippled
AMM.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 
22 #include <ripple/app/misc/AMMUtils.h>
23 #include <ripple/protocol/AMMCore.h>
24 #include <ripple/protocol/AmountConversions.h>
25 #include <ripple/protocol/jss.h>
26 #include <ripple/rpc/impl/RPCHelpers.h>
27 #include <test/jtx/Env.h>
28 
29 namespace ripple {
30 namespace test {
31 namespace jtx {
32 
33 static Number
34 number(STAmount const& a)
35 {
36  if (isXRP(a))
37  return a.xrp();
38  return a;
39 }
40 
41 static IOUAmount
42 initialTokens(STAmount const& asset1, STAmount const& asset2)
43 {
44  auto const product = number(asset1) * number(asset2);
45  return (IOUAmount)(
46  product.mantissa() >= 0 ? root2(product) : root2(-product));
47 }
48 
50  Env& env,
51  Account const& account,
52  STAmount const& asset1,
53  STAmount const& asset2,
54  bool log,
55  std::uint16_t tfee,
60  std::optional<ter> const& ter,
61  bool close)
62  : env_(env)
63  , creatorAccount_(account)
64  , asset1_(asset1)
65  , asset2_(asset2)
66  , ammID_(keylet::amm(asset1_.issue(), asset2_.issue()).key)
67  , initialLPTokens_(initialTokens(asset1, asset2))
68  , log_(log)
69  , doClose_(close)
70  , lastPurchasePrice_(0)
71  , bidMin_()
72  , bidMax_()
73  , msig_(ms)
74  , fee_(fee)
75  , ammAccount_(create(tfee, flags, seq, ter))
76  , lptIssue_(ripple::ammLPTIssue(
77  asset1_.issue().currency,
78  asset2_.issue().currency,
79  ammAccount_))
80 {
81 }
82 
84  Env& env,
85  Account const& account,
86  STAmount const& asset1,
87  STAmount const& asset2,
88  ter const& ter,
89  bool log,
90  bool close)
91  : AMM(env,
92  account,
93  asset1,
94  asset2,
95  log,
96  0,
97  0,
98  std::nullopt,
99  std::nullopt,
100  std::nullopt,
101  ter,
102  close)
103 {
104 }
105 
107  Env& env,
108  Account const& account,
109  STAmount const& asset1,
110  STAmount const& asset2,
111  CreateArg const& arg)
112  : AMM(env,
113  account,
114  asset1,
115  asset2,
116  arg.log,
117  arg.tfee,
118  arg.fee,
119  arg.flags,
120  arg.seq,
121  arg.ms,
122  arg.err,
123  arg.close)
124 {
125 }
126 
127 [[nodiscard]] AccountID
129  std::uint32_t tfee,
132  std::optional<ter> const& ter)
133 {
134  Json::Value jv;
135  jv[jss::Account] = creatorAccount_.human();
136  jv[jss::Amount] = asset1_.getJson(JsonOptions::none);
137  jv[jss::Amount2] = asset2_.getJson(JsonOptions::none);
138  jv[jss::TradingFee] = tfee;
139  jv[jss::TransactionType] = jss::AMMCreate;
140  if (flags)
141  jv[jss::Flags] = *flags;
142  if (fee_ != 0)
143  jv[jss::Fee] = std::to_string(fee_);
144  else
145  jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops());
146  submit(jv, seq, ter);
147 
148  if (!ter || env_.ter() == tesSUCCESS)
149  {
150  if (auto const amm = env_.current()->read(
152  {
153  return amm->getAccountID(sfAccount);
154  }
155  }
156  return {};
157 }
158 
161  std::optional<AccountID> const& account,
162  std::optional<std::string> const& ledgerIndex,
163  std::optional<Issue> issue1,
164  std::optional<Issue> issue2,
165  std::optional<AccountID> const& ammAccount,
166  bool ignoreParams) const
167 {
168  Json::Value jv;
169  if (account)
170  jv[jss::account] = to_string(*account);
171  if (ledgerIndex)
172  jv[jss::ledger_index] = *ledgerIndex;
173  if (!ignoreParams)
174  {
175  if (issue1 || issue2)
176  {
177  if (issue1)
178  jv[jss::asset] =
180  if (issue2)
181  jv[jss::asset2] =
183  }
184  else if (!ammAccount)
185  {
186  jv[jss::asset] =
188  jv[jss::asset2] =
190  }
191  if (ammAccount)
192  jv[jss::amm_account] = to_string(*ammAccount);
193  }
194  auto jr = env_.rpc("json", "amm_info", to_string(jv));
195  if (jr.isObject() && jr.isMember(jss::result) &&
196  jr[jss::result].isMember(jss::status))
197  return jr[jss::result];
198  return Json::nullValue;
199 }
200 
203  Issue const& issue1,
204  Issue const& issue2,
205  std::optional<AccountID> const& account) const
206 {
207  if (auto const amm =
209  {
210  auto const ammAccountID = amm->getAccountID(sfAccount);
211  auto const [asset1Balance, asset2Balance] = ammPoolHolds(
212  *env_.current(),
213  ammAccountID,
214  issue1,
215  issue2,
216  FreezeHandling::fhIGNORE_FREEZE,
217  env_.journal);
218  auto const lptAMMBalance = account
219  ? ammLPHolds(*env_.current(), *amm, *account, env_.journal)
220  : amm->getFieldAmount(sfLPTokenBalance);
221  return {asset1Balance, asset2Balance, lptAMMBalance};
222  }
223  return {STAmount{}, STAmount{}, STAmount{}};
224 }
225 
226 bool
228  STAmount const& asset1,
229  STAmount const& asset2,
230  IOUAmount const& lpt,
231  std::optional<AccountID> const& account) const
232 {
233  auto const [asset1Balance, asset2Balance, lptAMMBalance] =
234  balances(asset1.issue(), asset2.issue(), account);
235  return asset1 == asset1Balance && asset2 == asset2Balance &&
236  lptAMMBalance == STAmount{lpt, lptIssue_};
237  return false;
238 }
239 
240 IOUAmount
242 {
243  if (account)
244  return accountHolds(
245  *env_.current(),
246  *account,
247  lptIssue_,
248  FreezeHandling::fhZERO_IF_FROZEN,
249  env_.journal)
250  .iou();
251  if (auto const amm =
253  return amm->getFieldAmount(sfLPTokenBalance).iou();
254  return IOUAmount{0};
255 }
256 
257 bool
258 AMM::expectLPTokens(AccountID const& account, IOUAmount const& expTokens) const
259 {
260  if (auto const amm =
262  {
263  auto const lptAMMBalance =
264  ammLPHolds(*env_.current(), *amm, account, env_.journal);
265  return lptAMMBalance == STAmount{expTokens, lptIssue_};
266  }
267  return false;
268 }
269 
270 bool
274  IOUAmount expectedPrice) const
275 {
276  return expectAuctionSlot([&](std::uint32_t slotFee,
277  std::optional<std::uint8_t> slotInterval,
278  IOUAmount const& slotPrice,
279  auto const&) {
280  return slotFee == fee &&
281  // Auction slot might be expired, in which case slotInterval is
282  // 0
283  ((!timeSlot && slotInterval == 0) || slotInterval == timeSlot) &&
284  slotPrice == expectedPrice;
285  });
286 }
287 
288 bool
290 {
291  return expectAuctionSlot([&](std::uint32_t,
293  IOUAmount const&,
294  STArray const& accounts) {
295  for (auto const& account : accounts)
296  {
297  if (std::find(
298  authAccounts.cbegin(),
299  authAccounts.cend(),
300  account.getAccountID(sfAccount)) == authAccounts.end())
301  return false;
302  }
303  return true;
304  });
305 }
306 
307 bool
309 {
310  auto const amm =
312  return amm && (*amm)[sfTradingFee] == fee;
313 }
314 
315 bool
317 {
318  return env_.current()->read(keylet::account(ammAccount_)) != nullptr &&
319  env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())) !=
320  nullptr;
321 }
322 
323 bool
325  STAmount const& asset1,
326  STAmount const& asset2,
327  IOUAmount const& balance,
328  std::optional<AccountID> const& account,
329  std::optional<std::string> const& ledger_index,
330  std::optional<AccountID> const& ammAccount) const
331 {
332  auto const jv = ammRpcInfo(
333  account, ledger_index, std::nullopt, std::nullopt, ammAccount);
334  return expectAmmInfo(asset1, asset2, balance, jv);
335 }
336 
337 bool
339  STAmount const& asset1,
340  STAmount const& asset2,
341  IOUAmount const& balance,
342  Json::Value const& jvres) const
343 {
344  if (!jvres.isMember(jss::amm))
345  return false;
346  auto const& jv = jvres[jss::amm];
347  if (!jv.isMember(jss::amount) || !jv.isMember(jss::amount2) ||
348  !jv.isMember(jss::lp_token))
349  return false;
350  STAmount asset1Info;
351  if (!amountFromJsonNoThrow(asset1Info, jv[jss::amount]))
352  return false;
353  STAmount asset2Info;
354  if (!amountFromJsonNoThrow(asset2Info, jv[jss::amount2]))
355  return false;
356  STAmount lptBalance;
357  if (!amountFromJsonNoThrow(lptBalance, jv[jss::lp_token]))
358  return false;
359  // ammRpcInfo returns unordered assets
360  if (asset1Info.issue() != asset1.issue())
361  std::swap(asset1Info, asset2Info);
362  return asset1 == asset1Info && asset2 == asset2Info &&
363  lptBalance == STAmount{balance, lptIssue_};
364 }
365 
366 void
368  Json::Value& jv,
369  std::optional<std::pair<Issue, Issue>> const& assets)
370 {
371  if (assets)
372  {
373  jv[jss::Asset] =
374  STIssue(sfAsset, assets->first).getJson(JsonOptions::none);
375  jv[jss::Asset2] =
376  STIssue(sfAsset, assets->second).getJson(JsonOptions::none);
377  }
378  else
379  {
380  jv[jss::Asset] =
382  jv[jss::Asset2] =
384  }
385 }
386 
387 IOUAmount
389  std::optional<Account> const& account,
390  Json::Value& jv,
391  std::optional<std::pair<Issue, Issue>> const& assets,
393  std::optional<ter> const& ter)
394 {
395  auto const& acct = account ? *account : creatorAccount_;
396  auto const lpTokens = getLPTokensBalance(acct);
397  jv[jss::Account] = acct.human();
398  setTokens(jv, assets);
399  jv[jss::TransactionType] = jss::AMMDeposit;
400  if (fee_ != 0)
401  jv[jss::Fee] = std::to_string(fee_);
402  submit(jv, seq, ter);
403  return getLPTokensBalance(acct) - lpTokens;
404 }
405 
406 IOUAmount
408  std::optional<Account> const& account,
409  LPToken tokens,
410  std::optional<STAmount> const& asset1In,
412  std::optional<ter> const& ter)
413 {
414  return deposit(
415  account,
416  tokens,
417  asset1In,
418  std::nullopt,
419  std::nullopt,
420  flags,
421  std::nullopt,
422  std::nullopt,
423  std::nullopt,
424  ter);
425 }
426 
427 IOUAmount
429  std::optional<Account> const& account,
430  STAmount const& asset1In,
431  std::optional<STAmount> const& asset2In,
432  std::optional<STAmount> const& maxEP,
434  std::optional<ter> const& ter)
435 {
436  assert(!(asset2In && maxEP));
437  return deposit(
438  account,
439  std::nullopt,
440  asset1In,
441  asset2In,
442  maxEP,
443  flags,
444  std::nullopt,
445  std::nullopt,
446  std::nullopt,
447  ter);
448 }
449 
450 IOUAmount
452  std::optional<Account> const& account,
453  std::optional<LPToken> tokens,
454  std::optional<STAmount> const& asset1In,
455  std::optional<STAmount> const& asset2In,
456  std::optional<STAmount> const& maxEP,
458  std::optional<std::pair<Issue, Issue>> const& assets,
460  std::optional<std::uint16_t> const& tfee,
461  std::optional<ter> const& ter)
462 {
463  Json::Value jv;
464  if (tokens)
465  tokens->tokens(lptIssue_).setJson(jv[jss::LPTokenOut]);
466  if (asset1In)
467  asset1In->setJson(jv[jss::Amount]);
468  if (asset2In)
469  asset2In->setJson(jv[jss::Amount2]);
470  if (maxEP)
471  maxEP->setJson(jv[jss::EPrice]);
472  if (tfee)
473  jv[jss::TradingFee] = *tfee;
474  std::uint32_t jvflags = 0;
475  if (flags)
476  jvflags = *flags;
477  // If including asset1In and asset2In or tokens as
478  // deposit min amounts then must set the flags
479  // explicitly instead of relying on this logic.
480  if (!(jvflags & tfDepositSubTx))
481  {
482  if (tokens && !asset1In)
483  jvflags |= tfLPToken;
484  else if (tokens && asset1In)
485  jvflags |= tfOneAssetLPToken;
486  else if (asset1In && asset2In)
487  jvflags |= tfTwoAsset;
488  else if (maxEP && asset1In)
489  jvflags |= tfLimitLPToken;
490  else if (asset1In)
491  jvflags |= tfSingleAsset;
492  }
493  jv[jss::Flags] = jvflags;
494  return deposit(account, jv, assets, seq, ter);
495 }
496 
497 IOUAmount
499 {
500  return deposit(
501  arg.account,
502  arg.tokens,
503  arg.asset1In,
504  arg.asset2In,
505  arg.maxEP,
506  arg.flags,
507  arg.assets,
508  arg.seq,
509  arg.tfee,
510  arg.err);
511 }
512 
513 IOUAmount
515  std::optional<Account> const& account,
516  Json::Value& jv,
518  std::optional<std::pair<Issue, Issue>> const& assets,
519  std::optional<ter> const& ter)
520 {
521  auto const& acct = account ? *account : creatorAccount_;
522  auto const lpTokens = getLPTokensBalance(acct);
523  jv[jss::Account] = acct.human();
524  setTokens(jv, assets);
525  jv[jss::TransactionType] = jss::AMMWithdraw;
526  if (fee_ != 0)
527  jv[jss::Fee] = std::to_string(fee_);
528  submit(jv, seq, ter);
529  return lpTokens - getLPTokensBalance(acct);
530 }
531 
532 IOUAmount
534  std::optional<Account> const& account,
535  std::optional<LPToken> const& tokens,
536  std::optional<STAmount> const& asset1Out,
538  std::optional<ter> const& ter)
539 {
540  return withdraw(
541  account,
542  tokens,
543  asset1Out,
544  std::nullopt,
545  std::nullopt,
546  flags,
547  std::nullopt,
548  std::nullopt,
549  ter);
550 }
551 
552 IOUAmount
554  std::optional<Account> const& account,
555  STAmount const& asset1Out,
556  std::optional<STAmount> const& asset2Out,
557  std::optional<IOUAmount> const& maxEP,
558  std::optional<ter> const& ter)
559 {
560  assert(!(asset2Out && maxEP));
561  return withdraw(
562  account,
563  std::nullopt,
564  asset1Out,
565  asset2Out,
566  maxEP,
567  std::nullopt,
568  std::nullopt,
569  std::nullopt,
570  ter);
571 }
572 
573 IOUAmount
575  std::optional<Account> const& account,
576  std::optional<LPToken> const& tokens,
577  std::optional<STAmount> const& asset1Out,
578  std::optional<STAmount> const& asset2Out,
579  std::optional<IOUAmount> const& maxEP,
581  std::optional<std::pair<Issue, Issue>> const& assets,
583  std::optional<ter> const& ter)
584 {
585  Json::Value jv;
586  if (tokens)
587  tokens->tokens(lptIssue_).setJson(jv[jss::LPTokenIn]);
588  if (asset1Out)
589  asset1Out->setJson(jv[jss::Amount]);
590  if (asset2Out)
591  asset2Out->setJson(jv[jss::Amount2]);
592  if (maxEP)
593  {
594  STAmount const saMaxEP{*maxEP, lptIssue_};
595  saMaxEP.setJson(jv[jss::EPrice]);
596  }
597  std::uint32_t jvflags = 0;
598  if (flags)
599  jvflags = *flags;
600  if (!(jvflags & tfWithdrawSubTx))
601  {
602  if (tokens && !asset1Out)
603  jvflags |= tfLPToken;
604  else if (asset1Out && asset2Out)
605  jvflags |= tfTwoAsset;
606  else if (tokens && asset1Out)
607  jvflags |= tfOneAssetLPToken;
608  else if (asset1Out && maxEP)
609  jvflags |= tfLimitLPToken;
610  else if (asset1Out)
611  jvflags |= tfSingleAsset;
612  }
613  jv[jss::Flags] = jvflags;
614  return withdraw(account, jv, seq, assets, ter);
615 }
616 
617 IOUAmount
619 {
620  return withdraw(
621  arg.account,
622  arg.tokens,
623  arg.asset1Out,
624  arg.asset2Out,
625  arg.maxEP,
626  arg.flags,
627  arg.assets,
628  arg.seq,
629  arg.err);
630 }
631 
632 void
634  std::optional<Account> const& account,
635  std::uint32_t feeVal,
638  std::optional<std::pair<Issue, Issue>> const& assets,
639  std::optional<ter> const& ter)
640 {
641  Json::Value jv;
642  jv[jss::Account] = account ? account->human() : creatorAccount_.human();
643  setTokens(jv, assets);
644  jv[jss::TradingFee] = feeVal;
645  jv[jss::TransactionType] = jss::AMMVote;
646  if (flags)
647  jv[jss::Flags] = *flags;
648  if (fee_ != 0)
649  jv[jss::Fee] = std::to_string(fee_);
650  submit(jv, seq, ter);
651 }
652 
653 void
654 AMM::vote(VoteArg const& arg)
655 {
656  return vote(arg.account, arg.tfee, arg.flags, arg.seq, arg.assets, arg.err);
657 }
658 
659 void
661  std::optional<Account> const& account,
664  std::vector<Account> const& authAccounts,
667  std::optional<std::pair<Issue, Issue>> const& assets,
668  std::optional<ter> const& ter)
669 {
670  if (auto const amm =
672  {
673  assert(
674  !env_.current()->rules().enabled(fixInnerObjTemplate) ||
675  amm->isFieldPresent(sfAuctionSlot));
676  if (amm->isFieldPresent(sfAuctionSlot))
677  {
678  auto const& auctionSlot =
679  static_cast<STObject const&>(amm->peekAtField(sfAuctionSlot));
680  lastPurchasePrice_ = auctionSlot[sfPrice].iou();
681  }
682  }
683  bidMin_ = std::nullopt;
684  bidMax_ = std::nullopt;
685 
686  Json::Value jv;
687  jv[jss::Account] = account ? account->human() : creatorAccount_.human();
688  setTokens(jv, assets);
689  auto getBid = [&](auto const& bid) {
690  if (std::holds_alternative<int>(bid))
691  return STAmount{lptIssue_, std::get<int>(bid)};
692  else if (std::holds_alternative<IOUAmount>(bid))
693  return toSTAmount(std::get<IOUAmount>(bid), lptIssue_);
694  else
695  return std::get<STAmount>(bid);
696  };
697  if (bidMin)
698  {
699  STAmount saTokens = getBid(*bidMin);
700  saTokens.setJson(jv[jss::BidMin]);
701  bidMin_ = saTokens.iou();
702  }
703  if (bidMax)
704  {
705  STAmount saTokens = getBid(*bidMax);
706  saTokens.setJson(jv[jss::BidMax]);
707  bidMax_ = saTokens.iou();
708  }
709  if (authAccounts.size() > 0)
710  {
711  Json::Value accounts(Json::arrayValue);
712  for (auto const& account : authAccounts)
713  {
714  Json::Value acct;
715  Json::Value authAcct;
716  acct[jss::Account] = account.human();
717  authAcct[jss::AuthAccount] = acct;
718  accounts.append(authAcct);
719  }
720  jv[jss::AuthAccounts] = accounts;
721  }
722  if (flags)
723  jv[jss::Flags] = *flags;
724  jv[jss::TransactionType] = jss::AMMBid;
725  if (fee_ != 0)
726  jv[jss::Fee] = std::to_string(fee_);
727  submit(jv, seq, ter);
728 }
729 
730 void
731 AMM::bid(BidArg const& arg)
732 {
733  return bid(
734  arg.account,
735  arg.bidMin,
736  arg.bidMax,
737  arg.authAccounts,
738  arg.flags,
739  arg.seq,
740  arg.assets,
741  arg.err);
742 }
743 
744 void
746  Json::Value const& jv,
748  std::optional<ter> const& ter)
749 {
750  if (log_)
751  std::cout << jv.toStyledString();
752  if (msig_)
753  {
754  if (seq && ter)
755  env_(jv, *msig_, *seq, *ter);
756  else if (seq)
757  env_(jv, *msig_, *seq);
758  else if (ter)
759  env_(jv, *msig_, *ter);
760  else
761  env_(jv, *msig_);
762  }
763  else if (seq && ter)
764  env_(jv, *seq, *ter);
765  else if (seq)
766  env_(jv, *seq);
767  else if (ter)
768  env_(jv, *ter);
769  else
770  env_(jv);
771  if (doClose_)
772  env_.close();
773 }
774 
775 bool
776 AMM::expectAuctionSlot(auto&& cb) const
777 {
778  if (auto const amm =
780  {
781  assert(
782  !env_.current()->rules().enabled(fixInnerObjTemplate) ||
783  amm->isFieldPresent(sfAuctionSlot));
784  if (amm->isFieldPresent(sfAuctionSlot))
785  {
786  auto const& auctionSlot =
787  static_cast<STObject const&>(amm->peekAtField(sfAuctionSlot));
788  if (auctionSlot.isFieldPresent(sfAccount))
789  {
790  // This could fail in pre-fixInnerObjTemplate tests
791  // if the submitted transactions recreate one of
792  // the failure scenarios. Access as optional
793  // to avoid the failure.
794  auto const slotFee = auctionSlot[~sfDiscountedFee].value_or(0);
795  auto const slotInterval = ammAuctionTimeSlot(
796  env_.app().timeKeeper().now().time_since_epoch().count(),
797  auctionSlot);
798  auto const slotPrice = auctionSlot[sfPrice].iou();
799  auto const authAccounts =
800  auctionSlot.getFieldArray(sfAuthAccounts);
801  return cb(slotFee, slotInterval, slotPrice, authAccounts);
802  }
803  }
804  }
805  return false;
806 }
807 
808 void
810 {
811  Json::Value jv;
812  jv[jss::Account] = to_string(deleter);
813  setTokens(jv);
814  jv[jss::TransactionType] = jss::AMMDelete;
815  if (fee_ != 0)
816  jv[jss::Fee] = std::to_string(fee_);
817  submit(jv, std::nullopt, ter);
818 }
819 
820 namespace amm {
822 trust(AccountID const& account, STAmount const& amount, std::uint32_t flags)
823 {
824  if (isXRP(amount))
825  Throw<std::runtime_error>("trust() requires IOU");
826  Json::Value jv;
827  jv[jss::Account] = to_string(account);
828  jv[jss::LimitAmount] = amount.getJson(JsonOptions::none);
829  jv[jss::TransactionType] = jss::TrustSet;
830  jv[jss::Flags] = flags;
831  return jv;
832 }
834 pay(Account const& account, AccountID const& to, STAmount const& amount)
835 {
836  Json::Value jv;
837  jv[jss::Account] = account.human();
838  jv[jss::Amount] = amount.getJson(JsonOptions::none);
839  jv[jss::Destination] = to_string(to);
840  jv[jss::TransactionType] = jss::Payment;
841  jv[jss::Flags] = tfUniversal;
842  return jv;
843 }
844 } // namespace amm
845 } // namespace jtx
846 } // namespace test
847 } // namespace ripple
ripple::test::jtx::DepositArg::flags
std::optional< std::uint32_t > flags
Definition: AMM.h:79
ripple::test::jtx::WithdrawArg::asset2Out
std::optional< STAmount > asset2Out
Definition: AMM.h:91
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1032
ripple::test::jtx::BidArg::flags
std::optional< std::uint32_t > flags
Definition: AMM.h:115
ripple::root2
Number root2(Number f)
Definition: Number.cpp:689
ripple::sfDiscountedFee
const SF_UINT16 sfDiscountedFee
ripple::Issue
A currency issued by an account.
Definition: Issue.h:35
ripple::sfAsset
const SF_ISSUE sfAsset
ripple::test::jtx::AMM::ammDelete
void ammDelete(AccountID const &deleter, std::optional< ter > const &ter=std::nullopt)
Definition: AMM.cpp:809
ripple::test::jtx::CreateArg
Definition: AMM.h:60
ripple::test::jtx::WithdrawArg
Definition: AMM.h:86
ripple::test::jtx::Env::rpc
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:711
ripple::test::jtx::AMM::msig_
const std::optional< msig > msig_
Definition: AMM.h:138
ripple::test::jtx::AMM::ammAccount
AccountID const & ammAccount() const
Definition: AMM.h:336
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::ammLPTIssue
Issue ammLPTIssue(Currency const &cur1, Currency const &cur2, AccountID const &ammAccountID)
Calculate LPT Issue from AMM asset pair.
Definition: AMMCore.cpp:56
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
std::pair
ripple::test::jtx::DepositArg::tfee
std::optional< std::uint16_t > tfee
Definition: AMM.h:82
ripple::test::jtx::AMM::AMM
AMM(Env &env, Account const &account, STAmount const &asset1, STAmount const &asset2, bool log=false, std::uint16_t tfee=0, std::uint32_t fee=0, std::optional< std::uint32_t > flags=std::nullopt, std::optional< jtx::seq > seq=std::nullopt, std::optional< jtx::msig > ms=std::nullopt, std::optional< ter > const &ter=std::nullopt, bool close=true)
Definition: AMM.cpp:49
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::sfLPTokenBalance
const SF_AMOUNT sfLPTokenBalance
std::vector
STL class.
ripple::test::jtx::WithdrawArg::maxEP
std::optional< IOUAmount > maxEP
Definition: AMM.h:92
std::find
T find(T... args)
ripple::test::jtx::DepositArg::asset1In
std::optional< STAmount > asset1In
Definition: AMM.h:76
std::vector::size
T size(T... args)
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:226
ripple::keylet::amm
Keylet amm(Issue const &issue1, Issue const &issue2) noexcept
AMM entry.
Definition: Indexes.cpp:383
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:653
ripple::test::jtx::BidArg::err
std::optional< ter > err
Definition: AMM.h:118
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:633
ripple::test::jtx::WithdrawArg::asset1Out
std::optional< STAmount > asset1Out
Definition: AMM.h:90
ripple::test::jtx::amm::pay
Json::Value pay(Account const &account, AccountID const &to, STAmount const &amount)
Definition: AMM.cpp:834
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
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:407
std::tuple
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:660
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:43
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::test::jtx::AMM
Convenience class to test AMM functionality.
Definition: AMM.h:123
ripple::test::jtx::DepositArg::asset2In
std::optional< STAmount > asset2In
Definition: AMM.h:77
Json::Value::toStyledString
std::string toStyledString() const
Definition: json_value.cpp:1039
ripple::test::jtx::DepositArg::err
std::optional< ter > err
Definition: AMM.h:83
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::test::jtx::VoteArg::flags
std::optional< std::uint32_t > flags
Definition: AMM.h:103
ripple::test::jtx::AMM::expectAmmInfo
bool expectAmmInfo(STAmount const &asset1, STAmount const &asset2, IOUAmount const &balance, Json::Value const &jv) const
Definition: AMM.cpp:338
ripple::test::jtx::VoteArg::err
std::optional< ter > err
Definition: AMM.h:106
ripple::test::jtx::AMM::creatorAccount_
const Account creatorAccount_
Definition: AMM.h:126
ripple::sfPrice
const SF_AMOUNT sfPrice
ripple::STAmount::iou
IOUAmount iou() const
Definition: STAmount.cpp:360
ripple::test::jtx::Env::ter
TER ter() const
Return the TER for the last JTx.
Definition: Env.h:536
ripple::ammAccountID
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
Definition: AMMCore.cpp:30
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:345
ripple::test::jtx::VoteArg
Definition: AMM.h:99
ripple::sfTradingFee
const SF_UINT16 sfTradingFee
ripple::test::jtx::AMM::expectBalances
bool expectBalances(STAmount const &asset1, STAmount const &asset2, IOUAmount const &lpt, std::optional< AccountID > const &account=std::nullopt) const
Verify the AMM balances.
Definition: AMM.cpp:227
ripple::test::jtx::WithdrawArg::flags
std::optional< std::uint32_t > flags
Definition: AMM.h:93
ripple::ammPoolHolds
std::pair< STAmount, STAmount > ammPoolHolds(ReadView const &view, AccountID const &ammAccountID, Issue const &issue1, Issue const &issue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool balances.
Definition: AMMUtils.cpp:29
ripple::test::jtx::BidArg::authAccounts
std::vector< Account > authAccounts
Definition: AMM.h:114
ripple::test::jtx::DepositArg::seq
std::optional< jtx::seq > seq
Definition: AMM.h:81
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:160
std::cout
ripple::STIssue::getJson
Json::Value getJson(JsonOptions) const override
Definition: STIssue.cpp:74
ripple::test::jtx::DepositArg::tokens
std::optional< LPToken > tokens
Definition: AMM.h:75
ripple::base_uint< 160, detail::AccountIDTag >
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:324
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::sfAsset2
const SF_ISSUE sfAsset2
ripple::STAmount::setJson
void setJson(Json::Value &) const
Definition: STAmount.cpp:528
ripple::test::jtx::initialTokens
static IOUAmount initialTokens(STAmount const &asset1, STAmount const &asset2)
Definition: AMM.cpp:42
ripple::test::jtx::AMM::expectLPTokens
bool expectLPTokens(AccountID const &account, IOUAmount const &tokens) const
Definition: AMM.cpp:258
ripple::test::jtx::WithdrawArg::err
std::optional< ter > err
Definition: AMM.h:96
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:142
ripple::test::jtx::VoteArg::tfee
std::uint32_t tfee
Definition: AMM.h:102
ripple::test::jtx::AMM::lastPurchasePrice_
IOUAmount lastPurchasePrice_
Definition: AMM.h:134
ripple::toSTAmount
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
Definition: AmountConversions.h:30
ripple::sfAuthAccounts
const SField sfAuthAccounts
ripple::tfWithdrawSubTx
constexpr std::uint32_t tfWithdrawSubTx
Definition: TxFlags.h:175
ripple::test::jtx::AMM::log_
bool log_
Definition: AMM.h:131
ripple::STArray
Definition: STArray.h:28
std::to_string
T to_string(T... args)
ripple::test::jtx::AMM::env_
Env & env_
Definition: AMM.h:125
ripple::test::jtx::AMM::lptIssue_
const Issue lptIssue_
Definition: AMM.h:142
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
ripple::test::jtx::AMM::bidMax_
std::optional< IOUAmount > bidMax_
Definition: AMM.h:136
ripple::STAmount
Definition: STAmount.h:46
ripple::test::jtx::BidArg::seq
std::optional< jtx::seq > seq
Definition: AMM.h:116
ripple::test::jtx::amm::trust
Json::Value trust(AccountID const &account, STAmount const &amount, std::uint32_t flags=0)
Definition: AMM.cpp:822
ripple::test::jtx::VoteArg::assets
std::optional< std::pair< Issue, Issue > > assets
Definition: AMM.h:105
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint16_t
ripple::test::jtx::WithdrawArg::assets
std::optional< std::pair< Issue, Issue > > assets
Definition: AMM.h:94
ripple::tfSingleAsset
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:170
ripple::TimeKeeper::now
time_point now() const override
Returns the current time, using the server's clock.
Definition: TimeKeeper.h:64
ripple::STIssue
Definition: STIssue.h:31
ripple::test::jtx::DepositArg
Definition: AMM.h:72
ripple::test::jtx::AMM::expectTradingFee
bool expectTradingFee(std::uint16_t fee) const
Definition: AMM.cpp:308
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
std::swap
T swap(T... args)
ripple::test::jtx::AMM::asset1_
const STAmount asset1_
Definition: AMM.h:127
ripple::test::jtx::AMM::withdraw
IOUAmount withdraw(std::optional< Account > const &account, std::optional< LPToken > const &tokens, std::optional< STAmount > const &asset1OutDetails=std::nullopt, std::optional< std::uint32_t > const &flags=std::nullopt, std::optional< ter > const &ter=std::nullopt)
Definition: AMM.cpp:533
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::test::jtx::AMM::ammExists
bool ammExists() const
Definition: AMM.cpp:316
ripple::test::jtx::VoteArg::seq
std::optional< jtx::seq > seq
Definition: AMM.h:104
ripple::STObject
Definition: STObject.h:54
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::AMM::asset2_
const STAmount asset2_
Definition: AMM.h:128
ripple::test::jtx::AMM::setTokens
void setTokens(Json::Value &jv, std::optional< std::pair< Issue, Issue >> const &assets=std::nullopt)
Definition: AMM.cpp:367
ripple::tfLPToken
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:167
ripple::JsonOptions::none
@ none
Definition: STBase.h:42
ripple::test::jtx::VoteArg::account
std::optional< Account > account
Definition: AMM.h:101
ripple::test::jtx::flags
Match set account flags.
Definition: flags.h:111
ripple::test::jtx::AMM::ammAccount_
const AccountID ammAccount_
Definition: AMM.h:141
ripple::tfDepositSubTx
constexpr std::uint32_t tfDepositSubTx
Definition: TxFlags.h:178
ripple::test::jtx::BidArg::account
std::optional< Account > account
Definition: AMM.h:111
ripple::test::jtx::AMM::tokens
IOUAmount tokens() const
Definition: AMM.h:348
std::vector::cbegin
T cbegin(T... args)
std
STL namespace.
ripple::tfTwoAsset
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:171
ripple::test::jtx::number
static Number number(STAmount const &a)
Definition: AMM.cpp:34
ripple::test::jtx::WithdrawArg::account
std::optional< Account > account
Definition: AMM.h:88
ripple::test::jtx::BidArg::bidMin
std::optional< std::variant< int, IOUAmount, STAmount > > bidMin
Definition: AMM.h:112
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::test::jtx::WithdrawArg::seq
std::optional< jtx::seq > seq
Definition: AMM.h:95
ripple::ammLPHolds
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition: AMMUtils.cpp:104
ripple::test::jtx::AMM::expectAuctionSlot
bool expectAuctionSlot(std::uint32_t fee, std::optional< std::uint8_t > timeSlot, IOUAmount expectedPrice) const
Definition: AMM.cpp:271
ripple::test::jtx::AMM::doClose_
bool doClose_
Definition: AMM.h:132
std::optional< std::uint32_t >
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::AMM::create
AccountID create(std::uint32_t tfee=0, std::optional< std::uint32_t > const &flags=std::nullopt, std::optional< jtx::seq > const &seq=std::nullopt, std::optional< ter > const &ter=std::nullopt)
Definition: AMM.cpp:128
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::test::jtx::AMM::submit
void submit(Json::Value const &jv, std::optional< jtx::seq > const &seq, std::optional< ter > const &ter)
Definition: AMM.cpp:745
std::vector::cend
T cend(T... args)
ripple::test::jtx::LPToken
Definition: AMM.h:37
ripple::test::jtx::BidArg::assets
std::optional< std::pair< Issue, Issue > > assets
Definition: AMM.h:117
ripple::test::jtx::AMM::fee_
const std::uint32_t fee_
Definition: AMM.h:140
ripple::tfOneAssetLPToken
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:172
ripple::tfUniversal
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:59
ripple::test::jtx::BidArg::bidMax
std::optional< std::variant< int, IOUAmount, STAmount > > bidMax
Definition: AMM.h:113
ripple::test::jtx::BidArg
Definition: AMM.h:109
ripple::sfAuctionSlot
const SField sfAuctionSlot
ripple::fixInnerObjTemplate
const uint256 fixInnerObjTemplate
ripple::test::jtx::WithdrawArg::tokens
std::optional< LPToken > tokens
Definition: AMM.h:89
ripple::test::jtx::DepositArg::account
std::optional< Account > account
Definition: AMM.h:74
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:235
ripple::test::jtx::AMM::bidMin_
std::optional< IOUAmount > bidMin_
Definition: AMM.h:135
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:311
ripple::test::jtx::create
Json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
Definition: TestHelpers.cpp:250
ripple::test::jtx::DepositArg::maxEP
std::optional< STAmount > maxEP
Definition: AMM.h:78
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::ammAuctionTimeSlot
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Definition: AMMCore.cpp:107
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::jtx::AMM::balances
std::tuple< STAmount, STAmount, STAmount > balances(Issue const &issue1, Issue const &issue2, std::optional< AccountID > const &account=std::nullopt) const
Get AMM balances for the token pair.
Definition: AMM.cpp:202
std::variant
ripple::tfLimitLPToken
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:173
ripple::test::jtx::AMM::getLPTokensBalance
IOUAmount getLPTokensBalance(std::optional< AccountID > const &account=std::nullopt) const
Definition: AMM.cpp:241
ripple::test::jtx::DepositArg::assets
std::optional< std::pair< Issue, Issue > > assets
Definition: AMM.h:80