Build a cross-border payment system on Solana where stablecoins are atomically swapped between currencies — burning the source token and minting the target token in a single transaction.All signing is handled by Dfns wallets. Private keys never leave the Dfns KMS infrastructure, even as the system deploys programs, creates token mints, and executes payments on-chain.
A fintech company operates a remittance corridor between Europe and Southeast Asia. A customer in Paris wants to send EUR to a recipient in Singapore.The flow:
The bank initiates a payment on-chain, locking in the sender, receiver, and EUR amount.
An FX provider quotes the EUR/SGD rate and records the SGD output amount on the payment.
The bank executes the swap — the Solana program atomically burns tEUR from the sender and mints tSGD to the receiver. If either operation fails, nothing happens.
The on-chain program enforces that minted tokens can only go to the receiver specified during initialization. This prevents any redirection after the payment is created.
The system implements a three-step state machine stored in a Program Derived Address (PDA):
Copy
Ask AI
PendingFX --> FXRateSet --> Completed
Each payment creates a unique PDA seeded by ["payment", sender, payment_id]. This ensures every payment has its own on-chain record and prevents collisions.
The system uses standard SPL tokens with 6 decimals as stablecoins. Each token is deployed with Metaplex metadata (name, symbol) so it displays correctly in explorers and wallets. The bank’s Dfns wallet is the mint authority for both tokens.
git clone https://github.com/dfns/dfns-solutions.gitcd dfns-solutions/cross-border-payments-solana# Install Solana CLI, Anchor, and Node dependencies./setup.sh# Or if you already have the toolchain:npm install
Fill in dfns/.env with your Dfns credentials and the bank wallet ID:
Copy
Ask AI
DFNS_API_URL=https://api.dfns.ioDFNS_ORG_ID=or-...DFNS_AUTH_TOKEN=eyJ...DFNS_CRED_ID=Y2...DFNS_PRIVATE_KEY=-----BEGIN EC PRIVATE KEY-----\n...\n-----END EC PRIVATE KEY-----BANK_WALLET_ID=wa-...# Set after deploying (steps 5 and 6)SOURCE_MINT=TARGET_MINT=PROGRAM_ID=CEMoNh21BbxrVdPM6N9xwpqFHD8dxAFkBscZqPEdfrbe
An 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:
Copy
Ask AI
npm run set-fx-rate -- 1 <SENDER_ADDRESS> 800000
800000 — the exact output amount in target token base units
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
The UI calls the same functions as the CLI scripts — it’s a thin Express server (dfns/server.ts) serving a single HTML file (dfns/ui.html) with API endpoints that delegate to the shared payment logic.
The execute_payment instruction performs two CPIs in sequence:
Burn — calls token::burn on the source mint, debiting the sender’s token account
Mint — calls token::mint_to on the target mint, crediting the receiver’s token account
Both happen in the same Solana transaction. If the burn succeeds but the mint fails, the entire transaction reverts — no tokens are lost.The mint CPI uses the Payment PDA as the signing authority. This means the target mint’s authority must be set to the PDA (or in this demo, the bank wallet acts as both sender and mint authority).
cross-border-payments-solana/ programs/cross-border-payment/ src/lib.rs Anchor program -- 3 instructions + state dfns/ DfnsClient.ts Dfns SDK setup, env config, exports broadcast.ts Shared helper to serialize + broadcast via Dfns deploy-program.ts Deploy/upgrade the Anchor program binary deploy-stablecoin.ts Deploy SPL token mints with Metaplex metadata init-payment.ts Initialize a payment PDA set-fx-rate.ts Set the FX conversion rate execute-payment.ts Execute the atomic burn/mint swap mint-tokens.ts Mint tokens to any address server.ts Express API server for the web UI ui.html Interactive web UI (single file, no build step) tests/ cross-border-payment.ts Full Anchor test suite (4 tests) setup.sh One-command toolchain installer