mirror of
https://github.com/Xahau/xahaud.git
synced 2026-04-29 15:37:46 +00:00
Add TSH processing for AMM, AMMClawback, Clawback, Oracle (#532)
* Add TSH processing for `AMM`, `AMMClawback`, `Oracle`, `Clawback` * Add empty TSH processing for other transaction types * Add AMMTsh tests
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <test/app/Import_json.h>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/AMM.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <xrpld/app/misc/HashRouter.h>
|
||||
#include <xrpld/app/misc/TxQ.h>
|
||||
@@ -841,6 +842,391 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// AMM
|
||||
// | otxn | tsh | Bid | Create | Delete | Clawback | Deposit | Vote | Withdraw |
|
||||
// | A | I | - | W | W | W | W | - | W |
|
||||
// | A | H | - | - | - | W | - | - | - |
|
||||
// clang-format on
|
||||
void
|
||||
testAMMBidTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm bid tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh issuer
|
||||
// w/s: none
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(30'000), issuer, account);
|
||||
env.close();
|
||||
env.trust(USD(30'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(10'000)));
|
||||
env.close();
|
||||
|
||||
// create AMM
|
||||
AMM ammAlice(env, account, XRP(10'000), USD(10'000));
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, issuer);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, issuer, testStrong);
|
||||
|
||||
// bid
|
||||
ammAlice.bid({
|
||||
.account = account,
|
||||
.bidMin = 100,
|
||||
});
|
||||
|
||||
// verify tsh hook triggered
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
// AMMCreate
|
||||
void
|
||||
testAMMCreateTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm create tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh issuer
|
||||
// w/s: weak
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(30'000), issuer, account);
|
||||
env.close();
|
||||
env.trust(USD(30'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(10'000)));
|
||||
env.close();
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, issuer);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, issuer, testStrong);
|
||||
|
||||
// create AMM
|
||||
AMM ammAlice(env, account, XRP(10'000), USD(10'000));
|
||||
|
||||
// verify tsh hook triggered
|
||||
if (features[featureIOUIssuerWeakTSH])
|
||||
{
|
||||
auto const expected = testStrong ? tshNONE : tshWEAK;
|
||||
testTSHStrongWeak(env, expected, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AMMDelete
|
||||
void
|
||||
testAMMDeleteTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm delete tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh issuer, holder
|
||||
// w/s: none
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env(
|
||||
*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->FEES.reference_fee = XRPAmount(1);
|
||||
return cfg;
|
||||
}),
|
||||
features);
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(20'000), issuer, account, bob);
|
||||
env.close();
|
||||
env.trust(USD(10'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(10'000)));
|
||||
env.close();
|
||||
|
||||
AMM amm(env, account, XRP(10'000), USD(10'000));
|
||||
for (auto i = 0; i < maxDeletableAMMTrustLines + 10; ++i)
|
||||
{
|
||||
Account const a{std::to_string(i)};
|
||||
env.fund(XRP(1'000), a);
|
||||
env(trust(a, STAmount{amm.lptIssue(), 10'000}));
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
env(fset(a, asfTshCollect));
|
||||
// set tsh hook
|
||||
setTSHHook(env, a, testStrong);
|
||||
}
|
||||
amm.withdrawAll(account);
|
||||
BEAST_EXPECT(amm.ammExists());
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, issuer);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, issuer, testStrong);
|
||||
|
||||
// delete
|
||||
amm.ammDelete(bob);
|
||||
|
||||
// verify tsh hook triggered
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
// AMMClawback
|
||||
void
|
||||
testAMMClawbackTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm clawback tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh holder
|
||||
// w/s: weak
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(30'000), issuer, account);
|
||||
env.close();
|
||||
env(fset(issuer, asfAllowTrustLineClawback));
|
||||
env.close();
|
||||
env.trust(USD(30'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(30'000)));
|
||||
env.close();
|
||||
|
||||
// create AMM
|
||||
AMM ammAlice(env, account, XRP(10'000), USD(10'000));
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, account);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, account, testStrong);
|
||||
|
||||
// clawback
|
||||
env(amm::ammClawback(issuer, account, USD, XRP, USD(1000)));
|
||||
env.close();
|
||||
|
||||
// verify tsh hook triggered
|
||||
if (features[featureIOUIssuerWeakTSH])
|
||||
{
|
||||
auto const expected = testStrong ? tshNONE : tshWEAK;
|
||||
testTSHStrongWeak(env, expected, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AMMDeposit
|
||||
void
|
||||
testAMMDepositTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm deposit tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh issuer
|
||||
// w/s: weak
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(30'000), issuer, account);
|
||||
env.close();
|
||||
env.trust(USD(30'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(30'000)));
|
||||
env.close();
|
||||
|
||||
// create AMM
|
||||
AMM ammAlice(env, account, XRP(10'000), USD(10'000));
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, issuer);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, issuer, testStrong);
|
||||
|
||||
// deposit
|
||||
ammAlice.deposit(account, 10);
|
||||
|
||||
// verify tsh hook triggered
|
||||
if (features[featureIOUIssuerWeakTSH])
|
||||
{
|
||||
auto const expected = testStrong ? tshNONE : tshWEAK;
|
||||
testTSHStrongWeak(env, expected, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AMMVote
|
||||
void
|
||||
testAMMVoteTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm vote tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh issuer
|
||||
// w/s: none
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(30'000), issuer, account);
|
||||
env.close();
|
||||
env.trust(USD(30'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(30'000)));
|
||||
env.close();
|
||||
|
||||
// create AMM
|
||||
AMM ammAlice(env, account, XRP(10'000), USD(10'000));
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, issuer);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, issuer, testStrong);
|
||||
|
||||
// vote
|
||||
ammAlice.vote(account, 100);
|
||||
|
||||
// verify tsh hook triggered
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
// AMMWithdraw
|
||||
void
|
||||
testAMMWithdrawTSH(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("amm withdraw tsh");
|
||||
|
||||
// otxn: account
|
||||
// tsh issuer
|
||||
// w/s: weak
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("gw");
|
||||
auto const account = Account("alice");
|
||||
auto const USD = issuer["USD"];
|
||||
|
||||
env.fund(XRP(30'000), issuer, account);
|
||||
env.close();
|
||||
env.trust(USD(30'000), account);
|
||||
env.close();
|
||||
env(pay(issuer, account, USD(30'000)));
|
||||
env.close();
|
||||
|
||||
// create AMM
|
||||
AMM ammAlice(env, account, XRP(10'000), USD(10'000));
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, issuer);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, issuer, testStrong);
|
||||
|
||||
// withdraw
|
||||
ammAlice.withdraw(account, 100);
|
||||
|
||||
// verify tsh hook triggered
|
||||
if (features[featureIOUIssuerWeakTSH])
|
||||
{
|
||||
auto const expected = testStrong ? tshNONE : tshWEAK;
|
||||
testTSHStrongWeak(env, expected, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
testTSHStrongWeak(env, tshNONE, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check
|
||||
// | otxn | tsh | cancel | create | cash |
|
||||
// | A | A | S | S | N/A |
|
||||
@@ -1384,6 +1770,46 @@ private:
|
||||
auto const expected = testStrong ? tshNONE : tshWEAK;
|
||||
testTSHStrongWeak(env, expected, __LINE__);
|
||||
}
|
||||
|
||||
// otxn: MPT issuer
|
||||
// tsh holder
|
||||
// w/s: weak
|
||||
for (bool const testStrong : {true, false})
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337, "10", "1000000", "200000"),
|
||||
features};
|
||||
|
||||
auto const issuer = Account("alice");
|
||||
auto const holder = Account("bob");
|
||||
|
||||
MPTTester mptIssuer(env, issuer, {.holders = {holder}});
|
||||
|
||||
// issuer creates issuance
|
||||
mptIssuer.create(
|
||||
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback});
|
||||
|
||||
// holder creates a MPToken
|
||||
mptIssuer.authorize({.account = holder});
|
||||
|
||||
// issuer pays holder 100 tokens
|
||||
mptIssuer.pay(issuer, holder, 100);
|
||||
|
||||
// set tsh collect
|
||||
if (!testStrong)
|
||||
addWeakTSH(env, holder);
|
||||
|
||||
// set tsh hook
|
||||
setTSHHook(env, holder, testStrong);
|
||||
|
||||
// clawback
|
||||
mptIssuer.claw(issuer, holder, 1);
|
||||
|
||||
// verify tsh hook triggered
|
||||
auto const expected = testStrong ? tshNONE : tshWEAK;
|
||||
testTSHStrongWeak(env, expected, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
// DepositPreauth
|
||||
@@ -6345,6 +6771,13 @@ private:
|
||||
{
|
||||
testAccountSetTSH(features);
|
||||
testAccountDeleteTSH(features);
|
||||
testAMMBidTSH(features);
|
||||
testAMMCreateTSH(features);
|
||||
testAMMDeleteTSH(features);
|
||||
testAMMClawbackTSH(features);
|
||||
testAMMDepositTSH(features);
|
||||
testAMMVoteTSH(features);
|
||||
testAMMWithdrawTSH(features);
|
||||
testCheckCancelTSH(features);
|
||||
testCheckCashTSH(features);
|
||||
testCheckCreateTSH(features);
|
||||
@@ -6391,7 +6824,8 @@ public:
|
||||
run(std::uint32_t instance, bool last = false)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
static FeatureBitset const all{supported_amendments()};
|
||||
static FeatureBitset const all{
|
||||
supported_amendments() | featureMPTokensV1};
|
||||
|
||||
static std::array<FeatureBitset, 4> const feats{
|
||||
all,
|
||||
|
||||
@@ -497,12 +497,90 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
|
||||
case ttCLAWBACK: {
|
||||
auto const amount = tx.getFieldAmount(sfAmount);
|
||||
ADD_TSH(amount.getIssuer(), tshWEAK);
|
||||
|
||||
if (amount.holds<MPTIssue>())
|
||||
{
|
||||
if (!tx.isFieldPresent(sfHolder))
|
||||
return {};
|
||||
auto const holder = tx.getAccountID(sfHolder);
|
||||
ADD_TSH(holder, tshWEAK);
|
||||
}
|
||||
else
|
||||
ADD_TSH(amount.getIssuer(), tshWEAK);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return {};
|
||||
case ttAMM_CREATE:
|
||||
case ttAMM_DEPOSIT:
|
||||
case ttAMM_WITHDRAW:
|
||||
case ttAMM_VOTE:
|
||||
case ttAMM_BID:
|
||||
case ttAMM_DELETE:
|
||||
case ttAMM_CLAWBACK: {
|
||||
// The issuer or holder of tokens related to AMM is weakTSH with
|
||||
// IOUIssuerWeakTSH Amendment.
|
||||
break;
|
||||
}
|
||||
case ttORACLE_SET:
|
||||
case ttORACLE_DELETE: {
|
||||
break;
|
||||
}
|
||||
case ttXCHAIN_CREATE_CLAIM_ID:
|
||||
case ttXCHAIN_COMMIT:
|
||||
case ttXCHAIN_CLAIM:
|
||||
case ttXCHAIN_ACCOUNT_CREATE_COMMIT:
|
||||
case ttXCHAIN_ADD_CLAIM_ATTESTATION:
|
||||
case ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION:
|
||||
case ttXCHAIN_MODIFY_BRIDGE:
|
||||
case ttXCHAIN_CREATE_BRIDGE: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttDID_SET:
|
||||
case ttDID_DELETE: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttLEDGER_STATE_FIX: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttMPTOKEN_ISSUANCE_CREATE:
|
||||
case ttMPTOKEN_ISSUANCE_DESTROY:
|
||||
case ttMPTOKEN_ISSUANCE_SET:
|
||||
case ttMPTOKEN_AUTHORIZE: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttCREDENTIAL_CREATE:
|
||||
case ttCREDENTIAL_ACCEPT:
|
||||
case ttCREDENTIAL_DELETE: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttNFTOKEN_MODIFY: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttPERMISSIONED_DOMAIN_SET:
|
||||
case ttPERMISSIONED_DOMAIN_DELETE: {
|
||||
// TODO: Implement if needed
|
||||
break;
|
||||
}
|
||||
case ttREMARKS_SET: {
|
||||
break;
|
||||
}
|
||||
// pseudo transactions
|
||||
case ttAMENDMENT:
|
||||
case ttFEE:
|
||||
case ttUNL_MODIFY:
|
||||
case ttEMIT_FAILURE:
|
||||
case ttUNL_REPORT: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE("Unknown transaction type");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<AccountID, bool>> ret{tshEntries.size()};
|
||||
|
||||
Reference in New Issue
Block a user