Skip to content

feat: permit flow integration - #236

Merged
hugomrdias merged 1 commit into
FilOzone:masterfrom
lordshashank:feat/permit-flow
Oct 1, 2025
Merged

hugomrdias merged 1 commit into
FilOzone:masterfrom
lordshashank:feat/permit-flow

Conversation

@lordshashank

@lordshashank lordshashank commented Sep 23, 2025 •

Copy link
Copy Markdown
Contributor

This pull request introduces support for ERC-2612 permit-based deposits in the payments system, allowing users to approve and deposit USDFC tokens in a single transaction using EIP-712 signatures. It adds new methods to the PaymentsService for permit-based deposits, updates contract ABIs and constants to support EIP-2612, and enhances the test suite and mocks to cover the new functionality.

ERC-2612 Permit Support and Payments Enhancements:

  • Added a minimal erc20PermitAbi for reading nonces and version from ERC-20 permit tokens (src/abis/erc20-permit.ts).
  • Updated CONTRACT_ABIS to include ERC20_PERMIT, and introduced EIP2612_PERMIT_TYPES for EIP-712 typed data schema, as well as a PERMIT_DEADLINE_DURATION constant for permit expiry (src/utils/constants.ts). [1] [2] [3] [4]

PaymentsService Additions:

  • Implemented _getPermitSignature to generate EIP-2612 permit signatures, handling balance checks, domain creation, nonce retrieval, and signature generation using Multicall3 for efficient RPC batching (src/payments/service.ts).
  • Added depositWithPermit and depositWithPermitAndApproveOperator methods to allow deposits and operator approvals using ERC-2612 permits in a single transaction, improving UX and reducing on-chain transactions (src/payments/service.ts).

Testing and Mock Improvements:

  • Added tests for depositWithPermit and depositWithPermitAndApproveOperator to ensure correct behavior and signature handling (src/test/payments.test.ts).
  • Enhanced the mock signer to return a valid 65-byte signature for typed data, and improved the mock provider to correctly simulate Multicall3 and ERC-2612 permit-related contract calls (src/test/test-utils.ts). [1] [2] [3]

@github-project-automation github-project-automation Bot moved this to 📌 Triage in FOC Sep 23, 2025
@rvagg
rvagg requested a review from wjmelements September 24, 2025 06:13
@rjan90 rjan90 moved this from 📌 Triage to 🔎 Awaiting review in FOC Sep 24, 2025
@rvagg
rvagg requested a review from hugomrdias September 24, 2025 07:23
Comment thread src/abis/erc20-permit.ts
Comment thread src/payments/service.ts Outdated
Comment thread src/payments/service.ts Outdated
Comment thread src/payments/service.ts Outdated
@pali101

pali101 commented Sep 27, 2025

Copy link
Copy Markdown
Contributor

I think we can significantly improve the maintainability by refactoring the duplicated logic. The initial validation and the signature generation code are repeated across the new functions.

I suggest creating two private helper methods:

  1. A _prepareDeposit helper for validation:
private async _prepareDeposit(
    caller: 'deposit' | 'depositWithPermit' | 'depositWithPermitAndApproveOperator', 
    amount: TokenAmount, 
    token: TokenIdentifier) {
    if (token !== TOKENS.USDFC) {
      throw createError('PaymentsService', caller, `Unsupported token: ${token}`)
    }

    const depositAmountBigint = typeof amount === 'bigint' ? amount : BigInt(amount)
    if (depositAmountBigint <= 0n) {
      throw createError('PaymentsService', caller, 'Invalid amount')
    }

    const signerAddress = await this._signer.getAddress()
    const usdfcContract = this._getUsdfcContract()

    // Check balance
    const usdfcBalance = await usdfcContract.balanceOf(signerAddress)
    if (usdfcBalance < depositAmountBigint) {
      throw createError(
        'PaymentsService',
        caller,
        `Insufficient USDFC: have ${usdfcBalance.toString()}, need ${depositAmountBigint.toString()}`
      )
    }

    return {
      depositAmountBigint,
      signerAddress,
      paymentsContract: this._getPaymentsContract(),
    }
  }
  1. Similarly, a _createDepositPermitSignature helper: This would encapsulate the EIP-2612 signature logic used by both depositWithPermit and depositWithPermitAndApproveOperator.
private async _createDepositPermitSignature(caller: string, usdfcContract: ethers.Contract, signerAddress: string, depositAmountBigint: bigint, deadline?: number | bigint) {
  // ... implementation for creating and returning the signature {v, r, s, permitDeadline}
}

By doing this, our main functions will become very clean and focused, like this:

async depositWithPermit(amount: TokenAmount, token: TokenIdentifier, deadline?: number | bigint) {
  const { depositAmountBigint, signerAddress, usdfcContract, paymentsContract } = 
    await this._prepareDeposit('depositWithPermit', amount, token);

  const { v, r, s, permitDeadline } = 
    await this._createDepositPermitSignature('depositWithPermit', usdfcContract, signerAddress, depositAmountBigint, deadline);

  return paymentsContract.depositWithPermit(/* ...args */);
}

Also, it might be a good time to consider adding a simpler callback structure (e.g., an onSignatureRequest, onDepositStarting hook) to the new permit methods for better UI feedback.

Comment thread src/payments/service.ts
},
{
target: this._usdfcAddress,
allowFailure: false,

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.

since you don't allowFailure for some of these, you need to check the length of the results.

Comment thread src/payments/service.ts

const depositAmountBigint = typeof amount === 'bigint' ? amount : BigInt(amount)
if (depositAmountBigint <= 0n) {
throw createError('PaymentsService', 'depositWithPermit', 'Invalid amount')

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.

this error can say the amount was negative since that's what makes it invalid

Comment thread src/payments/service.ts
/**
* Deposit funds using ERC-2612 permit and approve an operator in a single transaction
* This signs an EIP-712 permit for the USDFC token and calls the Payments contract
* function `depositWithPermitAndApproveOperator` which both deposits and sets operator approval.

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.

should document that this can throw an error if the user rejects the signature

Comment thread src/test/payments.test.ts

it('should deposit with permit', async () => {
const depositAmount = ethers.parseUnits('10', 18)
const tx = await payments.depositWithPermit(depositAmount)

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.

should also test this with deadline being number and deadline being bigint.

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.

also depositWithPermitAndApproveOperator

@hugomrdias hugomrdias left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@github-project-automation github-project-automation Bot moved this from 🔎 Awaiting review to ✔️ Approved by reviewer in FOC Oct 1, 2025
@hugomrdias
hugomrdias merged commit 5c41189 into FilOzone:master Oct 1, 2025
18 checks passed
@github-project-automation github-project-automation Bot moved this from ✔️ Approved by reviewer to 🎉 Done in FOC Oct 1, 2025
@pali101 pali101 mentioned this pull request Oct 5, 2025
virajbhartiya pushed a commit to virajbhartiya/synapse-sdk that referenced this pull request Oct 8, 2025
Introduces support for ERC-2612 permit-based deposits in the payments system, allowing users to approve and deposit USDFC tokens in a single transaction using EIP-712 signatures. It adds new methods to the PaymentsService for permit-based deposits, updates contract ABIs and constants to support EIP-2612, and enhances the test suite and mocks to cover the new functionality.

Co-authored-by: Shashank Trivedi <lordforever@Shashanks-MacBook-Pro.local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🎉 Done

Development

Successfully merging this pull request may close these issues.

5 participants