This guide demonstrates how to build stablecoin on-ramp and off-ramp operations using Formance Ledger. Learn to manage the bridge between traditional banking and blockchain, handling payment authorizations, mint/burn operations, and multi-phase settlements.
What are On-Ramp and Off-Ramp Operations?
On-ramp and off-ramp operations represent the bridge between traditional fiat banking systems and blockchain-based digital assets, specifically stablecoins. These operations are fundamental to platforms that provide crypto services while maintaining fiat currency reserves.On-Ramp (Fiat to Crypto)
An on-ramp is the process where end users make a payment (card, wire transfer, etc.) to your platform, and in return receive stablecoins. Similar to payment acceptance, this involves real-time crediting based on payment authorization, followed by asynchronous settlement:- Payment Authorization: User initiates payment (card/instant payment), receives immediate confirmation
- Immediate Credit: User’s stablecoin balance credited instantly based on technical payment confirmation
- Mint Operation: Platform mints stablecoins on blockchain to back the user’s balance
- Bank Settlement: Fiat eventually settles to your bank account (T+1 to T+3 depending on payment method)
Off-Ramp (Crypto to Fiat)
An off-ramp is the reverse process where users return stablecoins to the platform and receive fiat currency:- Burn Instruction: User requests withdrawal, platform locks their stablecoins
- Burn Confirmation: Stablecoins are burned on the blockchain
- Fiat Transfer: Platform initiates bank transfer to user
- Transfer Confirmation: Bank confirms the fiat transfer completed
Key Concepts
Payment Authorization Promise Similar to card authorization in payment acceptance, real-time payment confirmation from PSPs is treated as an asset—a binding promise to settle later. Stablecoin Reserves & 1:1 Peg- Reserve Backing: Fiat held in bank accounts backing stablecoins in circulation
- 1:1 Peg: Each stablecoin represents exactly one unit of fiat currency (1 USDC = $1.00 USD)
- Minting: Creating new tokens on the blockchain when users purchase stablecoins
- Burning: Permanently destroying tokens when users redeem for fiat
- On-Ramp: Payment authorization (instant) → Mint confirmation (minutes) → Bank settlement (days)
- Off-Ramp: Burn instruction (instant) → Burn confirmation (minutes) → Fiat transfer (days)
- Mint In-Flight: Blockchain transactions submitted but not yet confirmed (awaiting block confirmations)
- Bank Settlements Pending: PSP authorization received, bank settlement T+1 to T+3
- Burn In-Flight: Burn transactions submitted but not yet on-chain
- Fiat Withdrawals Pending: Bank transfers initiated but not yet completed
- Gas Fees: Blockchain transaction costs (typically absorbed by platform)
- Payment Processing Fees: PSP/acquirer fees for fiat payments
- Transfer Fees: Bank wire transfer costs for withdrawals
Example Stablecoin Operations with Formance
Let’s work out comprehensive examples for both on-ramp and off-ramp operations.System Actors
- Payment Providers (PSPs)
- Banks
- Blockchain Networks
- End Users
- Platform
Normal Debit Accounts - Hold real-time payment promises.Similar to payment acceptance, these financial institutions provide:Examples: Stripe, Adyen, Banking Circle, Column
- Real-time card processing and instant payments
- Immediate technical confirmation
- Asynchronous settlement (T+1 to T+3)
Asset Representation
Formance uses Universal Monetary Notation (UMN) to handle the precision differences between fiat and blockchain assets:| Asset Type | UMN Format | Decimals | Example Value | Meaning |
|---|---|---|---|---|
| Fiat | USD/2 | 2 | 100000 | $1,000.00 |
| Fiat | EUR/2 | 2 | 50000 | €500.00 |
| Stablecoin | USDC/6 | 6 | 1000000000 | 1,000.00 USDC |
| Stablecoin | EURC/6 | 6 | 500000000 | 500.00 EURC |
| Native Token | ETH/18 | 18 | 1000000000000000000 | 1.0 ETH |
| Native Token | SOL/9 | 9 | 1000000000 | 1.0 SOL |
Balances & Periods
A balance of an asset in an account is the result of the sum of all incoming volumes subtracted by the sum of all outgoing volumes. For stablecoin operations, you need to track multiple temporal states across three systems:- Payment authorization: Real-time confirmation from PSP/acquirer (immediate)
- Mint in-flight: Transactions submitted to blockchain but not yet confirmed (minutes)
- Stablecoins in circulation: Confirmed on-chain supply matching user balances
- Bank settlement: Fiat actually received in bank account (T+1 to T+3)
- Burn in-flight: Burn transactions submitted but not yet confirmed
- Fiat withdrawals pending: Bank transfers initiated but not yet completed
Transaction Patterns
Below are example Numscripts that capture the intent of movements and bookings needed to handle stablecoin on-ramp and off-ramp operations. This is merely an example and your business might need different implementations, additional details, different steps and events to handle, etc…Download the T-Account Movements Excel Template to visualize all accounting entries with detailed T-account diagrams for each payment acceptance flow described in this guide.
On-Ramp Step 1: Payment Authorization and Immediate Stablecoin Credit
User initiates a payment (card, instant payment, etc.) and receives immediate technical confirmation from the payment provider. The PSP handles fiat currency (USD/2, EUR/2), which we receive as their promise. We use a platform pivot account to immediately mint/issue the equivalent stablecoin to the user for the best UX.Variables
- $fiat_asset (asset): Fiat asset in UMN (e.g., USD/2, EUR/2)
- $stable_asset (asset): Stablecoin asset in UMN (e.g., USDC/6)
- $fiat_amount (number): Payment amount in fiat
- $stable_amount (number): Equivalent stablecoin amount (accounting for decimal differences)
- $psp_id (account): Payment service provider identifier
- $client_id (account): Client account identifier
- $authorization_id (string): Payment authorization reference
Accounts Used
- @psp:$psp_id:main : PSP account holding the fiat payment promise (normal debit)
- @platform:pivot:stablecoin_issuance : Platform pivot account for fiat→stablecoin conversion
- @clients:$client_id:stablecoin : Client’s stablecoin balance (normal credit)
Numscript
Example Usage
USD card payment → USDC credit - Try in Playground →The PSP provides fiat (USD/2 or EUR/2), which flows through the platform pivot account that converts it into stablecoins for the user. The pivot account holds both the fiat receivable (from PSP) and stablecoin payable (to client), acting as the conversion point.
On-Ramp Step 2: Blockchain Mint Instruction
Platform initiates the mint transaction on the blockchain to create the stablecoins that back the user’s balance. The user already has their stablecoins from Step 1, so this is a background operation to maintain the reserve backing. We move the stablecoin obligation from the pivot account to a mint in-flight tracking account.Variables
- $stable_asset (asset): Stablecoin asset in UMN
- $stable_amount (number): Stablecoin amount to mint
- $network (account): Blockchain network identifier
- $mint_tx_hash (string): Blockchain transaction hash
- $authorization_id (string): Original payment authorization reference
Accounts Used
- @platform:pivot:stablecoin_issuance : Platform pivot account (has stablecoin overdraft from Step 1)
- @blockchain:$network:mint_in_flight : Tracking in-flight mint operations
Numscript
Example Usage
USDC mint instruction on Ethereum - Try in Playground →On-Ramp Step 3: Blockchain Mint Confirmation
Blockchain confirms the mint transaction. The stablecoins are now officially in circulation on-chain, backing the user’s balance. The in-flight mint resolves.Variables
- $stable_asset (asset): Stablecoin asset in UMN
- $stable_amount (number): Stablecoin amount minted
- $network (account): Blockchain network identifier
- $mint_tx_hash (string): Blockchain transaction hash
- $block_number (string): Block number where mint was confirmed
Accounts Used
- @blockchain:$network:mint_in_flight : In-flight mint operations
- @blockchain:$network:circulating : Confirmed on-chain supply
Numscript
Example Usage
USDC mint confirmed on Ethereum - Try in Playground →The mint is confirmed on-chain. The blockchain:circulating account now properly tracks the minted stablecoins backing user balances.
On-Ramp Step 4: PSP/Bank Settlement
The PSP/acquirer settles the fiat payment to your bank account. Similar to acquirer settlement in payment acceptance, they typically settle net amounts after deducting fees. This resolves the fiat side of the pivot account - completing the full backing cycle.Variables
- $fiat_asset (asset): Fiat asset in UMN (USD/2, EUR/2)
- $net_amount (number): Net settlement amount received
- $fee_amount (number): Fee deducted by PSP
- $psp_id (account): Payment service provider identifier
- $bank_number (account): Bank account identifier
- $settlement_ref (string): Settlement reference
Accounts Used
- @banks:$bank_number:main : Bank account receiving fiat (normal debit)
- @platform:pivot:stablecoin_issuance : Platform pivot account (clearing the fiat receivable)
- @platform:expenses:payment_fees : Platform’s payment processing fee expenses
Numscript
Example Usage
USD settlement from Stripe to bank - Try in Playground →Complete on-ramp cycle: User has stablecoins (Step 1) → Stablecoins minted on-chain (Steps 2-3) → Fiat settled to bank (Step 4). The pivot account is now balanced, with fiat in your bank backing the on-chain minted stablecoins that back the user’s balance.
Off-Ramp Step 1: Burn Instruction
User requests to withdraw fiat and return their stablecoins. Platform initiates a burn transaction on the blockchain and locks the user’s stablecoin balance.Variables
- $stable_asset (asset): Stablecoin asset in UMN
- $stable_amount (number): Stablecoin amount to burn
- $network (account): Blockchain network identifier
- $client_id (account): Client account identifier
- $burn_tx_hash (string): Blockchain transaction hash
Accounts Used
- @clients:$client_id:stablecoin : Client’s stablecoin balance
- @blockchain:$network:burn_in_flight : Tracking in-flight burn operations
Numscript
Example Usage
USDC burn instruction on Ethereum - Try in Playground →Off-Ramp Step 2: Burn Confirmation
Blockchain confirms the burn transaction. The stablecoins are permanently removed from circulation, and the corresponding fiat is released from backing reserves to pending withdrawal.Variables
- $fiat_asset (asset): Fiat asset in UMN
- $stable_asset (asset): Stablecoin asset in UMN
- $fiat_amount (number): Fiat amount to release
- $stable_amount (number): Stablecoin amount burned
- $network (account): Blockchain network identifier
- $client_id (account): Client account identifier
- $burn_tx_hash (string): Blockchain transaction hash
- $block_number (string): Block number where burn was confirmed
Accounts Used
- @blockchain:$network:burn_in_flight : In-flight burn operations
- @blockchain:$network:circulating : Confirmed on-chain supply
- @platform:reserves:backing_stablecoins : Fiat backing circulating stablecoins
- @platform:reserves:pending_withdrawal : Fiat pending withdrawal to clients
Numscript
Example Usage
USDC burn confirmed on Ethereum - Try in Playground →Off-Ramp Step 3: Fiat Withdrawal
Platform initiates bank transfer to send fiat to the client. This follows similar patterns to the payout flow in omnibus accounts.Variables
- $fiat_asset (asset): Fiat asset in UMN
- $fiat_amount (number): Fiat amount to transfer
- $bank_number (account): Bank account identifier
- $client_id (account): Client account identifier
- $transfer_ref (string): Bank transfer reference
Accounts Used
- @platform:reserves:pending_withdrawal : Fiat pending withdrawal
- @banks:transfer_ref : In-flight bank transfer
Numscript
Example Usage
USD withdrawal to bank - Try in Playground →Key Differences from Traditional Operations
Stablecoin operations combine patterns from both payment acceptance and omnibus accounts, with unique blockchain characteristics:- Triple Asynchrony
- Asset Creation vs. Movement
- Precision & Decimals
- Reserve Management
- Operational Characteristics
- Multi-Network Complexity
Unlike traditional operations with one or two timing phases, stablecoins require managing three asynchronous timelines:On-Ramp:
- Payment authorization (instant) - User charged via PSP
- Blockchain mint (minutes) - Tokens created on-chain
- Bank settlement (days) - Fiat arrives in bank
- Burn instruction (instant) - User initiates withdrawal
- Blockchain burn (minutes) - Tokens destroyed on-chain
- Fiat transfer (days) - Bank sends money to user
Advanced Ledger Features
Bi-temporality
Track payment, mint, and settlement times separately for accurate historical balance reconstruction.Use case: Generate reserve attestations showing point-in-time matching between minted supply and bank reserves.
Metadata
Store blockchain transaction hashes, block numbers, wallet addresses, and network identifiers.Use case: Enable complete audit trails and blockchain reconciliation with on-chain explorers.
Multi-Asset Support
Handle USDC, USDT, EURC, and native tokens across networks without code changes.Use case: Launch new stablecoins or expand to additional blockchains using existing Numscripts.
Event Publishing
Stream mint/burn events for real-time monitoring and integration.Use case: Trigger on-chain mints, update dashboards, or alert when reserves fall below thresholds.