Skip to content

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

Description

@MantisClone

Problem

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

ContractFee-from-total (payee bears fee)Fee-as-surplus (payer bears fee)
EthereumFeeProxytransferWithReferenceAndFeetransferExactEthWithReferenceAndFee
ERC20FeeProxymissingtransferFromWithReferenceAndFee

EthereumFeeProxy supports both modes:

// Fee-from-total (payee bears): fee deducted from msg.valuetransferWithReferenceAndFee(to, ref, feeAmount, feeAddress)
// → payee receives msg.value - feeAmount// Fee-as-surplus (payer bears): explicit amountstransferExactEthWithReferenceAndFee(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 amountstransferFromWithReferenceAndFee(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 payerbytescalldata_paymentReference,
uint256_feeAmount,
address_feeAddress
) external {
uint256 payeeAmount = _totalAmount - _feeAmount;
safeTransferFrom(_tokenAddress, _to, payeeAmount);
if (_feeAmount >0&& _feeAddress \!=address(0)) {
safeTransferFrom(_tokenAddress, _feeAddress, _feeAmount);
}
emitTransferWithReferenceAndFee(...);
}

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
    🎫 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions