mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-23 07:10:53 +00:00
feat: Add MPT support to DEX (#5285)
This commit is contained in:
committed by
GitHub
parent
6d1a5be8d2
commit
dfcad69155
@@ -49,14 +49,14 @@ AMM::AMM(
|
||||
, creatorAccount_(account)
|
||||
, asset1_(asset1)
|
||||
, asset2_(asset2)
|
||||
, ammID_(keylet::amm(asset1_.issue(), asset2_.issue()).key)
|
||||
, ammID_(keylet::amm(asset1_.asset(), asset2_.asset()).key)
|
||||
, log_(log)
|
||||
, doClose_(close)
|
||||
, lastPurchasePrice_(0)
|
||||
, msig_(ms)
|
||||
, fee_(fee)
|
||||
, ammAccount_(create(tfee, flags, seq, ter))
|
||||
, lptIssue_(xrpl::ammLPTIssue(asset1_.issue().currency, asset2_.issue().currency, ammAccount_))
|
||||
, lptIssue_(xrpl::ammLPTIssue(asset1_.asset(), asset2_.asset(), ammAccount_))
|
||||
, initialLPTokens_(initialTokens())
|
||||
{
|
||||
}
|
||||
@@ -105,6 +105,23 @@ AMM::AMM(
|
||||
{
|
||||
}
|
||||
|
||||
Json::Value
|
||||
AMM::createJv(
|
||||
AccountID const& account,
|
||||
STAmount const& asset1,
|
||||
STAmount const& asset2,
|
||||
std::uint16_t const& tfee)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = to_string(account);
|
||||
jv[jss::Amount] = asset1.getJson(JsonOptions::none);
|
||||
jv[jss::Amount2] = asset2.getJson(JsonOptions::none);
|
||||
jv[jss::TradingFee] = tfee;
|
||||
jv[jss::TransactionType] = jss::AMMCreate;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
[[nodiscard]] AccountID
|
||||
AMM::create(
|
||||
std::uint32_t tfee,
|
||||
@@ -112,12 +129,7 @@ AMM::create(
|
||||
std::optional<jtx::seq> const& seq,
|
||||
std::optional<ter> const& ter)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = creatorAccount_.human();
|
||||
jv[jss::Amount] = asset1_.getJson(JsonOptions::none);
|
||||
jv[jss::Amount2] = asset2_.getJson(JsonOptions::none);
|
||||
jv[jss::TradingFee] = tfee;
|
||||
jv[jss::TransactionType] = jss::AMMCreate;
|
||||
Json::Value jv = createJv(creatorAccount_, asset1_, asset2_, tfee);
|
||||
if (flags)
|
||||
jv[jss::Flags] = *flags;
|
||||
if (fee_ != 0)
|
||||
@@ -132,7 +144,7 @@ AMM::create(
|
||||
|
||||
if (!ter || env_.ter() == tesSUCCESS)
|
||||
{
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())))
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())))
|
||||
{
|
||||
return amm->getAccountID(sfAccount);
|
||||
}
|
||||
@@ -144,8 +156,8 @@ Json::Value
|
||||
AMM::ammRpcInfo(
|
||||
std::optional<AccountID> const& account,
|
||||
std::optional<std::string> const& ledgerIndex,
|
||||
std::optional<Issue> issue1,
|
||||
std::optional<Issue> issue2,
|
||||
std::optional<Asset> asset1,
|
||||
std::optional<Asset> asset2,
|
||||
std::optional<AccountID> const& ammAccount,
|
||||
bool ignoreParams,
|
||||
unsigned apiVersion) const
|
||||
@@ -157,17 +169,17 @@ AMM::ammRpcInfo(
|
||||
jv[jss::ledger_index] = *ledgerIndex;
|
||||
if (!ignoreParams)
|
||||
{
|
||||
if (issue1 || issue2)
|
||||
if (asset1 || asset2)
|
||||
{
|
||||
if (issue1)
|
||||
jv[jss::asset] = STIssue(sfAsset, *issue1).getJson(JsonOptions::none);
|
||||
if (issue2)
|
||||
jv[jss::asset2] = STIssue(sfAsset2, *issue2).getJson(JsonOptions::none);
|
||||
if (asset1)
|
||||
jv[jss::asset] = STIssue(sfAsset, *asset1).getJson(JsonOptions::none);
|
||||
if (asset2)
|
||||
jv[jss::asset2] = STIssue(sfAsset2, *asset2).getJson(JsonOptions::none);
|
||||
}
|
||||
else if (!ammAccount)
|
||||
{
|
||||
jv[jss::asset] = STIssue(sfAsset, asset1_.issue()).getJson(JsonOptions::none);
|
||||
jv[jss::asset2] = STIssue(sfAsset2, asset2_.issue()).getJson(JsonOptions::none);
|
||||
jv[jss::asset] = STIssue(sfAsset, asset1_.asset()).getJson(JsonOptions::none);
|
||||
jv[jss::asset2] = STIssue(sfAsset2, asset2_.asset()).getJson(JsonOptions::none);
|
||||
}
|
||||
if (ammAccount)
|
||||
jv[jss::amm_account] = to_string(*ammAccount);
|
||||
@@ -182,18 +194,19 @@ AMM::ammRpcInfo(
|
||||
}
|
||||
|
||||
std::tuple<STAmount, STAmount, STAmount>
|
||||
AMM::balances(Issue const& issue1, Issue const& issue2, std::optional<AccountID> const& account)
|
||||
AMM::balances(Asset const& asset1, Asset const& asset2, std::optional<AccountID> const& account)
|
||||
const
|
||||
{
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())))
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())))
|
||||
{
|
||||
auto const ammAccountID = amm->getAccountID(sfAccount);
|
||||
auto const [asset1Balance, asset2Balance] = ammPoolHolds(
|
||||
*env_.current(),
|
||||
ammAccountID,
|
||||
issue1,
|
||||
issue2,
|
||||
asset1,
|
||||
asset2,
|
||||
FreezeHandling::fhIGNORE_FREEZE,
|
||||
AuthHandling::ahIGNORE_AUTH,
|
||||
env_.journal);
|
||||
auto const lptAMMBalance = account
|
||||
? ammLPHolds(*env_.current(), *amm, *account, env_.journal)
|
||||
@@ -211,7 +224,7 @@ AMM::expectBalances(
|
||||
std::optional<AccountID> const& account) const
|
||||
{
|
||||
auto const [asset1Balance, asset2Balance, lptAMMBalance] =
|
||||
balances(asset1.issue(), asset2.issue(), account);
|
||||
balances(asset1.asset(), asset2.asset(), account);
|
||||
return asset1 == asset1Balance && asset2 == asset2Balance &&
|
||||
lptAMMBalance == STAmount{lpt, lptIssue_};
|
||||
}
|
||||
@@ -229,7 +242,7 @@ AMM::getLPTokensBalance(std::optional<AccountID> const& account) const
|
||||
env_.journal)
|
||||
.iou();
|
||||
}
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())))
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())))
|
||||
return amm->getFieldAmount(sfLPTokenBalance).iou();
|
||||
return IOUAmount{0};
|
||||
}
|
||||
@@ -237,7 +250,7 @@ AMM::getLPTokensBalance(std::optional<AccountID> const& account) const
|
||||
bool
|
||||
AMM::expectLPTokens(AccountID const& account, IOUAmount const& expTokens) const
|
||||
{
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())))
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())))
|
||||
{
|
||||
auto const lptAMMBalance = ammLPHolds(*env_.current(), *amm, account, env_.journal);
|
||||
return lptAMMBalance == STAmount{expTokens, lptIssue_};
|
||||
@@ -283,7 +296,7 @@ AMM::expectAuctionSlot(std::vector<AccountID> const& authAccounts) const
|
||||
bool
|
||||
AMM::expectTradingFee(std::uint16_t fee) const
|
||||
{
|
||||
auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue()));
|
||||
auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset()));
|
||||
return amm && (*amm)[sfTradingFee] == fee;
|
||||
}
|
||||
|
||||
@@ -291,7 +304,7 @@ bool
|
||||
AMM::ammExists() const
|
||||
{
|
||||
return env_.current()->read(keylet::account(ammAccount_)) != nullptr &&
|
||||
env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())) != nullptr;
|
||||
env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())) != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -329,14 +342,14 @@ AMM::expectAmmInfo(
|
||||
if (!amountFromJsonNoThrow(lptBalance, jv[jss::lp_token]))
|
||||
return false;
|
||||
// ammRpcInfo returns unordered assets
|
||||
if (asset1Info.issue() != asset1.issue())
|
||||
if (asset1Info.asset() != asset1.asset())
|
||||
std::swap(asset1Info, asset2Info);
|
||||
return asset1 == asset1Info && asset2 == asset2Info &&
|
||||
lptBalance == STAmount{balance, lptIssue_};
|
||||
}
|
||||
|
||||
void
|
||||
AMM::setTokens(Json::Value& jv, std::optional<std::pair<Issue, Issue>> const& assets)
|
||||
AMM::setTokens(Json::Value& jv, std::optional<std::pair<Asset, Asset>> const& assets)
|
||||
{
|
||||
if (assets)
|
||||
{
|
||||
@@ -345,28 +358,65 @@ AMM::setTokens(Json::Value& jv, std::optional<std::pair<Issue, Issue>> const& as
|
||||
}
|
||||
else
|
||||
{
|
||||
jv[jss::Asset] = STIssue(sfAsset, asset1_.issue()).getJson(JsonOptions::none);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, asset2_.issue()).getJson(JsonOptions::none);
|
||||
jv[jss::Asset] = STIssue(sfAsset, asset1_.asset()).getJson(JsonOptions::none);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, asset2_.asset()).getJson(JsonOptions::none);
|
||||
}
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
AMM::deposit(
|
||||
std::optional<Account> const& account,
|
||||
Json::Value& jv,
|
||||
std::optional<std::pair<Issue, Issue>> const& assets,
|
||||
std::optional<jtx::seq> const& seq,
|
||||
std::optional<ter> const& ter)
|
||||
Json::Value
|
||||
AMM::depositJv(DepositArg const& arg)
|
||||
{
|
||||
auto const& acct = account ? *account : creatorAccount_;
|
||||
auto const lpTokens = getLPTokensBalance(acct);
|
||||
jv[jss::Account] = acct.human();
|
||||
setTokens(jv, assets);
|
||||
Json::Value jv;
|
||||
if (!arg.account || !arg.assets)
|
||||
Throw<std::runtime_error>("AMM::depositJv: account or assets not set");
|
||||
|
||||
jv[jss::Account] = arg.account->human();
|
||||
jv[jss::Asset] = STIssue(sfAsset, arg.assets->first).getJson(JsonOptions::none);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, arg.assets->second).getJson(JsonOptions::none);
|
||||
if (arg.tokens)
|
||||
arg.tokens->tokens().setJson(jv[jss::LPTokenOut]);
|
||||
if (arg.asset1In)
|
||||
arg.asset1In->setJson(jv[jss::Amount]);
|
||||
if (arg.asset2In)
|
||||
arg.asset2In->setJson(jv[jss::Amount2]);
|
||||
if (arg.maxEP)
|
||||
arg.maxEP->setJson(jv[jss::EPrice]);
|
||||
if (arg.tfee)
|
||||
jv[jss::TradingFee] = *arg.tfee;
|
||||
std::uint32_t flags = 0;
|
||||
if (arg.flags)
|
||||
flags = *arg.flags;
|
||||
// If including asset1In and asset2In or tokens as
|
||||
// deposit min amounts then must set the flags
|
||||
// explicitly instead of relying on this logic.
|
||||
if ((flags & tfDepositSubTx) == 0u)
|
||||
{
|
||||
if (arg.tokens && !arg.asset1In)
|
||||
{
|
||||
flags |= tfLPToken;
|
||||
}
|
||||
else if (arg.tokens && arg.asset1In)
|
||||
{
|
||||
flags |= tfOneAssetLPToken;
|
||||
}
|
||||
else if (arg.asset1In && arg.asset2In)
|
||||
{
|
||||
flags |= tfTwoAsset;
|
||||
}
|
||||
else if (arg.maxEP && arg.asset1In)
|
||||
{
|
||||
flags |= tfLimitLPToken;
|
||||
}
|
||||
else if (arg.asset1In)
|
||||
{
|
||||
flags |= tfSingleAsset;
|
||||
}
|
||||
}
|
||||
jv[jss::Flags] = flags;
|
||||
|
||||
jv[jss::TransactionType] = jss::AMMDeposit;
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, seq, ter);
|
||||
return getLPTokensBalance(acct) - lpTokens;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
@@ -399,7 +449,8 @@ AMM::deposit(
|
||||
std::optional<std::uint32_t> const& flags,
|
||||
std::optional<ter> const& ter)
|
||||
{
|
||||
assert(!(asset2In && maxEP));
|
||||
if (asset2In && maxEP)
|
||||
Throw<std::runtime_error>("Invalid options: asset2In and maxEP");
|
||||
return deposit(
|
||||
account,
|
||||
std::nullopt,
|
||||
@@ -421,53 +472,26 @@ AMM::deposit(
|
||||
std::optional<STAmount> const& asset2In,
|
||||
std::optional<STAmount> const& maxEP,
|
||||
std::optional<std::uint32_t> const& flags,
|
||||
std::optional<std::pair<Issue, Issue>> const& assets,
|
||||
std::optional<std::pair<Asset, Asset>> const& assets,
|
||||
std::optional<jtx::seq> const& seq,
|
||||
std::optional<std::uint16_t> const& tfee,
|
||||
std::optional<ter> const& ter)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (tokens)
|
||||
tokens->tokens(lptIssue_).setJson(jv[jss::LPTokenOut]);
|
||||
if (asset1In)
|
||||
asset1In->setJson(jv[jss::Amount]);
|
||||
if (asset2In)
|
||||
asset2In->setJson(jv[jss::Amount2]);
|
||||
if (maxEP)
|
||||
maxEP->setJson(jv[jss::EPrice]);
|
||||
if (tfee)
|
||||
jv[jss::TradingFee] = *tfee;
|
||||
std::uint32_t jvFlags = 0;
|
||||
if (flags)
|
||||
jvFlags = *flags;
|
||||
// If including asset1In and asset2In or tokens as
|
||||
// deposit min amounts then must set the flags
|
||||
// explicitly instead of relying on this logic.
|
||||
if ((jvFlags & tfDepositSubTx) == 0u)
|
||||
{
|
||||
if (tokens && !asset1In)
|
||||
{
|
||||
jvFlags |= tfLPToken;
|
||||
}
|
||||
else if (tokens && asset1In)
|
||||
{
|
||||
jvFlags |= tfOneAssetLPToken;
|
||||
}
|
||||
else if (asset1In && asset2In)
|
||||
{
|
||||
jvFlags |= tfTwoAsset;
|
||||
}
|
||||
else if (maxEP && asset1In)
|
||||
{
|
||||
jvFlags |= tfLimitLPToken;
|
||||
}
|
||||
else if (asset1In)
|
||||
{
|
||||
jvFlags |= tfSingleAsset;
|
||||
}
|
||||
}
|
||||
jv[jss::Flags] = jvFlags;
|
||||
return deposit(account, jv, assets, seq, ter);
|
||||
auto const acct = account ? account : creatorAccount_;
|
||||
auto const lpTokens = getLPTokensBalance(acct);
|
||||
Json::Value jv = depositJv(
|
||||
{.account = acct,
|
||||
.tokens = tokens ? tokens->tokens(lptIssue_) : tokens,
|
||||
.asset1In = asset1In,
|
||||
.asset2In = asset2In,
|
||||
.maxEP = maxEP,
|
||||
.flags = flags,
|
||||
.assets = assets ? assets : std::make_pair(asset1_.asset(), asset2_.asset()),
|
||||
.tfee = tfee});
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, seq, ter);
|
||||
return getLPTokensBalance(acct) - lpTokens;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
@@ -486,23 +510,54 @@ AMM::deposit(DepositArg const& arg)
|
||||
arg.err);
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
AMM::withdraw(
|
||||
std::optional<Account> const& account,
|
||||
Json::Value& jv,
|
||||
std::optional<jtx::seq> const& seq,
|
||||
std::optional<std::pair<Issue, Issue>> const& assets,
|
||||
std::optional<ter> const& ter)
|
||||
Json::Value
|
||||
AMM::withdrawJv(WithdrawArg const& arg)
|
||||
{
|
||||
auto const& acct = account ? *account : creatorAccount_;
|
||||
auto const lpTokens = getLPTokensBalance(acct);
|
||||
jv[jss::Account] = acct.human();
|
||||
setTokens(jv, assets);
|
||||
Json::Value jv;
|
||||
if (!arg.account || !arg.assets)
|
||||
Throw<std::runtime_error>("AMM::withdrawJv: account or assets not set");
|
||||
jv[jss::Account] = arg.account->human();
|
||||
jv[jss::Asset] = STIssue(sfAsset, arg.assets->first).getJson(JsonOptions::none);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, arg.assets->second).getJson(JsonOptions::none);
|
||||
if (arg.tokens)
|
||||
arg.tokens->tokens().setJson(jv[jss::LPTokenIn]);
|
||||
if (arg.asset1Out)
|
||||
arg.asset1Out->setJson(jv[jss::Amount]);
|
||||
if (arg.asset2Out)
|
||||
arg.asset2Out->setJson(jv[jss::Amount2]);
|
||||
if (arg.maxEP)
|
||||
arg.maxEP->tokens().setJson(jv[jss::EPrice]);
|
||||
std::uint32_t flags = 0;
|
||||
if (arg.flags)
|
||||
flags = *arg.flags;
|
||||
if ((flags & tfWithdrawSubTx) == 0u)
|
||||
{
|
||||
if (arg.tokens && !arg.asset1Out)
|
||||
{
|
||||
flags |= tfLPToken;
|
||||
}
|
||||
else if (arg.asset1Out && arg.asset2Out)
|
||||
{
|
||||
flags |= tfTwoAsset;
|
||||
}
|
||||
else if (arg.tokens && arg.asset1Out)
|
||||
{
|
||||
flags |= tfOneAssetLPToken;
|
||||
}
|
||||
else if (arg.asset1Out && arg.maxEP)
|
||||
{
|
||||
flags |= tfLimitLPToken;
|
||||
}
|
||||
else if (arg.asset1Out)
|
||||
{
|
||||
flags |= tfSingleAsset;
|
||||
}
|
||||
}
|
||||
jv[jss::Flags] = flags;
|
||||
|
||||
jv[jss::TransactionType] = jss::AMMWithdraw;
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, seq, ter);
|
||||
return lpTokens - getLPTokensBalance(acct);
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
@@ -530,10 +585,11 @@ AMM::withdraw(
|
||||
std::optional<Account> const& account,
|
||||
STAmount const& asset1Out,
|
||||
std::optional<STAmount> const& asset2Out,
|
||||
std::optional<IOUAmount> const& maxEP,
|
||||
std::optional<LPToken> const& maxEP,
|
||||
std::optional<ter> const& ter)
|
||||
{
|
||||
assert(!(asset2Out && maxEP));
|
||||
if (asset2Out && maxEP)
|
||||
Throw<std::runtime_error>("Invalid options: asset2Out and maxEP");
|
||||
return withdraw(
|
||||
account,
|
||||
std::nullopt,
|
||||
@@ -552,52 +608,27 @@ AMM::withdraw(
|
||||
std::optional<LPToken> const& tokens,
|
||||
std::optional<STAmount> const& asset1Out,
|
||||
std::optional<STAmount> const& asset2Out,
|
||||
std::optional<IOUAmount> const& maxEP,
|
||||
std::optional<LPToken> const& maxEP,
|
||||
std::optional<std::uint32_t> const& flags,
|
||||
std::optional<std::pair<Issue, Issue>> const& assets,
|
||||
std::optional<std::pair<Asset, Asset>> const& assets,
|
||||
std::optional<jtx::seq> const& seq,
|
||||
std::optional<ter> const& ter)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (tokens)
|
||||
tokens->tokens(lptIssue_).setJson(jv[jss::LPTokenIn]);
|
||||
if (asset1Out)
|
||||
asset1Out->setJson(jv[jss::Amount]);
|
||||
if (asset2Out)
|
||||
asset2Out->setJson(jv[jss::Amount2]);
|
||||
if (maxEP)
|
||||
{
|
||||
STAmount const saMaxEP{*maxEP, lptIssue_};
|
||||
saMaxEP.setJson(jv[jss::EPrice]);
|
||||
}
|
||||
std::uint32_t jvFlags = 0;
|
||||
if (flags)
|
||||
jvFlags = *flags;
|
||||
if ((jvFlags & tfWithdrawSubTx) == 0u)
|
||||
{
|
||||
if (tokens && !asset1Out)
|
||||
{
|
||||
jvFlags |= tfLPToken;
|
||||
}
|
||||
else if (asset1Out && asset2Out)
|
||||
{
|
||||
jvFlags |= tfTwoAsset;
|
||||
}
|
||||
else if (tokens && asset1Out)
|
||||
{
|
||||
jvFlags |= tfOneAssetLPToken;
|
||||
}
|
||||
else if (asset1Out && maxEP)
|
||||
{
|
||||
jvFlags |= tfLimitLPToken;
|
||||
}
|
||||
else if (asset1Out)
|
||||
{
|
||||
jvFlags |= tfSingleAsset;
|
||||
}
|
||||
}
|
||||
jv[jss::Flags] = jvFlags;
|
||||
return withdraw(account, jv, seq, assets, ter);
|
||||
auto const acct = account ? account : creatorAccount_;
|
||||
auto const lpTokens = getLPTokensBalance(acct);
|
||||
Json::Value jv = withdrawJv({
|
||||
.account = acct,
|
||||
.tokens = tokens ? tokens->tokens(lptIssue_) : tokens,
|
||||
.asset1Out = asset1Out,
|
||||
.asset2Out = asset2Out,
|
||||
.maxEP = maxEP ? maxEP->tokens(lptIssue_) : maxEP,
|
||||
.flags = flags,
|
||||
.assets = assets ? assets : std::make_pair(asset1_.asset(), asset2_.asset()),
|
||||
});
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, seq, ter);
|
||||
return lpTokens - getLPTokensBalance(acct);
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
@@ -615,22 +646,39 @@ AMM::withdraw(WithdrawArg const& arg)
|
||||
arg.err);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
AMM::voteJv(VoteArg const& arg)
|
||||
{
|
||||
Json::Value jv;
|
||||
if (!arg.account || !arg.assets)
|
||||
Throw<std::runtime_error>("AMM::withdrawJv: account or assets not set");
|
||||
jv[jss::Account] = arg.account->human();
|
||||
jv[jss::Asset] = STIssue(sfAsset, arg.assets->first).getJson(JsonOptions::none);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, arg.assets->second).getJson(JsonOptions::none);
|
||||
jv[jss::TradingFee] = arg.tfee;
|
||||
if (arg.flags)
|
||||
jv[jss::Flags] = *arg.flags;
|
||||
|
||||
jv[jss::TransactionType] = jss::AMMVote;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
AMM::vote(
|
||||
std::optional<Account> const& account,
|
||||
std::uint32_t feeVal,
|
||||
std::optional<std::uint32_t> const& flags,
|
||||
std::optional<jtx::seq> const& seq,
|
||||
std::optional<std::pair<Issue, Issue>> const& assets,
|
||||
std::optional<std::pair<Asset, Asset>> const& assets,
|
||||
std::optional<ter> const& ter)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = account ? account->human() : creatorAccount_.human();
|
||||
setTokens(jv, assets);
|
||||
jv[jss::TradingFee] = feeVal;
|
||||
jv[jss::TransactionType] = jss::AMMVote;
|
||||
if (flags)
|
||||
jv[jss::Flags] = *flags;
|
||||
Json::Value jv = voteJv({
|
||||
.account = account ? account : creatorAccount_,
|
||||
.tfee = feeVal,
|
||||
.flags = flags,
|
||||
.assets = assets ? assets : std::make_pair(asset1_.asset(), asset2_.asset()),
|
||||
});
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, seq, ter);
|
||||
@@ -645,11 +693,11 @@ AMM::vote(VoteArg const& arg)
|
||||
Json::Value
|
||||
AMM::bid(BidArg const& arg)
|
||||
{
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())))
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())))
|
||||
{
|
||||
assert(
|
||||
!env_.current()->rules().enabled(fixInnerObjTemplate) ||
|
||||
amm->isFieldPresent(sfAuctionSlot));
|
||||
if (env_.current()->rules().enabled(fixInnerObjTemplate) &&
|
||||
!amm->isFieldPresent(sfAuctionSlot))
|
||||
Throw<std::runtime_error>("AMM::Bid");
|
||||
if (amm->isFieldPresent(sfAuctionSlot))
|
||||
{
|
||||
auto const& auctionSlot =
|
||||
@@ -708,6 +756,22 @@ AMM::bid(BidArg const& arg)
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
AMM::clawback(ClawbackArg const& arg)
|
||||
{
|
||||
auto const& [asset, asset2] = [&]() {
|
||||
if (arg.assets)
|
||||
return *arg.assets;
|
||||
return std::make_pair(asset1_.asset(), asset2_.asset());
|
||||
}();
|
||||
auto jv = amm::ammClawback(arg.issuer, arg.holder, asset, asset2, arg.amount);
|
||||
if (arg.flags)
|
||||
jv[jss::Flags] = *arg.flags;
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, std::nullopt, arg.err);
|
||||
}
|
||||
|
||||
void
|
||||
AMM::submit(
|
||||
Json::Value const& jv,
|
||||
@@ -758,11 +822,11 @@ AMM::submit(
|
||||
bool
|
||||
AMM::expectAuctionSlot(auto&& cb) const
|
||||
{
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.issue(), asset2_.issue())))
|
||||
if (auto const amm = env_.current()->read(keylet::amm(asset1_.asset(), asset2_.asset())))
|
||||
{
|
||||
assert(
|
||||
!env_.current()->rules().enabled(fixInnerObjTemplate) ||
|
||||
amm->isFieldPresent(sfAuctionSlot));
|
||||
if (env_.current()->rules().enabled(fixInnerObjTemplate) &&
|
||||
!amm->isFieldPresent(sfAuctionSlot))
|
||||
Throw<std::runtime_error>("AMM::expectAuctionSlot");
|
||||
if (amm->isFieldPresent(sfAuctionSlot))
|
||||
{
|
||||
auto const& auctionSlot =
|
||||
@@ -785,48 +849,36 @@ AMM::expectAuctionSlot(auto&& cb) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
AMM::ammDelete(AccountID const& deleter, std::optional<ter> const& ter)
|
||||
Json::Value
|
||||
AMM::deleteJv(AccountID const& account, Asset const& asset1, Asset const& asset2)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = to_string(deleter);
|
||||
setTokens(jv);
|
||||
jv[jss::Account] = to_string(account);
|
||||
jv[jss::Asset] = STIssue(sfAsset, asset1).getJson(JsonOptions::none);
|
||||
jv[jss::Asset2] = STIssue(sfAsset, asset2).getJson(JsonOptions::none);
|
||||
|
||||
jv[jss::TransactionType] = jss::AMMDelete;
|
||||
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
AMM::ammDelete(AccountID const& account, std::optional<ter> const& ter)
|
||||
{
|
||||
Json::Value jv = deleteJv(account, asset1_.asset(), asset2_.asset());
|
||||
if (fee_ != 0)
|
||||
jv[jss::Fee] = std::to_string(fee_);
|
||||
submit(jv, std::nullopt, ter);
|
||||
}
|
||||
|
||||
namespace amm {
|
||||
Json::Value
|
||||
trust(AccountID const& account, STAmount const& amount, std::uint32_t flags)
|
||||
{
|
||||
if (isXRP(amount))
|
||||
Throw<std::runtime_error>("trust() requires IOU");
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = to_string(account);
|
||||
jv[jss::LimitAmount] = amount.getJson(JsonOptions::none);
|
||||
jv[jss::TransactionType] = jss::TrustSet;
|
||||
jv[jss::Flags] = flags;
|
||||
return jv;
|
||||
}
|
||||
Json::Value
|
||||
pay(Account const& account, AccountID const& to, STAmount const& amount)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[jss::Amount] = amount.getJson(JsonOptions::none);
|
||||
jv[jss::Destination] = to_string(to);
|
||||
jv[jss::TransactionType] = jss::Payment;
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
ammClawback(
|
||||
Account const& issuer,
|
||||
Account const& holder,
|
||||
Issue const& asset,
|
||||
Issue const& asset2,
|
||||
Asset const& asset,
|
||||
Asset const& asset2,
|
||||
std::optional<STAmount> const& amount)
|
||||
{
|
||||
Json::Value jv;
|
||||
|
||||
Reference in New Issue
Block a user