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
| Function | Who Can Call | Description |
|---|---|---|
Initialize | Deployer | Set up merchant, fee recipient, and fee rate |
Pay | Anyone | Send DERO through the router (splits to merchant + fee recipient) |
UpdateMerchant | Merchant | Change the merchant address |
Pause | Merchant | Stop accepting payments |
Resume | Merchant | Resume accepting payments |
WithdrawTrapped | Merchant | Recover any DERO accidentally trapped in the contract |
GetStats | Anyone | Returns 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
feeRecipientaddress - If
feeBasisPointsis 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 → merchantSecurity Features
The contract includes several hardened security measures:
| Guard | Purpose |
|---|---|
DEROVALUE() > 0 on non-payable functions | Prevents accidental DERO trapping |
feeBasisPoints <= 10000 | Fee cannot exceed 100% |
merchant != feeRecipient (when fee > 0) | Prevents misconfigured self-fee |
payout > 0 / fee > 0 guards | No zero-value transfers |
paused flag | Merchant can halt payments |
SIGNER() checks | Only 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 += 1Mainnet 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.