Minting & Redeem
Emission and burning of Twin tokens (ARGt, BRAt, COLt, etc.) backed by fiat reserves.
Overview
Minting creates new tokens on-chain when fiat is deposited. Redeem burns tokens when fiat is withdrawn. The dashboard supports two signing paths:
| Path | Signer | Sync | Use Case |
|---|---|---|---|
| BitGo Mint | BitGo Express (custodial) | Cron MINTING_TX_SYNC | Primary operational flow |
| Wallet Mint | RainbowKit (Safe/EOA) | Manual / on-chain only | Multisig or direct wallet |
1. BitGo Mint Flow
Admin creates a mint transaction through the dashboard API. BitGo Express signs and broadcasts.
Key Details
- Coin format: Full token-qualified coin, e.g.
baseeth:argt,polygon:argt(NOT justbaseeth). - Amount: Always
"0"for contract calls (no native value transfer). - Calldata:
mint(address recipient, uint256 amount)encoded via viem. - Amounts: String-based base unit conversion. NEVER
parseFloat * Math.pow(10, decimals).
2. Wallet Mint Flow
Admin connects a wallet (Safe multisig or EOA) via RainbowKit in the dashboard frontend, signs the transaction client-side, then records it in the backend.
Safe Wallet Limitations
| Constraint | Reason |
|---|---|
No useWaitForTransactionReceipt | Safe returns safeTxHash which never appears on-chain until all signers approve |
No useSwitchChain() | Safe wallets don't support wallet_switchEthereumChain. Show an Alert asking the user to connect on the correct network |
| Cancel not supported | Wallet-mint TXs are canceled in Safe UI, not via dashboard |
3. Cron MINTING_TX_SYNC
Synchronizes BitGo-sourced transaction statuses. Runs on schedule, queries BitGo for updates.
Critical Filter
The cron only processes transactions where source = 'bitgo'. Wallet-mint transactions are excluded because BitGo has no knowledge of them.
Code
Entity Relationship Diagram
Amount Conversion
Amounts are stored and transmitted as base unit strings (e.g. "1000000" for 1 USDC with 6 decimals).
Code
Backend schemas validate with pattern: '^[0-9]+$' (digits only).
API Endpoints
| Method | Path | Description |
|---|---|---|
POST | /api/operations/minting/mint | BitGo mint (creates TX + sends to BitGo) |
POST | /api/operations/minting/wallet-mint | Record wallet-mint TX |
GET | /api/operations/minting/transaction | List transactions (paginated) |
GET | /api/operations/minting/transaction/:id | Get single transaction |
PUT | /api/operations/minting/transaction/:id/cancel | Cancel BitGo-mint only |
Route Registration Order
Static routes (/minting/wallet-mint) must be registered before parameterized routes (/minting/transaction/:id). Fastify matches in registration order.
Dashboard Frontend Components
- MintingPage (
/operations/minting): Transaction list with filters, status badges, BitGo mint dialog. - WalletMintModal: RainbowKit-connected flow. Encodes calldata, sends via connected wallet, records in backend.
- ConnectButton: Global in
top-bar.tsx, compact props. Shared with bridge flow.
RainbowKit / wagmi Stack
WagmiProvider > QueryClientProvider > Redux > ThemeProvider > RainbowKitThemeWrapperRainbowKitThemeWrappersyncs dark/light mode viauseThemeMode().VITE_WALLET_CONNECT_PROJECT_IDis embedded at build time (not runtime). Must be set as GitHub Secret for CI/CD.