feat: XLS-93d: Token-Enabled Payment Channels - #5448
Conversation
dabe68d to
5c1949a
Compare
5afa17d to
db65118
Compare
482f7ff to
4da5bf5
Compare
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
|
We recently merged a refactor to One-time setupIf you don't already have clang-tidy working in your env, on macOS: brew install llvm@21
# Follow brew's hint to put $(brew --prefix llvm@21)/bin on PATH so run-clang-tidy is found.Workflow on your branch (before merging develop)1. Grab the new git remote -v # should show 'upstream' among others; if not:
# git remote set-url upstream git@github.com:XRPLF/rippled.git
git fetch upstream
git checkout upstream/develop -- .clang-tidy2. Reconfigure conan/cmake so 3. Apply renames for the files modified in your PR: git diff --name-only $(git merge-base HEAD upstream/develop) HEAD \
| grep -E '\.(cpp|h|hpp|ipp)$' \
| xargs run-clang-tidy -p build -fix -allow-no-checks
# or -p .build, or whatever your build dir is called4. Build + test, then commit as a single dedicated commit: cmake --build build -j8
git commit -am "refactor: Align identifier naming with develop"5. Now merge develop: git merge upstream/developExtraRun clang-tidy once more after the merge to catch any stragglers introduced from develop's side: run-clang-tidy -p build -fix -allow-no-checks src tests
# or -p .build, or whatever your build dir is called |
|
@copilot resolve the merge conflicts in this pull request |
|
All conflicts have been resolved. Assigned reviewers can now start or resume their review. |
There was a problem hiding this comment.
Pull request overview
This PR implements XLS-93d token-enabled Payment Channels, extending payment channels to support non-XRP assets (IOUs and MPTs) behind a new TokenPaychan amendment, and refactors/extends related ledger helpers and tests to cover the new behavior.
Changes:
- Add IOU/MPT support to
PaymentChannelCreate,PaymentChannelFund, andPaymentChannelClaim, including transfer-rate capture and escrow-style locking/unlocking. - Extend paychan claim signing to serialize non-XRP amounts, and add new ledger fields (
sfTransferRate,sfIssuerNode) to paychan entries. - Add extensive unit test coverage and new jtx helpers for paychan operations and balance/escrow assertions.
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/xrpld/rpc/handlers/account/GatewayBalances.cpp | Adds paychan amounts into gateway_balances “locked” aggregation. |
| src/xrpld/app/misc/EscrowUtils.h | Introduces new app-level escrow/paychan helper templates (currently appears unused). |
| src/test/jtx/TestHelpers.h | Declares new test helpers for escrowed balances (IOU/MPT). |
| src/test/jtx/paychan.h | Adds jtx paychan transaction builders/utilities. |
| src/test/jtx/impl/TestHelpers.cpp | Implements new gateway balance / escrowed amount helpers for tests. |
| src/test/jtx/impl/paychan.cpp | Implements the new jtx paychan helpers. |
| src/test/jtx.h | Exposes the new jtx paychan helpers. |
| src/test/app/PayChanToken_test.cpp | Adds comprehensive IOU/MPT paychan test suite. |
| src/test/app/PayChan_test.cpp | Migrates existing paychan tests to new jtx::paychan::* helpers and adds coverage for feature interactions. |
| src/test/app/MPToken_test.cpp | Expands MPT JSON field-validation coverage to more txn types. |
| src/test/app/EscrowToken_test.cpp | Minor formatting cleanup. |
| src/test/app/AMM_test.cpp | Formatting adjustment for paychan create call. |
| src/libxrpl/tx/transactors/payment_channel/PaymentChannelFund.cpp | Extends fund to support token amounts via escrow-style locking. |
| src/libxrpl/tx/transactors/payment_channel/PaymentChannelCreate.cpp | Extends create to support token amounts, transfer rate capture, and issuer owner-dir tracking. |
| src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp | Extends claim to support token payouts via escrow-style unlock/apply logic and new auth serialization. |
| src/libxrpl/tx/transactors/escrow/EscrowFinish.cpp | Refactors to reuse shared escrow unlock preclaim helper. |
| src/libxrpl/tx/transactors/escrow/EscrowCreate.cpp | Refactors to reuse shared escrow create preflight/preclaim helpers. |
| src/libxrpl/tx/transactors/escrow/EscrowCancel.cpp | Refactors to reuse shared escrow unlock preclaim helper. |
| src/libxrpl/tx/invariants/MPTInvariant.cpp | Updates invariant handling to accommodate paychan claim flows. |
| src/libxrpl/tx/invariants/InvariantCheck.cpp | Adjusts XRP-not-created invariant to account for non-XRP paychans. |
| src/libxrpl/ledger/helpers/PaymentChannelHelpers.cpp | Extends close logic to return token funds and clean up issuer owner-dir link. |
| include/xrpl/protocol/PayChan.h | Adds non-XRP paychan authorization serialization. |
| include/xrpl/protocol/jss.h | Adds jss::escrowed JSON key. |
| include/xrpl/protocol/detail/transactions.macro | Marks paychan amount/balance fields as MPT-supported. |
| include/xrpl/protocol/detail/ledger_entries.macro | Adds optional fields to paychan ledger entry format. |
| include/xrpl/protocol/detail/features.macro | Introduces the TokenPaychan amendment. |
| include/xrpl/ledger/helpers/PaymentChannelHelpers.h | Updates closeChannel signature to include submitting account. |
| include/xrpl/ledger/helpers/EscrowHelpers.h | Adds shared escrow/paychan create/lock/unlock helpers for IOU/MPT flows. |
Comments suppressed due to low confidence (2)
src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp:60
sfBalance/sfAmountare no longer restricted to XRP, but this preflight still compares*bal > *amtdirectly.STAmountcomparisons throwstd::runtime_errorwhen the two amounts are not comparable (different asset types/currencies), which would make preflight throw instead of returning a TER. Add explicit validation thatbalandamt(when both present) are comparable / same asset before comparing, and reject invalid combinations withtemBAD_AMOUNT.
auto const bal = ctx.tx[~sfBalance];
if (bal && *bal <= beast::kZERO)
return temBAD_AMOUNT;
auto const amt = ctx.tx[~sfAmount];
if (amt && *amt <= beast::kZERO)
return temBAD_AMOUNT;
if (bal && amt && *bal > *amt)
return temBAD_AMOUNT;
src/libxrpl/tx/transactors/payment_channel/PaymentChannelClaim.cpp:176
- In
doApply,reqBalance > chanFundsandreqBalance - chanBalancewill throw if the claim supplies an amount/balance with an asset that doesn't match the channel'ssfAmount/sfBalance(comparisons/arithmetic on non-comparableSTAmountthrow). Please validate inpreclaim(after loading the channel) that any providedsfBalance/sfAmountare the same asset type as the channel (XRP vs IOU currency/issuer vs MPT issuance) before doing comparisons/arithmetic, and returntemBAD_AMOUNT(or similar) on mismatch.
if (ctx_.tx[~sfBalance])
{
auto const chanBalance = slep->getFieldAmount(sfBalance);
auto const chanFunds = slep->getFieldAmount(sfAmount);
auto const reqBalance = ctx_.tx[sfBalance];
if (account_ == dst && !ctx_.tx[~sfSignature])
return temBAD_SIGNATURE;
if (ctx_.tx[~sfSignature])
{
PublicKey const pk((*slep)[sfPublicKey]);
if (ctx_.tx[sfPublicKey] != pk)
return temBAD_SIGNER;
}
if (reqBalance > chanFunds)
return tecUNFUNDED_PAYMENT;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
|
All conflicts have been resolved. Assigned reviewers can now start or resume their review. |
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
|
All conflicts have been resolved. Assigned reviewers can now start or resume their review. |
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
Includes post-merge compile fixes (build-verified).
|
All conflicts have been resolved. Assigned reviewers can now start or resume their review. |
| beast::Journal j) | ||
| { | ||
| auto const& issue = amount.get<Issue>(); | ||
| AccountID const& issuer = amount.getIssuer(); |
There was a problem hiding this comment.
nit: use auto to remain consistent with the rest of this function.
| STAmount const balance = (*sleRippleState)[sfBalance]; | ||
|
|
||
| // If balance is positive, issuer must have higher address than account | ||
| if (balance > beast::kZero && issuer < account) |
There was a problem hiding this comment.
I didn't see this failure condition within the spec
There was a problem hiding this comment.
This is a guard on the internal RippleState representation, the balance sign must match the low/high account ordering. Unreachable for a well formed line (hence the LCOV_EXCL), not protocol behavior, so its not in the spec.
| return tecNO_PERMISSION; // LCOV_EXCL_LINE | ||
|
|
||
| // If balance is negative, issuer must have lower address than account | ||
| if (balance < beast::kZero && issuer > account) |
There was a problem hiding this comment.
I didn't see this failure condition within the spec
There was a problem hiding this comment.
Same as above, internal representation guard, not spec material.
| return tecLOCKED; | ||
|
|
||
| // If the mpt cannot be transferred, return tecNO_AUTH | ||
| if (auto const ter = canTransfer(view, mptIssue, account, dest); !isTesSuccess(ter)) |
There was a problem hiding this comment.
I am not quite sure if this failure case is mentioned in the spec.
There was a problem hiding this comment.
This one is in the spec, PaymentChannelCreate failure conditions: lacking lsfMPTCanTransfer fails with tecNO_AUTH unless the destination is the issuer.
| return tesSUCCESS; | ||
|
|
||
| if (!ctx.view.exists(trustLineKey) && createAsset) | ||
| if (!lineExisted && createAsset) |
There was a problem hiding this comment.
Why the need for this change?
There was a problem hiding this comment.
Leftover hoist from an earlier revision, functionally identical. Reverted to the develop form. resolved: 3c85a01
| } | ||
| else | ||
| { | ||
| if (amount <= beast::kZero) |
There was a problem hiding this comment.
Can this conditional be rolled up into the outer conditional?
| if (!sle) | ||
| return tefINTERNAL; // LCOV_EXCL_LINE | ||
|
|
||
| STAmount const amount{ctx_.tx[sfAmount]}; |
There was a problem hiding this comment.
Reference type could be used here.
There was a problem hiding this comment.
auto const, tx[sfAmount] is by value. resolved: 3c85a01
| return tefINTERNAL; // LCOV_EXCL_LINE | ||
|
|
||
| STAmount const amount{ctx_.tx[sfAmount]}; | ||
| STAmount const chanAmt{(*slep)[sfAmount]}; |
There was a problem hiding this comment.
Reference type could be used here.
There was a problem hiding this comment.
Done, getFieldAmount reference. resolved: 3c85a01
| { | ||
| if (ctx.view.rules().enabled(featureTokenPaychan)) | ||
| { | ||
| Keylet const k(ltPAYCHAN, ctx.tx[sfChannel]); |
There was a problem hiding this comment.
Nit: Can we use uniform initialization instead?
| for (json::Value::ArrayIndex i = 0; i < jv.size(); ++i) | ||
| if (!isValidJson2(jv[i])) | ||
| return false; | ||
| return true; |
There was a problem hiding this comment.
These four lines could be collapsed into
return std::all_of(std::begin(jv), std::end(jv), isValidJson2);
There was a problem hiding this comment.
That was a bad merge resolution on my side, restored develop's std::all_of form verbatim. resolved: 096fa96
|
This PR has conflicts, please resolve them in order for the PR to be reviewed. |
High Level Overview of Change
Context of Change
Type of Change
.gitignore, formatting, dropping support for older tooling)API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)