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 the service account guide)
- 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
1
Clone and install
2
Set up environment variables
Copy the example environment file and fill in your values:
dfns/.env
3
Build and test
Build the Anchor program and run the test suite against a local validator:4 tests cover the full flow: initialization, FX rate setting, atomic execution, and duplicate prevention. No DFNS credentials or devnet access required.
Deploy
1
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.2
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.
3
Mint tokens to the sender
1000000000 = 1,000.000000 tokens).End-to-End Payment Flow
1
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)
2
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
3
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.
4
Verify balances
- Sender: should show reduced tEUR balance
- Receiver: should show new tSGD balance
Interactive UI
The solution includes a web UI for running the full payment flow:http://localhost:3000. The UI provides:
- 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
All amounts are in base units (6 decimals). To send 100 tokens, pass
100000000.