mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-23 07:10:53 +00:00
fix: Apply asfDisallowIncomingTrustline blocker to OfferCreate (#6307)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Mayukha Vadari <mvadari@gmail.com> Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
This commit is contained in:
@@ -4324,6 +4324,165 @@ public:
|
||||
env.require(Balance(bob, gwUSD(10)));
|
||||
}
|
||||
|
||||
void
|
||||
testDisallowIncomingTrustline(FeatureBitset features)
|
||||
{
|
||||
testcase("DisallowIncomingTrustline in OfferCreate");
|
||||
|
||||
// Test that asfDisallowIncomingTrustline flag prevents offer crossing
|
||||
// when the taker doesn't have a trustline.
|
||||
//
|
||||
// 1. alice creates a trustline and sells USD/gw tokens.
|
||||
//
|
||||
// 2. gw sets asfDisallowIncomingTrustline flag.
|
||||
//
|
||||
// 3. An account without a trustline tries to create an offer for USD/gw.
|
||||
// Without amendment: succeeds and crosses alice's offer (backward compatible).
|
||||
// With amendment: fails with tecNO_LINE (new behavior).
|
||||
//
|
||||
// 4. An account WITH an existing trustline can create an offer.
|
||||
// The offer succeeds and crosses alice's offer.
|
||||
//
|
||||
// Note: The DisallowIncomingTrustline flag also prevents NEW trustlines
|
||||
// from being created via TrustSet (enforced by fixDisallowIncomingV1).
|
||||
// So accounts must create trustlines BEFORE the issuer sets the flag.
|
||||
|
||||
using namespace jtx;
|
||||
auto const gw = Account("gw");
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
auto const dan = Account("dan");
|
||||
auto const eve = Account("eve");
|
||||
auto const gwUSD = gw["USD"];
|
||||
|
||||
// Test without fixCleanup3_4_0 amendment
|
||||
{
|
||||
Env env{*this, features - fixCleanup3_4_0};
|
||||
|
||||
env.fund(XRP(400000), gw, alice, bob);
|
||||
env.close();
|
||||
|
||||
// Alice creates trustline and gets some USD
|
||||
env(trust(alice, gwUSD(100)));
|
||||
env.close();
|
||||
env(pay(gw, alice, gwUSD(50)));
|
||||
env.close();
|
||||
|
||||
// Alice creates sell offer
|
||||
env(offer(alice, XRP(4000), gwUSD(40)));
|
||||
env.close();
|
||||
env.require(offers(alice, 1));
|
||||
|
||||
// GW sets DisallowIncomingTrustline flag
|
||||
env(fset(gw, asfDisallowIncomingTrustline));
|
||||
env.close();
|
||||
|
||||
// Without the amendment, bob can still create offer without trustline
|
||||
// and the offer should cross (old behavior)
|
||||
env(offer(bob, gwUSD(40), XRP(4000)));
|
||||
env.close();
|
||||
|
||||
// Offer should have crossed
|
||||
env.require(offers(alice, 0));
|
||||
env.require(offers(bob, 0));
|
||||
env.require(Balance(bob, gwUSD(40)));
|
||||
}
|
||||
|
||||
// Test with fixCleanup3_4_0 amendment
|
||||
{
|
||||
Env env{*this, features};
|
||||
|
||||
env.fund(XRP(400000), gw, alice, bob, carol, dan);
|
||||
env.close();
|
||||
|
||||
// Alice creates trustline and gets some USD
|
||||
env(trust(alice, gwUSD(100)));
|
||||
env.close();
|
||||
env(pay(gw, alice, gwUSD(50)));
|
||||
env.close();
|
||||
|
||||
// Bob and carol create trustlines BEFORE the flag is set
|
||||
env(trust(bob, gwUSD(100)));
|
||||
env.close();
|
||||
env(trust(carol, gwUSD(100)));
|
||||
env.close();
|
||||
|
||||
// Alice creates sell offer
|
||||
env(offer(alice, XRP(4000), gwUSD(40)));
|
||||
env.close();
|
||||
env.require(offers(alice, 1));
|
||||
env.require(Balance(alice, gwUSD(50)));
|
||||
|
||||
// GW sets DisallowIncomingTrustline flag
|
||||
env(fset(gw, asfDisallowIncomingTrustline));
|
||||
env.close();
|
||||
|
||||
// Dan tries to create offer without trustline - should fail
|
||||
env(offer(dan, gwUSD(40), XRP(4000)), Ter(tecNO_LINE));
|
||||
env.close();
|
||||
|
||||
// Alice's offer should still exist
|
||||
env.require(offers(alice, 1));
|
||||
env.require(Balance(alice, gwUSD(50)));
|
||||
|
||||
// Dan shouldn't have any offers or balance
|
||||
env.require(offers(dan, 0));
|
||||
BEAST_EXPECT(env.le(keylet::trustLine(dan, gwUSD)) == nullptr);
|
||||
|
||||
// Bob already has trustline, so his offer should succeed and cross
|
||||
env(offer(bob, gwUSD(40), XRP(4000)));
|
||||
env.close();
|
||||
|
||||
// Offer should have crossed
|
||||
env.require(offers(alice, 0));
|
||||
env.require(offers(bob, 0));
|
||||
env.require(Balance(alice, gwUSD(10)));
|
||||
env.require(Balance(bob, gwUSD(40)));
|
||||
|
||||
// Test scenario where carol already has a trustline (created before flag was set)
|
||||
// Carol should be able to create offer since trustline already exists
|
||||
env(pay(gw, alice, gwUSD(50)));
|
||||
env.close();
|
||||
env(offer(alice, XRP(1000), gwUSD(10)));
|
||||
env.close();
|
||||
env.require(offers(alice, 1));
|
||||
|
||||
env(offer(carol, gwUSD(10), XRP(1000)));
|
||||
env.close();
|
||||
|
||||
// Offer should have crossed
|
||||
env.require(offers(alice, 0));
|
||||
env.require(offers(carol, 0));
|
||||
env.require(Balance(alice, gwUSD(50)));
|
||||
env.require(Balance(carol, gwUSD(10)));
|
||||
|
||||
// Test that gw can clear the flag
|
||||
env(fclear(gw, asfDisallowIncomingTrustline));
|
||||
env.close();
|
||||
|
||||
// Create new account eve without trustline
|
||||
env.fund(XRP(400000), eve);
|
||||
env.close();
|
||||
|
||||
// Bob creates another sell offer
|
||||
env(pay(gw, bob, gwUSD(50)));
|
||||
env.close();
|
||||
env(offer(bob, XRP(5000), gwUSD(50)));
|
||||
env.close();
|
||||
env.require(offers(bob, 1));
|
||||
|
||||
// Eve should now be able to create offer without trustline (flag is cleared)
|
||||
env(offer(eve, gwUSD(50), XRP(5000)));
|
||||
env.close();
|
||||
|
||||
// Offer should have crossed
|
||||
env.require(offers(bob, 0));
|
||||
env.require(offers(eve, 0));
|
||||
env.require(Balance(eve, gwUSD(50)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testRCSmoketest(FeatureBitset features)
|
||||
{
|
||||
@@ -5167,6 +5326,7 @@ public:
|
||||
testSelfPayUnlimitedFunds(features);
|
||||
testRequireAuth(features);
|
||||
testMissingAuth(features);
|
||||
testDisallowIncomingTrustline(features);
|
||||
testRCSmoketest(features);
|
||||
testSelfAuth(features);
|
||||
testDeletedOfferIssuer(features);
|
||||
|
||||
Reference in New Issue
Block a user