mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Add asfDisallowIncomingTrustline check to OfferCreate and comprehensive tests
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
This commit is contained in:
committed by
Mayukha Vadari
parent
d34a960de7
commit
fa0cc0abcd
@@ -4173,6 +4173,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 an offer to acquire USD/gw, an asset for which
|
||||
// she does not have a trust line. The offer is created successfully.
|
||||
//
|
||||
// 2. gw sets asfDisallowIncomingTrustline flag.
|
||||
//
|
||||
// 3. bob tries to create an offer for USD/gw without a trustline.
|
||||
// This should fail with tecNO_LINE.
|
||||
//
|
||||
// 4. bob creates a trustline to USD/gw, then creates an offer.
|
||||
// The offer should succeed and cross alice's offer.
|
||||
|
||||
using namespace jtx;
|
||||
|
||||
// Test without fixDisallowIncomingV1 amendment
|
||||
{
|
||||
Env env{*this, features - fixDisallowIncomingV1};
|
||||
|
||||
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 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 gwUSD = gw["USD"];
|
||||
|
||||
env.fund(XRP(400000), gw, alice, bob, carol);
|
||||
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));
|
||||
env.require(balance(alice, gwUSD(50)));
|
||||
|
||||
// GW sets DisallowIncomingTrustline flag
|
||||
env(fset(gw, asfDisallowIncomingTrustline));
|
||||
env.close();
|
||||
|
||||
// Bob tries to create offer without trustline - should fail
|
||||
env(offer(bob, 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)));
|
||||
|
||||
// Bob shouldn't have any offers or balance
|
||||
env.require(offers(bob, 0));
|
||||
env.require(balance(bob, gwUSD(none)));
|
||||
|
||||
// Bob creates trustline first
|
||||
env(trust(bob, gwUSD(100)));
|
||||
env.close();
|
||||
|
||||
// Now bob can create an offer and it should 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 before flag is set
|
||||
env(trust(carol, gwUSD(100)));
|
||||
env.close();
|
||||
|
||||
// Alice creates another sell offer
|
||||
env(offer(alice, XRP(1000), gwUSD(10)));
|
||||
env.close();
|
||||
env.require(offers(alice, 1));
|
||||
|
||||
// Carol should be able to create offer since trustline already exists
|
||||
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(0)));
|
||||
env.require(balance(carol, gwUSD(10)));
|
||||
|
||||
// Test that gw can clear the flag
|
||||
env(fclear(gw, asfDisallowIncomingTrustline));
|
||||
env.close();
|
||||
|
||||
// Create new account dan without trustline
|
||||
auto const dan = Account("dan");
|
||||
env.fund(XRP(400000), dan);
|
||||
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));
|
||||
|
||||
// Dan should now be able to create offer without trustline (flag is cleared)
|
||||
env(offer(dan, gwUSD(50), XRP(5000)));
|
||||
env.close();
|
||||
|
||||
// Offer should have crossed
|
||||
env.require(offers(bob, 0));
|
||||
env.require(offers(dan, 0));
|
||||
env.require(balance(dan, gwUSD(50)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testRCSmoketest(FeatureBitset features)
|
||||
{
|
||||
@@ -5009,6 +5168,7 @@ public:
|
||||
testSelfPayUnlimitedFunds(features);
|
||||
testRequireAuth(features);
|
||||
testMissingAuth(features);
|
||||
testDisallowIncomingTrustline(features);
|
||||
testRCSmoketest(features);
|
||||
testSelfAuth(features);
|
||||
testDeletedOfferIssuer(features);
|
||||
|
||||
@@ -216,6 +216,20 @@ CreateOffer::checkAcceptAsset(
|
||||
// An account can always accept its own issuance.
|
||||
return tesSUCCESS;
|
||||
|
||||
// Check if the issuer has lsfDisallowIncomingTrustline set
|
||||
// If so, the account must already have a trustline to receive tokens
|
||||
if (view.rules().enabled(fixDisallowIncomingV1) &&
|
||||
((*issuerAccount)[sfFlags] & lsfDisallowIncomingTrustline))
|
||||
{
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user