Get the code
dfns/dfns-solutions — cross-border-payments-solana
Bank
Deploys stablecoins and the payment program, mints tokens, and executes settlements
FX Provider
Quotes the exchange rate and records the converted amount on-chain
Receiver
Receives funds in the destination currency (e.g., tSGD)
- The Bank initiates a payment, specifying the receiver and amount in tEUR
- The FX Provider sets the conversion rate (how much tSGD the receiver gets)
- The Bank executes the payment — tEUR is burned from the sender and tSGD is minted to the receiver
Prerequisites
- Clone the cross-border-payments-solana solution
- Create a Dfns organization if you don’t have one already, and note the organization ID
- Create a service account for API access (see how to create one here)
- Create 2 wallets: Bank and Receiver on Solana Devnet
- Fund the Bank wallet with devnet SOL for transaction fees (
solana airdrop 2 <BANK_WALLET_ADDRESS> --url devnet) - Make sure you have installed Node.js v18+, Rust, and Cargo
- Install Solana CLI and Anchor (v0.32+) — the included
setup.shscript can install these
Project Structure
Configuration
Set up environment variables
Copy the example environment file and fill in your values:
dfns/.env
| Variable | Description |
|---|---|
DFNS_API_URL | Dfns API base URL (https://api.dfns.io) |
DFNS_ORG_ID | Your organization ID |
DFNS_AUTH_TOKEN | Service account auth token |
DFNS_CRED_ID | Credential ID for the signing key (found in Settings > Service Accounts) |
DFNS_PRIVATE_KEY | Private key for request signing (PEM format) |
BANK_WALLET_ID | Wallet ID for the bank (wa-xxxx...) |
SOURCE_MINT | Source stablecoin mint address (set after deploying stablecoins) |
TARGET_MINT | Target stablecoin mint address (set after deploying stablecoins) |
PROGRAM_ID | Anchor program ID (set after deploying, or use the default) |
Deploy
Deploy stablecoins
Deploy two SPL token mints that represent the source and target currencies. The bank’s Dfns wallet becomes the mint authority.Each command prints the mint address. Copy both into your
dfns/.env as SOURCE_MINT and TARGET_MINT.Deploy the program
Upload the compiled Anchor program to Solana Devnet. The Dfns wallet is used as the payer and upgrade authority.The upgrade authority stays in the Dfns KMS, meaning future upgrades also go through Dfns.
End-to-End Payment Flow
Initialize a payment
Create a payment record on-chain. This stores the sender, receiver, and input amount in a PDA.
1— payment ID (unique per sender)500000— amount in base units (0.5 tokens)
Set the FX rate
The FX provider locks in the conversion rate. In this demo, any signer can call
set_fx_rate — a production system should restrict this to authorized accounts.For example, converting 0.5 tEUR at a rate of 1.6x gives 0.8 tSGD:800000— the exact output amount in target token base units
Execute the payment
Trigger the atomic swap. The program burns the source tokens from the sender and mints the target tokens to the receiver:The script automatically creates the receiver’s token account if it doesn’t exist yet.
Interactive UI
The solution includes a web UI for running the full payment flow:- A three-step form to initialize a payment, set the FX rate, and execute the swap
- A flow visualization showing the current payment status (PendingFX → FXRateSet → Completed)
- Live balances for sender and receiver (source tokens, target tokens, SOL)
- Solana Explorer links for every transaction
CLI Reference
| Script | Usage | Description |
|---|---|---|
npm run deploy:stablecoin | -- <name> <symbol> | Deploy an SPL token mint with Metaplex metadata |
npm run deploy:program | [buffer_address] | Deploy or upgrade the Anchor program via Dfns |
npm run mint-tokens | -- <mint> <recipient> <amount> | Mint tokens to an address |
npm run init-payment | -- <id> <receiver> <amount> | Initialize a payment PDA on-chain |
npm run set-fx-rate | -- <id> <sender> <amount_out> | Lock in the FX conversion rate |
npm run execute-payment | -- <id> | Execute the atomic burn/mint swap |
npm run ui | Start the interactive web UI on port 3000 |
100000000.
