Retire Flow Cross amendment (#5562)

The FlowCross amendment is now permanently enabled, so all code branches that have this amendment disabled are removed.
This commit is contained in:
Vlad
2025-07-16 11:53:13 +01:00
committed by GitHub
parent 452263eaa5
commit c9135a63cd
18 changed files with 52 additions and 271 deletions

View File

@@ -98,7 +98,6 @@ XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYe
// fix1781: XRPEndpointSteps should be included in the circular payment check
XRPL_FIX (1781, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes)
// fixQualityUpperBound should be activated before FlowCross
XRPL_FIX (QualityUpperBound, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes)
@@ -116,7 +115,6 @@ XRPL_FIX (1571, Supported::yes, VoteBehavior::DefaultYe
XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes)
// The following amendments are obsolete, but must remain supported
@@ -159,3 +157,4 @@ XRPL_RETIRE(fix1201)
XRPL_RETIRE(fix1512)
XRPL_RETIRE(fix1523)
XRPL_RETIRE(fix1528)
XRPL_RETIRE(FlowCross)

View File

@@ -77,10 +77,8 @@ public:
auto const gw = Account("gateway");
auto const USD = gw["USD"];
// The number of allowed offers to cross is different between
// Taker and FlowCross. Taker allows 850 and FlowCross allows 1000.
// Accommodate that difference in the test.
int const maxConsumed = features[featureFlowCross] ? 1000 : 850;
// The payment engine allows 1000 offers to cross.
int const maxConsumed = 1000;
env.fund(XRP(100000000), gw, "alice", "bob", "carol");
int const bobsOfferCount = maxConsumed + 150;
@@ -119,11 +117,8 @@ public:
env.fund(XRP(100000000), gw, "alice", "bob", "carol", "dan", "evita");
// The number of offers allowed to cross is different between
// Taker and FlowCross. Taker allows 850 and FlowCross allows 1000.
// Accommodate that difference in the test.
bool const isFlowCross{features[featureFlowCross]};
int const maxConsumed = isFlowCross ? 1000 : 850;
// The payment engine allows 1000 offers to cross.
int const maxConsumed = 1000;
int const evitasOfferCount{maxConsumed + 49};
env.trust(USD(1000), "alice");
@@ -133,14 +128,8 @@ public:
env.trust(USD(evitasOfferCount + 1), "evita");
env(pay(gw, "evita", USD(evitasOfferCount + 1)));
// Taker and FlowCross have another difference we must accommodate.
// Taker allows a total of 1000 unfunded offers to be consumed
// beyond the 850 offers it can take. FlowCross draws no such
// distinction; its limit is 1000 funded or unfunded.
//
// Give carol an extra 150 (unfunded) offers when we're using Taker
// to accommodate that difference.
int const carolsOfferCount{isFlowCross ? 700 : 850};
// The payment engine has a limit of 1000 funded or unfunded offers.
int const carolsOfferCount{700};
n_offers(env, 400, "alice", XRP(1), USD(1));
n_offers(env, carolsOfferCount, "carol", XRP(1), USD(1));
n_offers(env, evitasOfferCount, "evita", XRP(1), USD(1));
@@ -268,9 +257,9 @@ public:
}
void
testAutoBridgedLimitsFlowCross(FeatureBitset features)
testAutoBridgedLimits(FeatureBitset features)
{
testcase("Auto Bridged Limits FlowCross");
testcase("Auto Bridged Limits");
// If any book step in a payment strand consumes 1000 offers, the
// liquidity from the offers is used, but that strand will be marked as
@@ -452,26 +441,6 @@ public:
}
}
void
testAutoBridgedLimits(FeatureBitset features)
{
// Taker and FlowCross are too different in the way they handle
// autobridging to make one test suit both approaches.
//
// o Taker alternates between books, completing one full increment
// before returning to make another pass.
//
// o FlowCross extracts as much as possible in one book at one Quality
// before proceeding to the other book. This reduces the number of
// times we change books.
//
// So the tests for the two forms of autobridging are separate.
if (features[featureFlowCross])
testAutoBridgedLimitsFlowCross(features);
else
testAutoBridgedLimitsTaker(features);
}
void
testOfferOverflow(FeatureBitset features)
{
@@ -522,11 +491,10 @@ public:
n_offers(env, 998, alice, XRP(0.96), USD(1));
n_offers(env, 998, alice, XRP(0.95), USD(1));
bool const withFlowCross = features[featureFlowCross];
bool const withSortStrands = features[featureFlowSortStrands];
auto const expectedTER = [&]() -> TER {
if (withFlowCross && !withSortStrands)
if (!withSortStrands)
return TER{tecOVERSIZE};
return tesSUCCESS;
}();
@@ -535,8 +503,6 @@ public:
env.close();
auto const expectedUSD = [&] {
if (!withFlowCross)
return USD(850);
if (!withSortStrands)
return USD(0);
return USD(1996);
@@ -558,11 +524,9 @@ public:
using namespace jtx;
auto const sa = supported_amendments();
testAll(sa);
testAll(sa - featureFlowSortStrands);
testAll(sa - featurePermissionedDEX);
testAll(sa - featureFlowSortStrands - featurePermissionedDEX);
testAll(
sa - featureFlowCross - featureFlowSortStrands -
featurePermissionedDEX);
}
};

View File

@@ -143,8 +143,6 @@ public:
{
using namespace jtx;
auto const sa = supported_amendments();
test_convert_all_of_an_asset(
sa - featureFlowCross - featurePermissionedDEX);
test_convert_all_of_an_asset(sa - featurePermissionedDEX);
test_convert_all_of_an_asset(sa);
}

View File

@@ -147,7 +147,6 @@ public:
{
using namespace test::jtx;
auto const sa = supported_amendments();
testXRPDiscrepancy(sa - featureFlowCross - featurePermissionedDEX);
testXRPDiscrepancy(sa - featurePermissionedDEX);
testXRPDiscrepancy(sa);
}

View File

@@ -1333,7 +1333,6 @@ struct Flow_test : public beast::unit_test::suite
using namespace jtx;
auto const sa = supported_amendments();
testWithFeats(sa - featureFlowCross - featurePermissionedDEX);
testWithFeats(sa - featurePermissionedDEX);
testWithFeats(sa);
testEmptyStrand(sa);
@@ -1347,12 +1346,9 @@ struct Flow_manual_test : public Flow_test
{
using namespace jtx;
auto const all = supported_amendments();
FeatureBitset const flowCross{featureFlowCross};
FeatureBitset const f1513{fix1513};
FeatureBitset const permDex{featurePermissionedDEX};
testWithFeats(all - flowCross - f1513 - permDex);
testWithFeats(all - flowCross - permDex);
testWithFeats(all - f1513 - permDex);
testWithFeats(all - permDex);
testWithFeats(all);

View File

@@ -961,24 +961,12 @@ class Freeze_test : public beast::unit_test::suite
env.close();
// test: A1 wants to buy, must fail
if (features[featureFlowCross])
{
env(offer(A1, USD(1), XRP(2)),
txflags(tfFillOrKill),
ter(tecKILLED));
env.close();
env.require(
balance(A1, USD(1002)),
balance(A2, USD(997)),
offers(A1, 0));
}
else
{
// The transaction that should be here would succeed.
// I don't want to adjust balances in following tests. Flow
// cross feature flag is not relevant to this particular test
// case so we're not missing out some corner cases checks.
}
env(offer(A1, USD(1), XRP(2)),
txflags(tfFillOrKill),
ter(tecKILLED));
env.close();
env.require(
balance(A1, USD(1002)), balance(A2, USD(997)), offers(A1, 0));
// test: A1 can create passive sell offer
env(offer(A1, XRP(2), USD(1)), txflags(tfPassive));
@@ -2107,17 +2095,14 @@ public:
};
using namespace test::jtx;
auto const sa = supported_amendments();
testAll(
sa - featureFlowCross - featureDeepFreeze - featurePermissionedDEX -
fixEnforceNFTokenTrustlineV2);
testAll(
sa - featureFlowCross - featurePermissionedDEX -
fixEnforceNFTokenTrustlineV2);
testAll(
sa - featureDeepFreeze - featurePermissionedDEX -
fixEnforceNFTokenTrustlineV2);
testAll(sa - featurePermissionedDEX - fixEnforceNFTokenTrustlineV2);
testAll(sa - featureDeepFreeze - featurePermissionedDEX);
testAll(sa - featurePermissionedDEX);
testAll(sa - fixEnforceNFTokenTrustlineV2);
testAll(sa - featureDeepFreeze);
testAll(sa);
}
};

View File

@@ -1343,18 +1343,10 @@ public:
// NOTE :
// At this point, all offers are expected to be consumed.
// Alas, they are not - because of a bug in the Taker auto-bridging
// implementation which is addressed by fixTakerDryOfferRemoval.
// The pre-fixTakerDryOfferRemoval implementation (incorrect) leaves
// an empty offer in the second leg of the bridge. Validate both the
// old and the new behavior.
{
auto acctOffers = offersOnAccount(env, account_to_test);
bool const noStaleOffers{
features[featureFlowCross] ||
features[fixTakerDryOfferRemoval]};
BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
BEAST_EXPECT(acctOffers.size() == 0);
for (auto const& offerPtr : acctOffers)
{
auto const& offer = *offerPtr;
@@ -1464,8 +1456,7 @@ public:
std::uint32_t const bobOfferSeq = env.seq(bob);
env(offer(bob, XRP(2000), USD(1)));
if (localFeatures[featureFlowCross] &&
localFeatures[fixReducedOffersV2])
if (localFeatures[fixReducedOffersV2])
{
// With the rounding introduced by fixReducedOffersV2, bob's
// offer does not cross alice's offer and goes straight into
@@ -1489,8 +1480,7 @@ public:
// crossing algorithms becomes apparent. The old offer crossing
// would consume small_amount and transfer no XRP. The new offer
// crossing transfers a single drop, rather than no drops.
auto const crossingDelta =
localFeatures[featureFlowCross] ? drops(1) : drops(0);
auto const crossingDelta = drops(1);
jrr = ledgerEntryState(env, alice, gw, "USD");
BEAST_EXPECT(
@@ -2044,15 +2034,9 @@ public:
env.require(balance(carol, USD(0)));
env.require(balance(carol, EUR(none)));
// If neither featureFlowCross nor fixTakerDryOfferRemoval are defined
// then carol's offer will be left on the books, but with zero value.
int const emptyOfferCount{
features[featureFlowCross] || features[fixTakerDryOfferRemoval]
? 0
: 1};
env.require(offers(carol, 0 + emptyOfferCount));
env.require(owners(carol, 1 + emptyOfferCount));
env.require(offers(carol, 0));
env.require(owners(carol, 1));
}
void
@@ -4236,22 +4220,13 @@ public:
};
// clang-format off
TestData const takerTests[]{
// btcStart ------------------- actor[0] -------------------- ------------------- actor[1] --------------------
{0, 0, 1, BTC(5), {{"deb", 0, drops(3900000'000000 - 4 * baseFee), BTC(5), USD(3000)}, {"dan", 0, drops(4100000'000000 - 3 * baseFee), BTC(0), USD(750)}}}, // no BTC xfer fee
{0, 0, 0, BTC(5), {{"flo", 0, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee
};
TestData const flowTests[]{
TestData const tests[]{
// btcStart ------------------- actor[0] -------------------- ------------------- actor[1] --------------------
{0, 0, 1, BTC(5), {{"gay", 1, drops(3950000'000000 - 4 * baseFee), BTC(5), USD(2500)}, {"gar", 1, drops(4050000'000000 - 3 * baseFee), BTC(0), USD(1375)}}}, // no BTC xfer fee
{0, 0, 0, BTC(5), {{"hye", 2, drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }} // no xfer fee
};
// clang-format on
// Pick the right tests.
auto const& tests = features[featureFlowCross] ? flowTests : takerTests;
for (auto const& t : tests)
{
Account const& self = t.actors[t.self].acct;
@@ -4378,9 +4353,8 @@ public:
// 1. alice creates an offer to acquire USD/gw, an asset for which
// she does not have a trust line. At some point in the future,
// gw adds lsfRequireAuth. Then, later, alice's offer is crossed.
// a. With Taker alice's unauthorized offer is consumed.
// b. With FlowCross alice's offer is deleted, not consumed,
// since alice is not authorized to hold USD/gw.
// Alice's offer is deleted, not consumed, since alice is not
// authorized to hold USD/gw.
//
// 2. alice tries to create an offer for USD/gw, now that gw has
// lsfRequireAuth set. This time the offer create fails because
@@ -4428,33 +4402,17 @@ public:
// gw now requires authorization and bob has gwUSD(50). Let's see if
// bob can cross alice's offer.
//
// o With Taker bob's offer should cross alice's.
// o With FlowCross bob's offer shouldn't cross and alice's
// unauthorized offer should be deleted.
// Bob's offer shouldn't cross and alice's unauthorized offer should be
// deleted.
env(offer(bob, XRP(4000), gwUSD(40)));
env.close();
std::uint32_t const bobOfferSeq = env.seq(bob) - 1;
bool const flowCross = features[featureFlowCross];
env.require(offers(alice, 0));
if (flowCross)
{
// alice's unauthorized offer is deleted & bob's offer not crossed.
env.require(balance(alice, gwUSD(none)));
env.require(offers(bob, 1));
env.require(balance(bob, gwUSD(50)));
}
else
{
// alice's offer crosses bob's
env.require(balance(alice, gwUSD(40)));
env.require(offers(bob, 0));
env.require(balance(bob, gwUSD(10)));
// The rest of the test verifies FlowCross behavior.
return;
}
// alice's unauthorized offer is deleted & bob's offer not crossed.
env.require(balance(alice, gwUSD(none)));
env.require(offers(bob, 1));
env.require(balance(bob, gwUSD(50)));
// See if alice can create an offer without authorization. alice
// should not be able to create the offer and bob's offer should be
@@ -5186,9 +5144,7 @@ public:
// tfFillOrKill, TakerPays must be filled
{
TER const err =
features[fixFillOrKill] || !features[featureFlowCross]
? TER(tesSUCCESS)
: tecKILLED;
features[fixFillOrKill] ? TER(tesSUCCESS) : tecKILLED;
env(offer(maker, XRP(100), USD(100)));
env.close();
@@ -5410,7 +5366,6 @@ public:
{
using namespace jtx;
static FeatureBitset const all{supported_amendments()};
static FeatureBitset const flowCross{featureFlowCross};
static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
static FeatureBitset const rmSmallIncreasedQOffers{
fixRmSmallIncreasedQOffers};
@@ -5419,10 +5374,9 @@ public:
FeatureBitset const fillOrKill{fixFillOrKill};
FeatureBitset const permDEX{featurePermissionedDEX};
static std::array<FeatureBitset, 7> const feats{
static std::array<FeatureBitset, 6> const feats{
all - takerDryOffer - immediateOfferKilled - permDEX,
all - flowCross - takerDryOffer - immediateOfferKilled - permDEX,
all - flowCross - immediateOfferKilled - permDEX,
all - immediateOfferKilled - permDEX,
all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
permDEX,
all - fillOrKill - permDEX,
@@ -5444,7 +5398,7 @@ public:
}
};
class OfferWOFlowCross_test : public OfferBaseUtil_test
class OfferWTakerDryOffer_test : public OfferBaseUtil_test
{
void
run() override
@@ -5453,7 +5407,7 @@ class OfferWOFlowCross_test : public OfferBaseUtil_test
}
};
class OfferWTakerDryOffer_test : public OfferBaseUtil_test
class OfferWOSmallQOffers_test : public OfferBaseUtil_test
{
void
run() override
@@ -5462,7 +5416,7 @@ class OfferWTakerDryOffer_test : public OfferBaseUtil_test
}
};
class OfferWOSmallQOffers_test : public OfferBaseUtil_test
class OfferWOFillOrKill_test : public OfferBaseUtil_test
{
void
run() override
@@ -5471,7 +5425,7 @@ class OfferWOSmallQOffers_test : public OfferBaseUtil_test
}
};
class OfferWOFillOrKill_test : public OfferBaseUtil_test
class OfferWOPermDEX_test : public OfferBaseUtil_test
{
void
run() override
@@ -5480,21 +5434,12 @@ class OfferWOFillOrKill_test : public OfferBaseUtil_test
}
};
class OfferWOPermDEX_test : public OfferBaseUtil_test
{
void
run() override
{
OfferBaseUtil_test::run(5);
}
};
class OfferAllFeatures_test : public OfferBaseUtil_test
{
void
run() override
{
OfferBaseUtil_test::run(6, true);
OfferBaseUtil_test::run(5, true);
}
};
@@ -5505,26 +5450,23 @@ class Offer_manual_test : public OfferBaseUtil_test
{
using namespace jtx;
FeatureBitset const all{supported_amendments()};
FeatureBitset const flowCross{featureFlowCross};
FeatureBitset const f1513{fix1513};
FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
FeatureBitset const fillOrKill{fixFillOrKill};
FeatureBitset const permDEX{featurePermissionedDEX};
testAll(all - flowCross - f1513 - immediateOfferKilled - permDEX);
testAll(all - flowCross - immediateOfferKilled - permDEX);
testAll(all - f1513 - immediateOfferKilled - permDEX);
testAll(all - immediateOfferKilled - fillOrKill - permDEX);
testAll(all - fillOrKill - permDEX);
testAll(all - permDEX);
testAll(all);
testAll(all - flowCross - takerDryOffer - permDEX);
testAll(all - takerDryOffer - permDEX);
}
};
BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx, ripple, 2);
BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx, ripple, 2);
BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx, ripple, 2);
BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx, ripple, 2);
BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx, ripple, 2);

View File

@@ -1268,15 +1268,12 @@ struct PayStrand_test : public beast::unit_test::suite
{
using namespace jtx;
auto const sa = supported_amendments();
testToStrand(sa - featureFlowCross - featurePermissionedDEX);
testToStrand(sa - featurePermissionedDEX);
testToStrand(sa);
testRIPD1373(sa - featureFlowCross - featurePermissionedDEX);
testRIPD1373(sa - featurePermissionedDEX);
testRIPD1373(sa);
testLoop(sa - featureFlowCross - featurePermissionedDEX);
testLoop(sa - featurePermissionedDEX);
testLoop(sa);

View File

@@ -207,24 +207,6 @@ class PermissionedDEX_test : public beast::unit_test::suite
env.close();
}
// test preflight: permissioned dex cannot be used without enable
// flowcross
{
Env env(*this, features - featureFlowCross);
auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
PermissionedDEX(env);
env(offer(bob, XRP(10), USD(10)),
domain(domainID),
ter(temDISABLED));
env.close();
env.enableFeature(featureFlowCross);
env.close();
env(offer(bob, XRP(10), USD(10)), domain(domainID));
env.close();
}
// preclaim - someone outside of the domain cannot create domain offer
{
Env env(*this, features);

View File

@@ -75,7 +75,6 @@ struct SetAuth_test : public beast::unit_test::suite
{
using namespace jtx;
auto const sa = supported_amendments();
testAuth(sa - featureFlowCross - featurePermissionedDEX);
testAuth(sa - featurePermissionedDEX);
testAuth(sa);
}

View File

@@ -481,7 +481,6 @@ public:
using namespace test::jtx;
auto const sa = supported_amendments();
testWithFeatures(sa - featureFlowCross - featurePermissionedDEX);
testWithFeatures(sa - featurePermissionedDEX);
testWithFeatures(sa);
}

View File

@@ -104,7 +104,6 @@ struct BookDirs_test : public beast::unit_test::suite
{
using namespace jtx;
auto const sa = supported_amendments();
test_bookdir(sa - featureFlowCross - featurePermissionedDEX);
test_bookdir(sa - featurePermissionedDEX);
test_bookdir(sa);
}

View File

@@ -421,7 +421,6 @@ public:
};
using namespace jtx;
auto const sa = supported_amendments();
testAll(sa - featureFlowCross - featurePermissionedDEX);
testAll(sa - featurePermissionedDEX);
testAll(sa);
}

View File

@@ -252,10 +252,7 @@ public:
{
using namespace jtx;
auto const sa = supported_amendments();
for (auto feature :
{sa - featureFlowCross - featurePermissionedDEX,
sa - featurePermissionedDEX,
sa})
for (auto feature : {sa - featurePermissionedDEX, sa})
{
testGWB(feature);
testGWBApiVersions(feature);

View File

@@ -294,7 +294,6 @@ public:
};
using namespace jtx;
auto const sa = supported_amendments();
withFeatsTests(sa - featureFlowCross - featurePermissionedDEX);
withFeatsTests(sa - featurePermissionedDEX);
withFeatsTests(sa);
}

View File

@@ -743,7 +743,6 @@ BookStep<TIn, TOut, TDerived>::forEachOffer(
FlowOfferStream<TIn, TOut> offers(
sb, afView, book_, sb.parentCloseTime(), counter, j_);
bool const flowCross = afView.rules().enabled(featureFlowCross);
bool offerAttempted = false;
std::optional<Quality> ofrQ;
auto execOffer = [&](auto& offer) {
@@ -760,8 +759,8 @@ BookStep<TIn, TOut, TDerived>::forEachOffer(
// Make sure offer owner has authorization to own IOUs from issuer.
// An account can always own XRP or their own IOUs.
if (flowCross && (!isXRP(offer.issueIn().currency)) &&
(offer.owner() != offer.issueIn().account))
if (!isXRP(offer.issueIn().currency) &&
offer.owner() != offer.issueIn().account)
{
auto const& issuerID = offer.issueIn().account;
auto const issuer = afView.read(keylet::account(issuerID));

View File

@@ -50,12 +50,6 @@ CreateOffer::preflight(PreflightContext const& ctx)
!ctx.rules.enabled(featurePermissionedDEX))
return temDISABLED;
// Permissioned offers should use the PE (which must be enabled by
// featureFlowCross amendment)
if (ctx.rules.enabled(featurePermissionedDEX) &&
!ctx.rules.enabled(featureFlowCross))
return temDISABLED;
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;
@@ -685,54 +679,6 @@ CreateOffer::step_account(OfferStream& stream, Taker const& taker)
return false;
}
// Fill as much of the offer as possible by consuming offers
// already on the books. Return the status and the amount of
// the offer to left unfilled.
std::pair<TER, Amounts>
CreateOffer::takerCross(
Sandbox& sb,
Sandbox& sbCancel,
Amounts const& takerAmount)
{
NetClock::time_point const when = sb.parentCloseTime();
beast::WrappedSink takerSink(j_, "Taker ");
Taker taker(
cross_type_,
sb,
account_,
takerAmount,
ctx_.tx.getFlags(),
beast::Journal(takerSink));
// If the taker is unfunded before we begin crossing
// there's nothing to do - just return an error.
//
// We check this in preclaim, but when selling XRP
// charged fees can cause a user's available balance
// to go to 0 (by causing it to dip below the reserve)
// so we check this case again.
if (taker.unfunded())
{
JLOG(j_.debug()) << "Not crossing: taker is unfunded.";
return {tecUNFUNDED_OFFER, takerAmount};
}
try
{
if (cross_type_ == CrossType::IouToIou)
return bridged_cross(taker, sb, sbCancel, when);
return direct_cross(taker, sb, sbCancel, when);
}
catch (std::exception const& e)
{
JLOG(j_.error()) << "Exception during offer crossing: " << e.what();
return {tecINTERNAL, taker.remaining_offer()};
}
}
std::pair<TER, Amounts>
CreateOffer::flowCross(
PaymentSandbox& psb,
@@ -944,22 +890,11 @@ CreateOffer::cross(
Amounts const& takerAmount,
std::optional<uint256> const& domainID)
{
if (sb.rules().enabled(featureFlowCross))
{
PaymentSandbox psbFlow{&sb};
PaymentSandbox psbCancelFlow{&sbCancel};
auto const ret =
flowCross(psbFlow, psbCancelFlow, takerAmount, domainID);
psbFlow.apply(sb);
psbCancelFlow.apply(sbCancel);
return ret;
}
Sandbox sbTaker{&sb};
Sandbox sbCancelTaker{&sbCancel};
auto const ret = takerCross(sbTaker, sbCancelTaker, takerAmount);
sbTaker.apply(sb);
sbCancelTaker.apply(sbCancel);
PaymentSandbox psbFlow{&sb};
PaymentSandbox psbCancelFlow{&sbCancel};
auto const ret = flowCross(psbFlow, psbCancelFlow, takerAmount, domainID);
psbFlow.apply(sb);
psbCancelFlow.apply(sbCancel);
return ret;
}

View File

@@ -109,13 +109,6 @@ private:
bool
reachedOfferCrossingLimit(Taker const& taker) const;
// Fill offer as much as possible by consuming offers already on the books,
// and adjusting account balances accordingly.
//
// Charges fees on top to taker.
std::pair<TER, Amounts>
takerCross(Sandbox& sb, Sandbox& sbCancel, Amounts const& takerAmount);
// Use the payment flow code to perform offer crossing.
std::pair<TER, Amounts>
flowCross(