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:
- Prevents contract-level support for payee-borne fees on ERC20 payments
- 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
Problem
ERC20FeeProxy lacks a fee-from-total function that EthereumFeeProxy already has:
transferWithReferenceAndFeetransferExactEthWithReferenceAndFeetransferFromWithReferenceAndFeeEthereumFeeProxy supports both modes:
ERC20FeeProxy only supports fee-as-surplus:
This gap:
Proposed Solution
Add a fee-from-total function to ERC20FeeProxy:
This enables contract-level feeBearer:
transferFromWithReferenceAndFee(payer sendsamount + fee)transferFromTotalWithReferenceAndFee(payer sendstotal, payee receivestotal - fee)Scope
This is a major undertaking with ripple effects across the stack:
1. Smart Contract Changes
transferFromTotalWithReferenceAndFee2. Contract Deployment
3. SDK Changes
transferFromTotalWithReferenceAndFeefunction4. Payment Detection
5. Payment Subgraph
6. Event Structure Decision
totalAmountorpayeeAmountin eventConsiderations
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
/packages/smart-contracts/src/contracts/ERC20FeeProxy.sol/packages/smart-contracts/src/contracts/EthereumFeeProxy.sol