Skip to content

fix(recurring): emit 8-byte payment references - #1751

Closed
LeoSlrRf wants to merge 1 commit into
masterfrom
feat/req-429-batch-permit-hash
Closed

fix(recurring): emit 8-byte payment references#1751
LeoSlrRf wants to merge 1 commit into
masterfrom
feat/req-429-batch-permit-hash

Conversation

@LeoSlrRf

@LeoSlrRf LeoSlrRf commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

EIP-712 SchedulePermitBatch struct and digest support

Adds a SchedulePermitBatch signed permit type to ERC20RecurringPaymentProxy, enabling a single subscriber signature to authorize a recurring payment schedule with distinct initial and recurring payment legs.

Contract changes

  • Introduces a Leg struct (recipient, amount, bytes8 paymentReference) and a SchedulePermitBatch struct that composes an array of due timestamps alongside initialLegs and recurringLegs arrays.
  • Defines _LEG_TYPEHASH and _BATCH_TYPEHASH constants following EIP-712 referenced-type ordering rules.
  • Adds internal helpers _hashLeg, _hashLegs, and _hashUint32Array to produce the correct EIP-712 encoded hashes for dynamic array fields.
  • Exposes hashScheduleBatch(SchedulePermitBatch) and the existing hashSchedule(SchedulePermit) as public view functions so off-chain clients and tests can verify digest parity without executing a transaction.

Test changes

  • Extracts schedulePermitTypes and schedulePermitBatchTypes EIP-712 type definitions as shared constants and adds an eip712Domain helper to avoid repetition.
  • Adds hashPermitOffchain and hashBatchOffchain helpers using ethers._TypedDataEncoder to compute expected digests off-chain.
  • Adds a createBatchSignature helper that mirrors createSignature for the batch permit type.
  • Adds an EIP-712 digest parity test suite that verifies the on-chain hash matches the off-chain ethers encoder for SchedulePermit, a fully-populated SchedulePermitBatch, and a batch with an empty initialLegs array. Also validates that bytes8 payment references hash differently from their zero-padded bytes32 equivalents.

@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds EIP-712 hashing support for a batch recurring-payment permit whose legs contain 8-byte payment references, plus digest-parity tests.

  • Defines Leg and SchedulePermitBatch typed-data schemas.
  • Adds public digest helpers for existing and batch schedule permits.
  • Adds off-chain/on-chain digest parity and payment-reference hashing tests.
  • The batch payload is not connected to an executable payment path, so its references cannot currently be emitted.

Confidence Score: 4/5

The batch permit must be connected to signature verification and payment execution before merging because the intended 8-byte references are currently never emitted.

The added batch schema can only produce an EIP-712 digest; no reachable function consumes the signed payload or transfers its legs, while the existing payment path remains unchanged.

Files Needing Attention: packages/smart-contracts/src/contracts/ERC20RecurringPaymentProxy.sol and packages/smart-contracts/test/contracts/ERC20RecurringPaymentProxy.test.ts

Important Files Changed

Filename Overview
packages/smart-contracts/src/contracts/ERC20RecurringPaymentProxy.sol Adds correct-looking EIP-712 digest helpers, but the new batch permit and bytes8 references are not consumed by any payment execution function.
packages/smart-contracts/test/contracts/ERC20RecurringPaymentProxy.test.ts Adds digest parity coverage, but the claimed reference-emission regression is tested only with local hashing rather than a contract event.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[SchedulePermitBatch payload] --> B[hashScheduleBatch]
  B --> C[EIP-712 digest]
  C -. no verification or execution entry point .-> D[ERC20FeeProxy transfer]
  E[Existing SchedulePermit plus arbitrary bytes reference] --> F[triggerRecurringPayment]
  F --> D
  D --> G[TransferWithReferenceAndFee event]
Loading

Reviews (1): Last reviewed commit: "fix(recurring): emit 8-byte payment refe..." | Re-trigger Greptile

Comment on lines +160 to +162
function hashScheduleBatch(SchedulePermitBatch calldata p) public view returns (bytes32) {
return _hashScheduleBatch(p);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Batch permits cannot execute

When a relayer submits a signed SchedulePermitBatch, this function can only return its digest; no entry point accepts the batch, verifies its signature, or transfers its legs. Consequently, the newly defined 8-byte references cannot be emitted and the existing recurring-payment path remains unchanged.

Knowledge Base Used:

Comment on lines +767 to +773
it('uses an 8-byte payment reference whose fee-proxy topic is not the 32-byte pad', () => {
const ref8 = ref(0x0a);
const ref32 = ethers.utils.hexZeroPad(ref8, 32);
expect(ref8).to.equal('0x000000000000000a');
expect(ethers.utils.keccak256(ref8)).to.equal(ethers.utils.keccak256('0x000000000000000a'));
expect(ethers.utils.keccak256(ref8)).to.not.equal(ethers.utils.keccak256(ref32));
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Emission path remains untested

This test only compares hashes of locally constructed byte values; it never calls triggerRecurringPayment or inspects TransferWithReferenceAndFee. Padding, truncation, or forwarding the wrong reference at the actual event boundary therefore remains undetected.

Knowledge Base Used: Payment lifecycle

@github-actions

Copy link
Copy Markdown

⚠️ Slither Security Analysis

Status: Issues Found

Findings Summary

Severity Count Status
✅ High 0 Pass
✅ Medium 0 Pass
🔵 Low 0 Info
ℹ️ Informational 0 Info

📄 Full report available in workflow artifacts.
🔍 View detailed findings in the Security tab.

@github-actions

Copy link
Copy Markdown

❌ Echidna Fuzzing Results

Mode: ( test sequences)
Status: Property Violations Found

Property Test Results

Status Count
✅ Passed 0
❌ Failed 0
Total 0
Pass Rate 0%

📄 Full report and corpus available in workflow artifacts.

ℹ️ About Echidna Fuzzing

Echidna is a property-based fuzzer that generates random sequences of transactions
to test invariants (properties that should always hold true).

Properties tested:

  • Fee calculation bounds
  • Access control enforcement
  • Amount constraints
  • No duplicate payments
  • Zero address validation
  • Integer overflow protection

@LeoSlrRf LeoSlrRf closed this Aug 24, 2026
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.

1 participant