Skip to content

Commit

Permalink
use fhIGNORE_FREEZE for AMMClawback
Browse files Browse the repository at this point in the history
  • Loading branch information
yinyiqian1 committed Oct 1, 2024
1 parent 4bdb019 commit 99c0d02
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 34 deletions.
289 changes: 288 additions & 1 deletion src/test/app/AMMClawback_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,293 @@ class AMMClawback_test : public jtx::AMMTest
ter(tecINTERNAL));
}

public:
void
testAssetFrozen(FeatureBitset features)
{
testcase("test assets frozen");
using namespace jtx;

// test Individually frozen trustline of USD currency.
{
Env env(*this, features);
Account gw{"gateway"};
Account gw2{"gateway2"};
Account alice{"alice"};
env.fund(XRP(1000000), gw, gw2, alice);
env.close();

// gw sets asfAllowTrustLineClawback.
env(fset(gw, asfAllowTrustLineClawback));
env.close();
env.require(flags(gw, asfAllowTrustLineClawback));

// gw issues 3000 USD to Alice.
auto const USD = gw["USD"];
env.trust(USD(100000), alice);
env(pay(gw, alice, USD(3000)));
env.close();
env.require(balance(alice, gw["USD"](3000)));

// gw2 issues 3000 EUR to Alice.
auto const EUR = gw2["EUR"];
env.trust(EUR(100000), alice);
env(pay(gw2, alice, EUR(3000)));
env.close();
env.require(balance(alice, gw2["EUR"](3000)));

// Alice creates AMM pool of EUR/USD.
AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS));
env.close();

BEAST_EXPECT(amm.expectBalances(
USD(2000), EUR(1000), IOUAmount{1414213562373095, -12}));

// freeze trustline
env(trust(gw, alice["USD"](0), tfSetFreeze));
env.close();

// gw clawback 1000 USD from the AMM pool.
env(amm::ammClawback(gw, alice, USD, EUR, USD(1000), std::nullopt),
ter(tesSUCCESS));
env.close();

env.require(balance(alice, gw["USD"](1000)));
env.require(balance(alice, gw2["EUR"](2500)));
BEAST_EXPECT(amm.expectBalances(
USD(1000), EUR(500), IOUAmount{7071067811865475, -13}));

// Alice has half of its initial lptokens Left.
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13}));

// gw clawback another 1000 USD from the AMM pool. The AMM pool will
// be empty and get deleted.
env(amm::ammClawback(gw, alice, USD, EUR, USD(1000), std::nullopt),
ter(tesSUCCESS));
env.close();

// Alice should still has 1000 USD because gw clawed back from the
// AMM pool.
env.require(balance(alice, gw["USD"](1000)));
env.require(balance(alice, gw2["EUR"](3000)));

// amm is automatically deleted.
BEAST_EXPECT(!amm.ammExists());
}

// test Individually frozen trustline of both USD and EUR currency.
{
Env env(*this, features);
Account gw{"gateway"};
Account gw2{"gateway2"};
Account alice{"alice"};
env.fund(XRP(1000000), gw, gw2, alice);
env.close();

// gw sets asfAllowTrustLineClawback.
env(fset(gw, asfAllowTrustLineClawback));
env.close();
env.require(flags(gw, asfAllowTrustLineClawback));

// gw issues 3000 USD to Alice.
auto const USD = gw["USD"];
env.trust(USD(100000), alice);
env(pay(gw, alice, USD(3000)));
env.close();
env.require(balance(alice, gw["USD"](3000)));

// gw2 issues 3000 EUR to Alice.
auto const EUR = gw2["EUR"];
env.trust(EUR(100000), alice);
env(pay(gw2, alice, EUR(3000)));
env.close();
env.require(balance(alice, gw2["EUR"](3000)));

// Alice creates AMM pool of EUR/USD.
AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS));
env.close();

BEAST_EXPECT(amm.expectBalances(
USD(2000), EUR(1000), IOUAmount{1414213562373095, -12}));

// freeze trustlines
env(trust(gw, alice["USD"](0), tfSetFreeze));
env(trust(gw2, alice["EUR"](0), tfSetFreeze));
env.close();

// gw clawback 1000 USD from the AMM pool.
env(amm::ammClawback(gw, alice, USD, EUR, USD(1000), std::nullopt),
ter(tesSUCCESS));
env.close();

env.require(balance(alice, gw["USD"](1000)));
env.require(balance(alice, gw2["EUR"](2500)));
BEAST_EXPECT(amm.expectBalances(
USD(1000), EUR(500), IOUAmount{7071067811865475, -13}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13}));
}

// test global freeze gw USD
{
Env env(*this, features);
Account gw{"gateway"};
Account gw2{"gateway2"};
Account alice{"alice"};
env.fund(XRP(1000000), gw, gw2, alice);
env.close();

// gw sets asfAllowTrustLineClawback.
env(fset(gw, asfAllowTrustLineClawback));
env.close();
env.require(flags(gw, asfAllowTrustLineClawback));

// gw issues 3000 USD to Alice.
auto const USD = gw["USD"];
env.trust(USD(100000), alice);
env(pay(gw, alice, USD(3000)));
env.close();
env.require(balance(alice, gw["USD"](3000)));

// gw2 issues 3000 EUR to Alice.
auto const EUR = gw2["EUR"];
env.trust(EUR(100000), alice);
env(pay(gw2, alice, EUR(3000)));
env.close();
env.require(balance(alice, gw2["EUR"](3000)));

// Alice creates AMM pool of EUR/USD.
AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS));
env.close();

BEAST_EXPECT(amm.expectBalances(
USD(2000), EUR(1000), IOUAmount{1414213562373095, -12}));

// global freeze
env(fset(gw, asfGlobalFreeze));
env.close();

// gw clawback 1000 USD from the AMM pool.
env(amm::ammClawback(gw, alice, USD, EUR, USD(1000), std::nullopt),
ter(tesSUCCESS));
env.close();

env.require(balance(alice, gw["USD"](1000)));
env.require(balance(alice, gw2["EUR"](2500)));
BEAST_EXPECT(amm.expectBalances(
USD(1000), EUR(500), IOUAmount{7071067811865475, -13}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13}));
}

// Test both assets are issued by the same issuer. And issuer sets
// global freeze.
{
Env env(*this, features);
Account gw{"gateway"};
Account alice{"alice"};
Account bob{"bob"};
Account carol{"carol"};
env.fund(XRP(1000000), gw, alice, bob, carol);
env.close();

// gw sets asfAllowTrustLineClawback.
env(fset(gw, asfAllowTrustLineClawback));
env.close();
env.require(flags(gw, asfAllowTrustLineClawback));

auto const USD = gw["USD"];
env.trust(USD(100000), alice);
env(pay(gw, alice, USD(10000)));
env.trust(USD(100000), bob);
env(pay(gw, bob, USD(9000)));
env.trust(USD(100000), carol);
env(pay(gw, carol, USD(8000)));
env.close();

auto const EUR = gw["EUR"];
env.trust(EUR(100000), alice);
env(pay(gw, alice, EUR(10000)));
env.trust(EUR(100000), bob);
env(pay(gw, bob, EUR(9000)));
env.trust(EUR(100000), carol);
env(pay(gw, carol, EUR(8000)));
env.close();

AMM amm(env, alice, EUR(2000), USD(8000), ter(tesSUCCESS));
env.close();

BEAST_EXPECT(
amm.expectBalances(USD(8000), EUR(2000), IOUAmount(4000)));
amm.deposit(bob, USD(4000), EUR(1000));
BEAST_EXPECT(
amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000)));
amm.deposit(carol, USD(2000), EUR(500));
BEAST_EXPECT(
amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000)));

// global freeze
env(fset(gw, asfGlobalFreeze));
env.close();

// gw clawback 1000 USD from carol.
env(amm::ammClawback(gw, carol, USD, EUR, USD(1000), std::nullopt),
ter(tesSUCCESS));
env.close();
BEAST_EXPECT(
amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500)));

BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000)));
BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(2000)));
BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500)));
BEAST_EXPECT(env.balance(alice, USD) == USD(2000));
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
// 250 EUR goes back to carol.
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));

// gw clawback 1000 USD from bob with tfClawTwoAssets flag.
// then the corresponding EUR will also be clawed back
// by gw.
env(amm::ammClawback(gw, bob, USD, EUR, USD(1000), tfClawTwoAssets),
ter(tesSUCCESS));
env.close();
BEAST_EXPECT(
amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000)));

BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000)));
BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500)));
BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500)));
BEAST_EXPECT(env.balance(alice, USD) == USD(2000));
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
// 250 EUR did not go back to bob because tfClawTwoAssets is set.
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));

// gw clawback all USD from alice and set tfClawTwoAssets.
env(amm::ammClawback(
gw, alice, USD, EUR, std::nullopt, tfClawTwoAssets),
ter(tesSUCCESS));
env.close();
BEAST_EXPECT(
amm.expectBalances(USD(4000), EUR(1000), IOUAmount(2000)));

BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0)));
BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500)));
BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500)));
BEAST_EXPECT(env.balance(alice, USD) == USD(2000));
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
}
}

void
run() override
{
Expand All @@ -1442,6 +1728,7 @@ class AMMClawback_test : public jtx::AMMTest
testAMMClawbackSameCurrency(all);
testAMMClawbackIssuesEachOther(all);
testNotHoldingLptoken(all);
testAssetFrozen(all);
}
};
BEAST_DEFINE_TESTSUITE(AMMClawback, app, ripple);
Expand Down
4 changes: 2 additions & 2 deletions src/test/app/AMM_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6957,9 +6957,9 @@ struct AMM_test : public jtx::AMMTest
env.fund(XRP(1'000), gw);
fund(env, gw, {alice}, XRP(1'000), {USD(1'000)}, Fund::Acct);
env.close();
AMM* amm = new AMM(env, alice, XRP(100), USD(100), ter(tesSUCCESS));
AMM amm(env, alice, XRP(100), USD(100), ter(tesSUCCESS));
env(trust(gw, alice["USD"](0), tfSetFreeze));
cb(*amm);
cb(amm);
};

// Deposit two assets, one of which is frozen,
Expand Down
2 changes: 0 additions & 2 deletions src/xrpld/app/misc/detail/AMMUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpld/app/misc/AMMHelpers.h>
#include <xrpld/app/misc/AMMUtils.h>
#include <xrpld/ledger/Sandbox.h>
#include <xrpl/basics/Log.h>
#include <xrpl/protocol/AMMCore.h>
#include <xrpl/protocol/STAccount.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/TxFlags.h>

namespace ripple {

Expand Down
6 changes: 4 additions & 2 deletions src/xrpld/app/tx/detail/AMMClawback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ AMMClawback::applyGuts(Sandbox& sb)
*ammSle,
asset,
asset2,
FreezeHandling::fhZERO_IF_FROZEN,
FreezeHandling::fhIGNORE_FREEZE,
ctx_.journal);

if (!expected)
Expand Down Expand Up @@ -184,6 +184,7 @@ AMMClawback::applyGuts(Sandbox& sb)
holdLPtokens,
holdLPtokens,
0,
FreezeHandling::fhIGNORE_FREEZE,
WithdrawAll::Yes,
ctx_.journal);
}
Expand Down Expand Up @@ -222,7 +223,6 @@ AMMClawback::applyGuts(Sandbox& sb)
// same issuer.
auto const flags = ctx_.tx.getFlags();
if (flags & tfClawTwoAssets)

return rippleCredit(sb, holder, issuer, *amount2Withdraw, true, j_);

return tesSUCCESS;
Expand Down Expand Up @@ -260,6 +260,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
holdLPtokens,
holdLPtokens,
0,
FreezeHandling::fhIGNORE_FREEZE,
WithdrawAll::Yes,
ctx_.journal);

Expand All @@ -276,6 +277,7 @@ AMMClawback::equalWithdrawMatchingOneAmount(
lptAMMBalance,
toSTAmount(lptAMMBalance.issue(), lptAMMBalance * frac),
0,
FreezeHandling::fhIGNORE_FREEZE,
WithdrawAll::No,
ctx_.journal);
}
Expand Down
Loading

0 comments on commit 99c0d02

Please sign in to comment.