Skip to content

## [CONTRACT-23] Implement pay_per_use_to for Third-Party Merchant Payments #479

Description

@orunganiekan
  • Points: 200
  • Labels: contract, pay-per-use, token, extensibility

Background

pay_per_use in lib.rs always routes payment to sub.merchant — the merchant stored in the subscription at subscribe time. This means a subscriber cannot make a one-off payment to a different merchant using the same subscription allowance, even if both are whitelisted. Use cases include: tipping a different creator, paying a marketplace fee to a platform address, or routing a single transaction to a sub-merchant in a marketplace context. The contract already tracks the subscription token and validates allowance — the routing logic is the only missing piece.

Task

Add pay_per_use_to(env: Env, user: Address, amount: i128, recipient: Address) as a public function. It follows the same flow as pay_per_use but transfers to recipient instead of sub.merchant. If whitelist::is_whitelist_enabled, verify recipient is whitelisted. Apply the protocol fee (split between fee collector and net to recipient). Record spend against the user's daily limit. Emit a pay_per_use event with recipient in place of sub.merchant. Do NOT update MerchantRevenue for sub.merchant — only update it for recipient.

Key Files

  • contract/src/lib.rs — add pay_per_use_to; factor shared pay-per-use logic into pay_per_use_inner(env, user, amount, recipient) used by both functions
  • contract/src/fee.rs — add transfer_pay_per_use(env, user, sub_token, amount, recipient) -> i128 mirroring the subscription charge transfer but accepting an explicit recipient and token
  • contract/src/test.rs — test: pay_per_use_to transfers to the specified recipient, not sub.merchant; test: whitelist-enabled contract rejects non-whitelisted recipient; test: daily limit applies to pay_per_use_to spending

Edge Cases

  • The subscription must be active and not paused (same checks as pay_per_use)
  • sub.token is used for the transfer — the recipient cannot specify a different token
  • pay_per_use_to with recipient == sub.merchant must behave identically to pay_per_use (no special-casing needed, but confirm in a test)
  • Daily limit tracks total spend across both pay_per_use and pay_per_use_to calls

Acceptance Criteria

  • pay_per_use_inner is a private function used by both pay_per_use and pay_per_use_to
  • pay_per_use_to requires user.require_auth() and ensure_contract_not_paused
  • Whitelist check applied to recipient when whitelist is enabled
  • MerchantRevenue incremented for recipient, not sub.merchant
  • Daily limit enforced across both pay-per-use variants
  • Test: payment routed to recipient with correct net amount after fee
  • cargo test passes with no regressions

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions