1#include <test/jtx/AMM.h>
3#include <test/jtx/Account.h>
4#include <test/jtx/Env.h>
5#include <test/jtx/multisign.h>
6#include <test/jtx/seq.h>
7#include <test/jtx/ter.h>
9#include <xrpl/basics/Number.h>
10#include <xrpl/basics/contract.h>
11#include <xrpl/basics/safe_cast.h>
12#include <xrpl/json/json_value.h>
13#include <xrpl/json/to_string.h>
14#include <xrpl/ledger/helpers/AMMHelpers.h>
15#include <xrpl/ledger/helpers/TokenHelpers.h>
16#include <xrpl/protocol/AMMCore.h>
17#include <xrpl/protocol/AccountID.h>
18#include <xrpl/protocol/AmountConversions.h>
19#include <xrpl/protocol/ApiVersion.h>
20#include <xrpl/protocol/Asset.h>
21#include <xrpl/protocol/Feature.h>
22#include <xrpl/protocol/IOUAmount.h>
23#include <xrpl/protocol/Indexes.h>
24#include <xrpl/protocol/SField.h>
25#include <xrpl/protocol/STAmount.h>
26#include <xrpl/protocol/STArray.h>
27#include <xrpl/protocol/TER.h>
28#include <xrpl/protocol/TxFlags.h>
29#include <xrpl/protocol/jss.h>
54 if (!
env_.enabled(fixAMMv1_3))
146 jv[jss::TradingFee] = tfee;
147 jv[jss::TransactionType] = jss::AMMCreate;
161 jv[jss::Flags] = *flags;
176 return amm->getAccountID(sfAccount);
190 unsigned apiVersion)
const
195 account.transform(
toJson),
212 unsigned apiVersion)
const
216 jv[jss::account] = *account;
218 jv[jss::ledger_index] = *ledgerIndex;
221 if (asset1 || asset2)
240 if (jr.isObject() && jr.isMember(jss::result) && jr[jss::result].isMember(jss::status))
241 return jr[jss::result];
251 auto const ammAccountID =
amm->getAccountID(sfAccount);
252 auto const [asset1Balance, asset2Balance] =
ammPoolHolds(
260 auto const lptAMMBalance = account
262 :
amm->getFieldAmount(sfLPTokenBalance);
263 return {asset1Balance, asset2Balance, lptAMMBalance};
275 auto const [asset1Balance, asset2Balance, lptAMMBalance] =
277 return asset1 == asset1Balance && asset2 == asset2Balance &&
291 return amm->getFieldAmount(sfLPTokenBalance).iou();
316 return slotFee == fee &&
319 ((!timeSlot && slotInterval == 0) || slotInterval == timeSlot) &&
320 slotPrice == expectedPrice;
329 for (
auto const& account : accounts)
343 return amm && (*amm)[sfTradingFee] == fee;
375 auto const& jv = jvRes[jss::amm];
376 if (!jv.isMember(jss::amount) || !jv.isMember(jss::amount2) || !jv.isMember(jss::lp_token))
390 return asset1 == asset1Info && asset2 == asset2Info &&
416 jv[jss::Account] = arg.
account->human();
420 arg.
tokens->tokens().setJson(jv[jss::LPTokenOut]);
422 arg.
asset1In->setJson(jv[jss::Amount]);
424 arg.
asset2In->setJson(jv[jss::Amount2]);
426 arg.
maxEP->setJson(jv[jss::EPrice]);
428 jv[jss::TradingFee] = *arg.
tfee;
443 flags |= tfOneAssetLPToken;
451 flags |= tfLimitLPToken;
455 flags |= tfSingleAsset;
458 jv[jss::Flags] = flags;
460 jv[jss::TransactionType] = jss::AMMDeposit;
495 if (asset2In && maxEP)
528 .asset1In = asset1In,
529 .asset2In = asset2In,
562 jv[jss::Account] = arg.
account->human();
566 arg.
tokens->tokens().setJson(jv[jss::LPTokenIn]);
570 arg.
asset2Out->setJson(jv[jss::Amount2]);
572 arg.
maxEP->tokens().setJson(jv[jss::EPrice]);
588 flags |= tfOneAssetLPToken;
592 flags |= tfLimitLPToken;
596 flags |= tfSingleAsset;
599 jv[jss::Flags] = flags;
601 jv[jss::TransactionType] = jss::AMMWithdraw;
634 if (asset2Out && maxEP)
665 .asset1Out = asset1Out,
666 .asset2Out = asset2Out,
667 .maxEP = maxEP ? maxEP->tokens(
lptIssue_) : maxEP,
698 jv[jss::Account] = arg.
account->human();
701 jv[jss::TradingFee] = arg.
tfee;
703 jv[jss::Flags] = *arg.
flags;
705 jv[jss::TransactionType] = jss::AMMVote;
741 if (
env_.current()->rules().enabled(fixInnerObjTemplate) &&
742 !
amm->isFieldPresent(sfAuctionSlot))
744 if (
amm->isFieldPresent(sfAuctionSlot))
746 auto const& auctionSlot =
757 auto getBid = [&](
auto const&
bid) {
767 return std::get<STAmount>(
bid);
772 saTokens.
setJson(jv[jss::BidMin]);
778 saTokens.
setJson(jv[jss::BidMax]);
788 acct[jss::Account] = account.human();
789 authAcct[jss::AuthAccount] = acct;
790 accounts.
append(authAcct);
792 jv[jss::AuthAccounts] = accounts;
795 jv[jss::Flags] = *arg.
flags;
796 jv[jss::TransactionType] = jss::AMMBid;
805 auto const& [asset, asset2] = [&]() {
812 jv[jss::Flags] = *arg.
flags;
847 env_(jv, *seq, *ter);
870 if (
env_.current()->rules().enabled(fixInnerObjTemplate) &&
871 !
amm->isFieldPresent(sfAuctionSlot))
873 if (
amm->isFieldPresent(sfAuctionSlot))
875 auto const& auctionSlot =
877 if (auctionSlot.isFieldPresent(sfAccount))
883 auto const slotFee = auctionSlot[~sfDiscountedFee].value_or(0);
885 env_.app().getTimeKeeper().now().time_since_epoch().count(), auctionSlot);
886 auto const slotPrice = auctionSlot[sfPrice].iou();
887 auto const authAccounts = auctionSlot.getFieldArray(sfAuthAccounts);
888 return cb(slotFee, slotInterval, slotPrice, authAccounts);
903 jv[jss::TransactionType] = jss::AMMDelete;
914 submit(jv, std::nullopt, ter);
928 jv[jss::TransactionType] = jss::AMMClawback;
929 jv[jss::Account] = issuer.
human();
930 jv[jss::Holder] = holder.
human();
931 jv[jss::Asset] =
toJson(asset);
932 jv[jss::Asset2] =
toJson(asset2);
std::string toStyledString() const
Value & append(Value const &value)
Append value to array at the end.
bool isMember(char const *key) const
Return true if the object has a member named key.
Floating point representation of amounts with high dynamic range.
Asset const & asset() const
void setJson(json::Value &) const
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
json::Value getJson(JsonOptions) const override
bool expectTradingFee(std::uint16_t fee) const
bool expectAmmRpcInfo(STAmount const &asset1, STAmount const &asset2, IOUAmount const &balance, std::optional< AccountID > const &account=std::nullopt, std::optional< std::string > const &ledgerIndex=std::nullopt, std::optional< AccountID > const &ammAccount=std::nullopt) const
json::Value bid(BidArg const &arg)
IOUAmount getLPTokensBalance(std::optional< AccountID > const &account=std::nullopt) const
std::optional< IOUAmount > bidMax_
static json::Value withdrawJv(WithdrawArg const &arg)
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)
AccountID const ammAccount_
IOUAmount lastPurchasePrice_
static json::Value deleteJv(AccountID const &account, Asset const &asset1, Asset const &assets)
bool expectAuctionSlot(std::uint32_t fee, std::optional< std::uint8_t > timeSlot, IOUAmount expectedPrice) const
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)
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)
Account const creatorAccount_
void submit(json::Value const &jv, std::optional< jtx::Seq > const &seq, std::optional< Ter > const &ter)
void ammDelete(AccountID const &account, std::optional< Ter > const &ter=std::nullopt)
AccountID const & ammAccount() const
std::optional< Msig > const msig_
static json::Value createJv(AccountID const &account, STAmount const &asset1, STAmount const &asset2, std::uint16_t const &tfee)
void setTokens(json::Value &jv, std::optional< std::pair< Asset, Asset > > const &assets=std::nullopt)
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< Asset, Asset > > const &assets=std::nullopt, std::optional< Ter > const &ter=std::nullopt)
static json::Value voteJv(VoteArg const &arg)
std::optional< IOUAmount > bidMin_
bool expectLPTokens(AccountID const &account, IOUAmount const &tokens) const
bool expectAmmInfo(STAmount const &asset1, STAmount const &asset2, IOUAmount const &balance, json::Value const &jv) const
IOUAmount initialTokens()
AMM(Env &env, Account account, STAmount asset1, STAmount 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)
void clawback(ClawbackArg const &arg)
json::Value ammRpcInfo(std::optional< AccountID > const &account=std::nullopt, std::optional< std::string > const &ledgerIndex=std::nullopt, std::optional< Asset > const &asset1=std::nullopt, std::optional< Asset > const &asset2=std::nullopt, std::optional< AccountID > const &ammAccount=std::nullopt, bool ignoreParams=false, unsigned apiVersion=RPC::kApiInvalidVersion) const
Send amm_info RPC command.
std::tuple< STAmount, STAmount, STAmount > balances(Asset const &asset1, Asset const &asset2, std::optional< AccountID > const &account=std::nullopt) const
Get AMM balances for the token pair.
static json::Value depositJv(DepositArg const &arg)
bool expectBalances(STAmount const &asset1, STAmount const &asset2, IOUAmount const &lpt, std::optional< AccountID > const &account=std::nullopt) const
Verify the AMM balances.
IOUAmount const initialLPTokens_
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
Set the expected result code for a JTx The test will fail if the code doesn't match.
T holds_alternative(T... args)
@ Array
array value (ordered list)
static constexpr auto kApiInvalidVersion
Keylet computation functions.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet account(AccountID const &id) noexcept
AccountID root.
json::Value ammClawback(Account const &issuer, Account const &holder, Asset const &asset, Asset const &asset2, std::optional< STAmount > const &amount)
static Number number(STAmount const &a)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount ammLPHolds(ReadView const &view, Asset const &asset1, Asset const &asset2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Dest safeDowncast(Src *s) noexcept
constexpr FlagValue tfDepositSubTx
bool isXRP(AccountID const &c)
std::string to_string(BaseUInt< Bits, Tag > const &a)
std::pair< STAmount, STAmount > ammPoolHolds(ReadView const &view, AccountID const &ammAccountID, Asset const &asset1, Asset const &asset2, FreezeHandling freezeHandling, AuthHandling authHandling, beast::Journal const j)
Get AMM pool balances.
json::Value toJson(Asset const &asset)
bool amountFromJsonNoThrow(STAmount &result, json::Value const &jvSource)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
Issue ammLPTIssue(Asset const &asset1, Asset const &asset2, AccountID const &ammAccountID)
Calculate LPT Issue from AMM asset pair.
constexpr FlagValue tfWithdrawSubTx
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=SpendableHandling::SimpleBalance)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
STAmount toSTAmount(IOUAmount const &iou, Asset const &asset)
std::optional< Account > account
std::optional< std::variant< int, IOUAmount, STAmount > > bidMin
std::vector< Account > authAccounts
std::optional< std::variant< int, IOUAmount, STAmount > > bidMax
std::optional< std::uint32_t > flags
std::optional< std::pair< Asset, Asset > > assets
std::optional< STAmount > amount
std::optional< std::uint32_t > flags
std::optional< std::pair< Asset, Asset > > assets
std::optional< std::uint32_t > flags
std::optional< std::uint16_t > tfee
std::optional< LPToken > tokens
std::optional< STAmount > maxEP
std::optional< std::pair< Asset, Asset > > assets
std::optional< jtx::Seq > seq
std::optional< Account > account
std::optional< STAmount > asset2In
std::optional< STAmount > asset1In
std::optional< std::pair< Asset, Asset > > assets
std::optional< jtx::Seq > seq
std::optional< Account > account
std::optional< std::uint32_t > flags
std::optional< STAmount > asset2Out
std::optional< jtx::Seq > seq
std::optional< std::pair< Asset, Asset > > assets
std::optional< LPToken > maxEP
std::optional< STAmount > asset1Out
std::optional< std::uint32_t > flags
std::optional< Account > account
std::optional< LPToken > tokens