1#include <test/jtx/AMM.h> 
    2#include <test/jtx/Env.h> 
    4#include <xrpld/app/misc/AMMHelpers.h> 
    5#include <xrpld/app/misc/AMMUtils.h> 
    7#include <xrpl/protocol/AMMCore.h> 
    8#include <xrpl/protocol/AmountConversions.h> 
    9#include <xrpl/protocol/ApiVersion.h> 
   10#include <xrpl/protocol/jss.h> 
   50    , creatorAccount_(account)
 
   53    , ammID_(keylet::amm(asset1_.issue(), asset2_.issue()).key)
 
   56    , lastPurchasePrice_(0)
 
   63          asset1_.issue().currency,
 
   64          asset2_.issue().currency,
 
   66    , initialLPTokens_(initialTokens())
 
 
  125    jv[jss::TradingFee] = tfee;
 
  126    jv[jss::TransactionType] = jss::AMMCreate;
 
  128        jv[jss::Flags] = *
flags;
 
  140            return amm->getAccountID(sfAccount);
 
 
  154    unsigned apiVersion)
 const 
  160        jv[jss::ledger_index] = *ledgerIndex;
 
  163        if (issue1 || issue2)
 
  186    if (jr.isObject() && jr.isMember(jss::result) &&
 
  187        jr[jss::result].isMember(jss::status))
 
  188        return jr[jss::result];
 
 
  201        auto const ammAccountID = amm->getAccountID(sfAccount);
 
  202        auto const [asset1Balance, asset2Balance] = 
ammPoolHolds(
 
  209        auto const lptAMMBalance = account
 
  211            : amm->getFieldAmount(sfLPTokenBalance);
 
  212        return {asset1Balance, asset2Balance, lptAMMBalance};
 
 
  224    auto const [asset1Balance, asset2Balance, lptAMMBalance] =
 
  226    return asset1 == asset1Balance && asset2 == asset2Balance &&
 
 
  243        return amm->getFieldAmount(sfLPTokenBalance).iou();
 
 
  253        auto const lptAMMBalance =
 
 
  270        return slotFee == 
fee &&
 
  273            ((!timeSlot && slotInterval == 0) || slotInterval == timeSlot) &&
 
  274            slotPrice == expectedPrice;
 
 
  285        for (
auto const& account : accounts)
 
  290                    account.getAccountID(sfAccount)) == authAccounts.
end())
 
 
  302    return amm && (*amm)[sfTradingFee] == 
fee;
 
 
  336    auto const& jv = jvres[jss::amm];
 
  337    if (!jv.isMember(jss::amount) || !jv.isMember(jss::amount2) ||
 
  338        !jv.isMember(jss::lp_token))
 
  352    return asset1 == asset1Info && asset2 == asset2Info &&
 
 
  387    jv[jss::Account] = acct.human();
 
  389    jv[jss::TransactionType] = jss::AMMDeposit;
 
 
  426    assert(!(asset2In && maxEP));
 
 
  457        asset1In->setJson(jv[jss::Amount]);
 
  459        asset2In->setJson(jv[jss::Amount2]);
 
  461        maxEP->setJson(jv[jss::EPrice]);
 
  463        jv[jss::TradingFee] = *tfee;
 
  474        else if (
tokens && asset1In)
 
  476        else if (asset1In && asset2In)
 
  478        else if (maxEP && asset1In)
 
  483    jv[jss::Flags] = jvflags;
 
 
  513    jv[jss::Account] = acct.human();
 
  515    jv[jss::TransactionType] = jss::AMMWithdraw;
 
 
  550    assert(!(asset2Out && maxEP));
 
 
  579        asset1Out->setJson(jv[jss::Amount]);
 
  581        asset2Out->setJson(jv[jss::Amount2]);
 
  585        saMaxEP.
setJson(jv[jss::EPrice]);
 
  594        else if (asset1Out && asset2Out)
 
  596        else if (
tokens && asset1Out)
 
  598        else if (asset1Out && maxEP)
 
  603    jv[jss::Flags] = jvflags;
 
 
  634    jv[jss::TradingFee] = feeVal;
 
  635    jv[jss::TransactionType] = jss::AMMVote;
 
  637        jv[jss::Flags] = *
flags;
 
 
  656            !
env_.
current()->rules().enabled(fixInnerObjTemplate) ||
 
  657            amm->isFieldPresent(sfAuctionSlot));
 
  658        if (amm->isFieldPresent(sfAuctionSlot))
 
  660            auto const& auctionSlot =
 
  661                static_cast<STObject const&
>(amm->peekAtField(sfAuctionSlot));
 
  672    auto getBid = [&](
auto const& 
bid) {
 
  683        saTokens.
setJson(jv[jss::BidMin]);
 
  689        saTokens.
setJson(jv[jss::BidMax]);
 
  699            acct[jss::Account] = account.human();
 
  700            authAcct[jss::AuthAccount] = acct;
 
  701            accounts.
append(authAcct);
 
  703        jv[jss::AuthAccounts] = accounts;
 
  706        jv[jss::Flags] = *arg.
flags;
 
  707    jv[jss::TransactionType] = jss::AMMBid;
 
 
  751            !
env_.
current()->rules().enabled(fixInnerObjTemplate) ||
 
  752            amm->isFieldPresent(sfAuctionSlot));
 
  753        if (amm->isFieldPresent(sfAuctionSlot))
 
  755            auto const& auctionSlot =
 
  756                static_cast<STObject const&
>(amm->peekAtField(sfAuctionSlot));
 
  757            if (auctionSlot.isFieldPresent(sfAccount))
 
  763                auto const slotFee = auctionSlot[~sfDiscountedFee].value_or(0);
 
  767                auto const slotPrice = auctionSlot[sfPrice].iou();
 
  768                auto const authAccounts =
 
  769                    auctionSlot.getFieldArray(sfAuthAccounts);
 
  770                return cb(slotFee, slotInterval, slotPrice, authAccounts);
 
 
  783    jv[jss::TransactionType] = jss::AMMDelete;
 
 
  794        Throw<std::runtime_error>(
"trust() requires IOU");
 
  798    jv[jss::TransactionType] = jss::TrustSet;
 
  799    jv[jss::Flags] = 
flags;
 
 
  806    jv[jss::Account] = account.human();
 
  809    jv[jss::TransactionType] = jss::Payment;
 
 
  822    jv[jss::TransactionType] = jss::AMMClawback;
 
  823    jv[jss::Account] = issuer.
human();
 
  824    jv[jss::Holder] = holder.
human();
 
  825    jv[jss::Asset] = 
to_json(asset);
 
  826    jv[jss::Asset2] = 
to_json(asset2);
 
 
Value & append(Value const &value)
Append value to array at the end.
 
std::string toStyledString() const
 
bool isMember(char const *key) const
Return true if the object has a member named key.
 
virtual TimeKeeper & timeKeeper()=0
 
Floating point representation of amounts with high dynamic range.
 
A currency issued by an account.
 
void setJson(Json::Value &jv) const
 
Json::Value getJson(JsonOptions=JsonOptions::none) const override
 
void setJson(Json::Value &) const
 
Issue const & issue() const
 
Json::Value getJson(JsonOptions) const override
 
time_point now() const override
Returns the current time, using the server's clock.
 
Convenience class to test AMM functionality.
 
std::optional< IOUAmount > bidMin_
 
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.
 
void submit(Json::Value const &jv, std::optional< jtx::seq > const &seq, std::optional< ter > const &ter)
 
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)
 
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)
 
bool expectAuctionSlot(std::uint32_t fee, std::optional< std::uint8_t > timeSlot, IOUAmount expectedPrice) const
 
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.
 
void ammDelete(AccountID const &deleter, std::optional< ter > const &ter=std::nullopt)
 
bool expectAmmInfo(STAmount const &asset1, STAmount const &asset2, IOUAmount const &balance, Json::Value const &jv) const
 
IOUAmount lastPurchasePrice_
 
AccountID const & ammAccount() const
 
IOUAmount initialTokens()
 
AccountID const ammAccount_
 
bool expectTradingFee(std::uint16_t fee) const
 
std::optional< msig > const msig_
 
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)
 
bool expectBalances(STAmount const &asset1, STAmount const &asset2, IOUAmount const &lpt, std::optional< AccountID > const &account=std::nullopt) const
Verify the AMM balances.
 
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)
 
Account const creatorAccount_
 
std::optional< IOUAmount > bidMax_
 
IOUAmount getLPTokensBalance(std::optional< AccountID > const &account=std::nullopt) const
 
Json::Value bid(BidArg const &arg)
 
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
 
void setTokens(Json::Value &jv, std::optional< std::pair< Issue, Issue > > const &assets=std::nullopt)
 
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)
 
bool expectLPTokens(AccountID const &account, IOUAmount const &tokens) const
 
Immutable cryptographic account descriptor.
 
std::string const & human() const
Returns the human readable public key.
 
A transaction testing environment.
 
TER ter() const
Return the TER for the last JTx.
 
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
 
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
 
bool enabled(uint256 feature) const
 
beast::Journal const journal
 
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
 
Set the expected result code for a JTx The test will fail if the code doesn't match.
 
@ arrayValue
array value (ordered list)
 
static constexpr auto apiInvalidVersion
 
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
 
Keylet account(AccountID const &id) noexcept
AccountID root.
 
Json::Value trust(AccountID const &account, STAmount const &amount, std::uint32_t flags=0)
 
Json::Value ammClawback(Account const &issuer, Account const &holder, Issue const &asset, Issue const &asset2, std::optional< STAmount > const &amount)
 
Json::Value pay(Account const &account, AccountID const &to, STAmount const &amount)
 
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)
 
static Number number(STAmount const &a)
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
constexpr std::uint32_t tfSingleAsset
 
bool isXRP(AccountID const &c)
 
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
 
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
 
constexpr std::uint32_t tfLimitLPToken
 
Issue ammLPTIssue(Currency const &cur1, Currency const &cur2, AccountID const &ammAccountID)
Calculate LPT Issue from AMM asset pair.
 
constexpr std::uint32_t tfOneAssetLPToken
 
constexpr std::uint32_t tfTwoAsset
 
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.
 
Json::Value to_json(Asset const &asset)
 
constexpr std::uint32_t tfDepositSubTx
 
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.
 
constexpr std::uint32_t tfLPToken
 
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
 
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
 
constexpr std::uint32_t tfWithdrawSubTx
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
std::vector< Account > authAccounts
 
std::optional< std::variant< int, IOUAmount, STAmount > > bidMin
 
std::optional< std::uint32_t > flags
 
std::optional< std::variant< int, IOUAmount, STAmount > > bidMax
 
std::optional< Account > account
 
std::optional< std::pair< Issue, Issue > > assets
 
std::optional< std::uint32_t > flags
 
std::optional< jtx::seq > seq
 
std::optional< Account > account
 
std::optional< STAmount > asset1In
 
std::optional< std::pair< Issue, Issue > > assets
 
std::optional< STAmount > maxEP
 
std::optional< STAmount > asset2In
 
std::optional< std::uint16_t > tfee
 
std::optional< LPToken > tokens
 
std::optional< Account > account
 
std::optional< jtx::seq > seq
 
std::optional< std::uint32_t > flags
 
std::optional< std::pair< Issue, Issue > > assets
 
std::optional< STAmount > asset2Out
 
std::optional< IOUAmount > maxEP
 
std::optional< Account > account
 
std::optional< std::uint32_t > flags
 
std::optional< STAmount > asset1Out
 
std::optional< std::pair< Issue, Issue > > assets
 
std::optional< LPToken > tokens
 
std::optional< jtx::seq > seq
 
Set the sequence number on a JTx.