Payment Router
Smart Contract

Payment Router Smart Contract

The payment router contract is written in DERO's DVM-BASIC smart contract language. It receives payments and instantly forwards them to the merchant, with an optional fee split.

Contract Functions

FunctionWho Can CallDescription
InitializeDeployerSet up merchant, fee recipient, and fee rate
PayAnyoneSend DERO through the router (splits to merchant + fee recipient)
UpdateMerchantMerchantChange the merchant address
PauseMerchantStop accepting payments
ResumeMerchantResume accepting payments
WithdrawTrappedMerchantRecover any DERO accidentally trapped in the contract
GetStatsAnyoneReturns totalProcessed

Roles

  • Merchant — The wallet that deploys the contract. Receives payment payouts. Can pause, resume, update their address, and withdraw trapped funds.
  • Fee Recipient — An optional address that receives a percentage of each payment. Set at deployment, cannot be changed.

Deployment Model

⚠️

The payment router is deployed once per merchant and reused for every payment. The merchant deploys it from their own wallet and owns it permanently. This is the opposite of the escrow contract, which deploys a fresh instance per transaction.

The deployer's wallet address automatically becomes the merchant. The contract stores aggregate statistics (totalProcessed, totalFees, paymentCount) that accumulate across all payments.

Fee Splitting

The contract supports an optional fee split in basis points (1 basis point = 0.01%):

  • Set at deployment via feeBasisPoints — immutable after deploy
  • Automatically deducted from every payment
  • Sent to the feeRecipient address
  • If feeBasisPoints is 0, no fee is taken (merchant receives 100%)
Example: 250 basis points = 2.5% fee
On a 10 DERO payment: 0.25 DERO → fee recipient, 9.75 DERO → merchant

Security Features

The contract includes several hardened security measures:

GuardPurpose
DEROVALUE() > 0 on non-payable functionsPrevents accidental DERO trapping
feeBasisPoints <= 10000Fee cannot exceed 100%
merchant != feeRecipient (when fee > 0)Prevents misconfigured self-fee
payout > 0 / fee > 0 guardsNo zero-value transfers
paused flagMerchant can halt payments
SIGNER() checksOnly merchant can call admin functions
EXISTS("merchant")Prevents re-initialization

Payment Flow

Pay("inv_123") with DEROVALUE() = 10,000 atomic

         ├── fee = 10000 × 250 / 10000 = 250 atomic
         ├── payout = 10000 - 250 = 9750 atomic

         ├── SEND_DERO_TO_ADDRESS(merchant, 9750)
         ├── SEND_DERO_TO_ADDRESS(feeRecipient, 250)

         ├── totalProcessed += 10000
         ├── totalFees += 250
         └── paymentCount += 1

Mainnet Validation

The payment router has been deployed and tested on DERO mainnet (2026-03-03):

  • Full cycle: deploy → pay (0.1 DERO) → verify split → pay (0.05 DERO) → verify accumulation
  • All funds forwarded correctly (SC balance = 0 after each payment)
  • Fee counters accumulated as expected
  • No trapped funds

See TypeScript SDK for the programmatic interface.