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.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:
- 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 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
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