Skip to content

Request SDK - Implement feeBearer to support payee-borne fees #1582

@MantisClone

Description

@MantisClone

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:

  1. The request's expectedAmount doesn't reflect the order total
  2. There's no standard field indicating who bears the fee
  3. 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 = expectedAmount

With 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 = expectedAmount

This works with current contracts — no #1692 required.

2. Payment Detection: Adjust balance interpretation based on feeBearer

  • Add feeBearer field to paymentNetwork extension stored in the request
  • feeBearer can be "payer" or "payee"
  • Adjust balance check logic:
    • Payer: balance >= expectedAmount (current behavior)
    • Payee: balance >= expectedAmount - serviceFee

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 amount field 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 uses transferFromWithReferenceAndFee with 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 chargeBearer field 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

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    🎫 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions