Skip to content

Harden signed-message domains and clarify pay-clearance semantics#3

Merged
hhl42 merged 3 commits into
mainfrom
improvements
May 5, 2026
Merged

Harden signed-message domains and clarify pay-clearance semantics#3
hhl42 merged 3 commits into
mainfrom
improvements

Conversation

@hhl42

@hhl42 hhl42 commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Two hardening themes:

  • Bind every standalone signed message to its execution domain.
    PaymentChannelInitializer carries chain_id and ledger_address;
    ConditionalPay carries chain_id. Both validated on entry. walletId
    prefixes block.chainid, so downstream channel_id-anchored messages
    bind transitively. Closes cross-chain and same-chain wrong-ledger replay
    surfaces.
  • Tighten PayResolver and clarify pay-clearance semantics.
    _resolvePayment now requires pay.payResolver == address(this).
    SimplexPaymentChannel.last_pay_resolve_deadline renamed to
    pay_clear_deadline (= max(pay.resolveDeadline) + clearMargin) — the
    margin reserves wall-clock time for clearPays to land on multi-segment
    pay lists. PayRegistry.getPayAmounts's second parameter renamed to
    _maxResolveDeadline so the registry's API describes its own domain.

Notes

  • walletId = keccak256(chainid, walletAddr, creatorAddr, nonce).
  • The pay_clear_deadline rename is not a wire-format break: same proto
    tag (6), same uint64. Off-chain producers regenerate bindings to pick
    up the new symbol; signed bytes are bit-identical.
  • README, docs/contracts.md, and relevant interface NatSpec updated. Plain
    ERC-20 only; fee-on-transfer / rebasing / ERC-777 hooks are out of scope
    (now stated in public docs).

hhl42 added 2 commits May 2, 2026 23:16
…ine rename

- PayResolver: require pay.payResolver == address(this) so a pay can only be
  resolved by the resolver its body designates
- Document plain-ERC20-only support in README, contracts.md, and openChannel
  NatSpec (fee-on-transfer / rebasing tokens are out of scope)
- Rename SimplexPaymentChannel.last_pay_resolve_deadline → pay_clear_deadline
  for clearer semantics (= max(pay.resolveDeadline) + clearMargin); rename
  PayRegistry.getPayAmounts parameter to _maxResolveDeadline so the registry
  describes its own domain; add multi-segment confirmSettle regression tests

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens replay protection for signed, standalone messages by binding them to their intended execution domain (chain + contract address where applicable), and clarifies settlement/pay-clearance semantics by renaming and tightening the “last pay resolve deadline” concept into an explicit pay_clear_deadline.

Changes:

  • Add domain-binding fields to protobuf messages (chain_id, ledger_address) and enforce them at runtime in CelerLedger.openChannel and PayResolver.
  • Rename last_pay_resolve_deadlinepay_clear_deadline across proto/Solidity/tests and update settlement gating semantics/docs accordingly.
  • Update interfaces, docs, and tests (including gas report snapshots) to reflect the new fields and naming.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/utils/Proto.t.sol Updates proto round-trip tests for new fields and renamed payClearDeadline.
test/utils/LedgerTestBase.t.sol Updates deterministic channel-id derivation to include block.chainid; adds initializer domain fields in fixtures.
test/utils/Fixtures.sol Extends fixture structs/encoders for chainId, ledgerAddress, and payClearDeadline (wire tags preserved).
test/gas_logs/fine_granularity/IntendSettle-OneState.txt Refreshes gas snapshots after additional checks/fields.
test/gas_logs/fine_granularity/DepositEthInBatch.txt Refreshes gas snapshots after additional checks/fields.
test/gas_logs/fine_granularity/ClearPays.txt Refreshes gas snapshots after additional checks/fields.
test/gas_logs/PayResolver.txt Refreshes PayResolver gas snapshots after added domain checks.
test/gas_logs/CelerLedger-ETH.txt Refreshes ETH-path deployment/call gas snapshots after changes.
test/gas_logs/CelerLedger-ERC20.txt Refreshes ERC20-path call gas snapshots after changes.
test/PayResolver.t.sol Adds regression tests for wrong-chain and wrong-resolver replays; updates pay building to include chainId.
test/PayRegistry.t.sol Aligns tests/comments with payClearDeadline terminology.
test/GasReport.t.sol Updates gas report harness to include chainId and renamed payClearDeadline.
test/CelerWallet.t.sol Updates wallet-id derivation expectation to include block.chainid.
test/CelerLedger.ETH.t.sol Adds open-channel replay protection tests (wrong chain / wrong ledger) and multi-segment clearance regression tests.
src/lib/ledgerlib/LedgerStruct.sol Renames peer state field to payClearDeadline.
src/lib/ledgerlib/LedgerOperation.sol Enforces initializer domain binding; updates settlement gating and registry calls to use payClearDeadline.
src/lib/ledgerlib/LedgerChannel.sol Renames getter to getPayClearDeadlineMap.
src/lib/interface/IPayResolver.sol Documents new domain-binding requirements for pay resolution.
src/lib/interface/IPayRegistry.sol Renames parameter to _maxResolveDeadline and clarifies semantics in NatSpec.
src/lib/interface/ICelerWallet.sol Updates wallet-id derivation NatSpec to include chainid.
src/lib/interface/ICelerLedger.sol Updates channel-id derivation NatSpec; documents initializer domain binding + token constraints.
src/lib/data/proto/entity.proto Adds chain_id / ledger_address fields; renames last_pay_resolve_deadline to pay_clear_deadline (same tag).
src/lib/data/PbEntity.sol Updates protobuf decoders/structs for new/renamed fields.
src/PayResolver.sol Enforces pay.chainId == block.chainid and pay.payResolver == address(this) before resolving.
src/PayRegistry.sol Renames getPayAmounts param and updates gating logic/comments accordingly.
src/CelerWallet.sol Changes wallet-id derivation to include block.chainid.
src/CelerLedgerMock.sol Renames mock getter/setter plumbing to payClearDeadline.
src/CelerLedger.sol Renames public getter to getPayClearDeadlineMap.
docs/contracts.md Documents supported-token constraints, wallet/channel id derivations, resolver rules, and renamed getter.
README.md Adds “Supported tokens” section clarifying plain ERC-20-only assumption.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/CelerWallet.sol Outdated
Comment thread docs/contracts.md Outdated
@hhl42

hhl42 commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

Copilot AI commented May 4, 2026

Copy link
Copy Markdown

@copilot apply changes based on the comments in this thread

Done in commit 8669201. Both the NatSpec in CelerWallet.sol and the wallet-id derivation section in docs/contracts.md now use creatorAddr (= msg.sender) instead of operatorAddr, matching the actual keccak256(block.chainid, address(this), msg.sender, _nonce) on-chain computation. The docs also clarify that creatorAddr is typically the CelerLedger contract, not the end-user operator.

Copilot finished work on behalf of hhl42 May 4, 2026 02:52
@hhl42 hhl42 merged commit f15aec0 into main May 5, 2026
2 checks passed
@hhl42 hhl42 deleted the improvements branch May 5, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants