mirror of
https://github.com/XRPLF/rippled.git
synced 2026-01-30 19:45:24 +00:00
Compare commits
7 Commits
bthomee/un
...
copilot/ap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a45546c775 | ||
|
|
fb8fd2d9e1 | ||
|
|
167d66bb3f | ||
|
|
f6bdf961e4 | ||
|
|
2a61f2dbd3 | ||
|
|
32fd267240 | ||
|
|
8765b8cc6d |
@@ -16,6 +16,7 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FIX (DisallowIncomingV1_1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (BatchInnerSigs, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocol, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -4173,6 +4173,170 @@ 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;
|
||||
|
||||
// Test without fixDisallowIncomingV1_1 amendment
|
||||
{
|
||||
Env env{*this, features - fixDisallowIncomingV1_1};
|
||||
|
||||
auto const gw = Account("gw");
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const gwUSD = gw["USD"];
|
||||
|
||||
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 fixDisallowIncomingV1_1 amendment
|
||||
{
|
||||
Env env{*this, features};
|
||||
|
||||
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 gwUSD = gw["USD"];
|
||||
|
||||
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));
|
||||
env.require(balance(dan, gwUSD(none)));
|
||||
|
||||
// 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
|
||||
auto const eve = Account("eve");
|
||||
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)
|
||||
{
|
||||
@@ -5009,6 +5173,7 @@ public:
|
||||
testSelfPayUnlimitedFunds(features);
|
||||
testRequireAuth(features);
|
||||
testMissingAuth(features);
|
||||
testDisallowIncomingTrustline(features);
|
||||
testRCSmoketest(features);
|
||||
testSelfAuth(features);
|
||||
testDeletedOfferIssuer(features);
|
||||
|
||||
@@ -216,10 +216,22 @@ CreateOffer::checkAcceptAsset(
|
||||
// An account can always accept its own issuance.
|
||||
return tesSUCCESS;
|
||||
|
||||
// Read the trustline once for multiple flag checks to optimize performance
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
// Check if the issuer has lsfDisallowIncomingTrustline set
|
||||
// If so, the account must already have a trustline to receive tokens
|
||||
if (view.rules().enabled(fixDisallowIncomingV1_1) && ((*issuerAccount)[sfFlags] & lsfDisallowIncomingTrustline))
|
||||
{
|
||||
if (!trustLine)
|
||||
{
|
||||
JLOG(j.debug()) << "delay: can't receive IOUs from issuer with DisallowIncomingTrustline set.";
|
||||
return (flags & tapRETRY) ? TER{terNO_LINE} : TER{tecNO_LINE};
|
||||
}
|
||||
}
|
||||
|
||||
if ((*issuerAccount)[sfFlags] & lsfRequireAuth)
|
||||
{
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
if (!trustLine)
|
||||
{
|
||||
return (flags & tapRETRY) ? TER{terNO_LINE} : TER{tecNO_LINE};
|
||||
@@ -248,8 +260,6 @@ CreateOffer::checkAcceptAsset(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
if (!trustLine)
|
||||
{
|
||||
return tesSUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user