-
Notifications
You must be signed in to change notification settings - Fork 92
Description
Problem
When a merchant wants to bear the platform fee, there's no standard way to express this intent in a request. The SDK's payment logic assumes payer pays expectedAmount + fee, so merchants must reduce expectedAmount to match what the payee actually receives.
This works, but:
- The request's expectedAmount doesn't reflect the order total
- There's no standard field indicating who bears the fee
- External systems must infer the arrangement from context
Limitation: This issue addresses SDK-level changes only. On-chain events still emit the net amount paid to payee. Full on-chain consistency requires contract changes (#1692).
Proposed Solution
Two SDK changes are required:
1. Payment Processor: Adjust payment amounts based on feeBearer
Currently, SDK payment calculates:
// Current: payer always pays expectedAmount + fee
payerPays = expectedAmount + feeAmount
payeeReceives = expectedAmountWith feeBearer support:
if (feeBearer === "payer") {
// Payer bears fee (current behavior)
payerPays = expectedAmount + feeAmount
payeeReceives = expectedAmount
} else if (feeBearer === "payee") {
// Payee bears fee
payerPays = expectedAmount // order total
payeeReceives = expectedAmount - feeAmount
}Contract calls with feeBearer = "payee":
// ETH: Use existing transferWithReferenceAndFee (fee-from-total)
// Payer sends expectedAmount as msg.value, contract deducts fee
transferWithReferenceAndFee(payee, ref, feeAmount, feeAddress)
// msg.value = expectedAmount
// ERC20: Use existing transferFromWithReferenceAndFee with adjusted amounts
transferFromWithReferenceAndFee(token, payee, payeeReceives, ref, feeAmount, feeAddress)
// Payer approves: payeeReceives + feeAmount = expectedAmountThis works with current contracts — no #1692 required.
2. Payment Detection: Adjust balance interpretation based on feeBearer
- Add
feeBearerfield to paymentNetwork extension stored in the request feeBearercan be"payer"or"payee"- Adjust balance check logic:
- Payer:
balance >= expectedAmount(current behavior) - Payee:
balance >= expectedAmount - serviceFee
- Payer:
Example: $100 Order with $10 Fee
| feeBearer | Payer Pays | Payee Receives | On-chain event amount |
expectedAmount | Balance Check |
|---|---|---|---|---|---|
"payer" |
$110 | $100 | $100 | $100 | $100 >= $100 ✓ |
"payee" |
$100 | $90 | $90 | $100 | $90 >= $100-$10 ✓ |
Considerations
- On-chain events emit net amount: The event
amountfield shows what payee received ($90), not the order total ($100). External systems reading only on-chain data won't see the full picture. - Works with current contracts: No contract changes required. ETH uses
transferWithReferenceAndFee(already fee-from-total). ERC20 usestransferFromWithReferenceAndFeewith calculated amounts. - Contract changes (Smart Contracts - Standardize ERC20FeeProxy and EthereumFeeProxy platform fee behavior #1692): Would enable on-chain events to emit the total, providing full consistency for on-chain observers. Not required for this implementation.
- Complementary to API-level approach (RequestNetwork/request-api#456): Either can be implemented independently. If both are implemented, they should use consistent logic.
- Precision: This is NOT the gas fee or protocol fee. Nor is it a crosschain solver fee or gateway fee.
Related Issues
This is one of two independent approaches to implementing feeBearer:
| Approach | Issue | Implementation | Scope |
|---|---|---|---|
| SDK-level | This issue (#1582) | PaymentNetwork extension + SDK payment/balance logic | SDK users |
| API-level | RequestNetwork/request-api#456 | Database field + API payment/status logic | API users only |
Key points:
- Either approach can be implemented independently
- SDK-level stores feeBearer in the protocol (IPFS); API-level stores in database only
- If both are implemented, the API could optionally read feeBearer from SDK instead of database
Contract-level feeBearer (#1692):
If #1692 ships, ERC20FeeProxy would gain a fee-from-total function. This would enable on-chain events to emit the total amount, providing full consistency for on-chain observers.
Historical Context
Original description:
Add chargeBearer field to the paymentNetwork extension stored in the request. The
chargeBearerfield will define who pays the "service fee" (aka. "platform fee", "app builder fee")Details:
- Charge Bearer can be "payer" or "payee".
- Charge Bearer setting changes the way we interpret the balance for determining if a request is paid or not.
- If charge bearer is "payer" then the interpretation remains the same: if (balance > expectedAmount) { status = paid }
- If charge bearer is "payee" then the interpretation would be: if (balance > expectedAmount - serviceFee) { status = paid }
- Inspired by PayGrid.
Precision: This is NOT the gas fee or protocol fee. Nor is it a crosschain solver fee or gateway fee.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status