Skip to content

Smart Contracts - Standardize ERC20FeeProxy and EthereumFeeProxy platform fee behavior #1692

@MantisClone

Description

@MantisClone

Problem

ERC20FeeProxy lacks a fee-from-total function that EthereumFeeProxy already has:

Contract Fee-from-total (payee bears fee) Fee-as-surplus (payer bears fee)
EthereumFeeProxy transferWithReferenceAndFee transferExactEthWithReferenceAndFee
ERC20FeeProxy missing transferFromWithReferenceAndFee

EthereumFeeProxy supports both modes:

// Fee-from-total (payee bears): fee deducted from msg.value
transferWithReferenceAndFee(to, ref, feeAmount, feeAddress)
// → payee receives msg.value - feeAmount

// Fee-as-surplus (payer bears): explicit amounts
transferExactEthWithReferenceAndFee(to, amount, ref, feeAmount, feeAddress)
// → payee receives amount, payer must provide amount + fee

ERC20FeeProxy only supports fee-as-surplus:

// Fee-as-surplus (payer bears): explicit amounts
transferFromWithReferenceAndFee(token, to, amount, ref, feeAmount, feeAddress)
// → payee receives amount, payer must provide amount + fee

This gap:

  1. Prevents contract-level support for payee-borne fees on ERC20 payments
  2. Creates interface inconsistency between ETH and ERC20 integrations

Proposed Solution

Add a fee-from-total function to ERC20FeeProxy:

function transferFromTotalWithReferenceAndFee(
    address _tokenAddress,
    address _to,
    uint256 _totalAmount,    // total to pull from payer
    bytes calldata _paymentReference,
    uint256 _feeAmount,
    address _feeAddress
) external {
    uint256 payeeAmount = _totalAmount - _feeAmount;
    safeTransferFrom(_tokenAddress, _to, payeeAmount);
    if (_feeAmount > 0 && _feeAddress \!= address(0)) {
        safeTransferFrom(_tokenAddress, _feeAddress, _feeAmount);
    }
    emit TransferWithReferenceAndFee(...);
}

This enables contract-level feeBearer:

  • Payer bears fee: Use existing transferFromWithReferenceAndFee (payer sends amount + fee)
  • Payee bears fee: Use new transferFromTotalWithReferenceAndFee (payer sends total, payee receives total - fee)

Scope

This is a major undertaking with ripple effects across the stack:

1. Smart Contract Changes

  • ERC20FeeProxy: Add transferFromTotalWithReferenceAndFee
  • BatchNoConversionPayments: Support new function
  • BatchConversionPayments: Support new function
  • Conversion proxies: Audit and update as needed
  • Other dependent contracts: Audit each

2. Contract Deployment

  • Deploy updated contracts to all supported chains
  • Old contract versions remain operational (backwards compatibility)
  • New deployments coexist with existing ones

3. SDK Changes

4. Payment Detection

  • Update detection logic for new function/events
  • Handle both old and new contract events

5. Payment Subgraph

  • Index new contract deployments (required regardless of event changes)
  • If event structure changes, update subgraph schema/mappings

6. Event Structure Decision

  • Decide whether to emit totalAmount or payeeAmount in event
  • This affects payment detection and subgraph

Considerations

  • Requires security audit for all contract changes
  • Backwards compatibility: old contracts remain operational, no migration required for existing requests

Related Issues

feeBearer without contract changes (can ship independently):

These implement feeBearer using payment calculation + balance interpretation with existing contracts. They work today without #1692.

What #1692 adds:
This issue enables on-chain events to potentially emit the total amount (via new function or modified event structure), providing full consistency for on-chain observers. Without #1692, on-chain events only show the net amount paid to payee.

References

  • ERC20FeeProxy: /packages/smart-contracts/src/contracts/ERC20FeeProxy.sol
  • EthereumFeeProxy: /packages/smart-contracts/src/contracts/EthereumFeeProxy.sol

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    Status

    🆕 New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions