SettlX is a Web3 payment platform for global merchants in volatile markets like Nigeria. It lets them accept USDC and receive instant NGN settlements at a locked rate, eliminating FX risk completely.




Instant FX + Insurance for Web3 Payments | Built on Arbitrum Stylus (Rust)
SettlX is a Web3 payment settlement platform that lets global merchants accept stablecoin (USDC) payments and receive guaranteed local-currency (NGN) settlements at a locked exchange rate — eliminating FX volatility risk entirely. Smart contracts written in Rust using Arbitrum Stylus handle escrow, rate locking, and settlement on-chain.
Production: https://settl-x.vercel.app/
Network: Arbitrum Sepolia
A merchant in Lagos sells a product for $100 USDC. By the time they convert it, the FX rate has slipped — and they net only ₦138,000 instead of ₦150,000. Their margin is gone.
SettlX solves this.
When a $100 USDC payment arrives, SettlX instantly quotes the merchant a guaranteed fiat value. The merchant clicks "Lock Rate" — the exchange rate is cryptographically locked on-chain at that exact moment. The merchant receives exactly ₦150,000, regardless of what the market does next. The platform manages the FX exposure in the background.
Crypto payment margins in emerging markets are razor-thin
FX volatility between payment creation and settlement can wipe out merchant profits
No existing solution offers guaranteed, locked-rate settlement at the point of sale
Merchants have no on-chain recourse if rates shift between payment and payout
Payer → SettlX Contract → Merchant
Payer approves USDC to the contract
Payer calls payMerchant()
USDC is held in escrow
Merchant calls acceptPaymentWithRate()
Rate is locked on-chain
USDC is transferred to admin treasury
Admin calls markAsPaid() after NGN transfer
Payment status becomes Paid
Pending (0) — Payment created, awaiting merchant action
Accepted (1) — Rate locked, USDC transferred to admin
Rejected (2) — Merchant rejected, USDC refunded to payer
Paid (3) — Admin confirmed NGN bank transfer sent
The contract is written in Rust using the Arbitrum Stylus SDK and compiled to WASM for on-chain execution. This provides significantly lower gas costs compared to equivalent Solidity contracts.
A payer sends USDC to the contract, which securely holds the funds in escrow until the merchant takes action.
The merchant accepts the payment and locks the FX rate on-chain at that exact moment.
This guarantees the NGN amount they will receive, eliminating volatility risk.
If the merchant declines the transaction, funds are automatically refunded to the payer.
After sending NGN to the merchant’s bank account, the admin confirms the payout on-chain, marking the payment as fully settled.
Merchants register their bank details (stored as hashes for privacy) so off-chain NGN settlements can be executed securely.
| Event | Parameters | Description |
| --------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `MerchantRegistered` | `merchant (indexed)`, `bankName`, `accountName`, `accountNumber` | Emitted on bank detail registration. Contains plaintext strings. |
| `PaymentCreated` | `id (indexed)`, `payer (indexed)`, `merchant (indexed)`, `amount`, `rfce` | Emitted when a payment is created. Contains plaintext `rfce` reference. |
| `PaymentAccepted` | `id (indexed)`, `lockedRate` | Emitted when merchant locks rate. `lockedRate` = NGN × 10^18. |
| `PaymentRejected` | `id (indexed)` | Emitted when merchant rejects payment. |
| `PaymentMarkedAsPaid` | `id (indexed)` | Emitted when admin confirms NGN settlement. |
> **Important:** Because `rfce` and bank details are hashed on-chain, the plaintext values only exist in event logs. Frontend clients should index `PaymentCreated` and `MerchantRegistered` events to display human-readable references and bank info.Rust (stable toolchain)
cargo-stylus CLI
Arbitrum Sepolia ETH for deployment gas
Clone the repository
git clone https://github.com/Chigozie0706/SettlX
cd SettlXFor contract deployment
cd contract-stylusInstall cargo-stylus:
cargo install cargo-stylus
Add WASM target:
rustup target add wasm32-unknown-unknown
Build for Arbitrum Sepolia
cargo stylus check --endpoint https://sepolia-rollup.arbitrum.io/rpcContract Deployment:
Deploy to Arbitrum Sepolia:
cargo stylus deploy \
--endpoint='https://sepolia-rollup.arbitrum.io/rpc' \
--private-key="YOUR_PRIVATE_KEY"Initialize the contract:
cast send CONTRACT_ADDRESS \
"init(address)" \
USDC_TOKEN_ADDRESS \
--rpc-url https://sepolia-rollup.arbitrum.io/rpc \
--private-key YOUR_PRIVATE_KEYExport ABI:
cargo stylus export-abi --json > settlX.json| Contract | Network | Address |
| ------------------ | ---------------- | -------------------------------------------- |
| SettlX | Arbitrum Sepolia | `0x4855dcefa1a1ecf8b2fbd7eae38b6f73a90f48d1` |
| USDC (Test) | Arbitrum Sepolia | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` |
| Chainlink USDC/USD | Arbitrum Sepolia | `0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3` |The frontend is built with Next.js 16, Privy (wallet authentication), Wagmi v2, and Viem.
cd frontend
cd settlX
pnpm install
pnpm run devTransact page for payer approvals and payments
Merchant dashboard to view and lock FX rates
Admin dashboard for full settlement management
Plain text data such as rfce and bank details are recovered from event logs on the frontend.
| Layer | Technology |
| ------------------ | -------------------------- |
| Smart Contract | Rust + Arbitrum Stylus SDK |
| Blockchain | Arbitrum Sepolia (L2) |
| Token Standard | ERC-20 (USDC) |
| Price Oracle | Chainlink AggregatorV3 |
| Frontend Framework | Next.js 16 (App Router) |
| Wallet Auth | Privy |
| Web3 Client | Wagmi v2 + Viem |
| FX Rate API | exchangerate.host |Lower gas costs
Fast finality
Familiar Rust tooling
Strong DeFi ecosystem
MIT OR Apache-2.0
SettlX is a cross-border payment settlement protocol built on Arbitrum using Stylus (Rust smart contracts). It solves a real problem for Nigerian merchants who receive USDC payments from international customers but need to settle in NGN — without trusting a centralized exchange or intermediary.
The core flow:
Payer sends USDC to a merchant via the SettlX contract — funds enter escrow
Merchant accepts the payment and locks the current NGN/USDC exchange rate on-chain
Admin transfers the NGN equivalent to the merchant's bank account, then marks the payment as Paid on-chain
If the merchant rejects, USDC is automatically refunded to the payer
Deployed on Arbitrum Sepolia at 0x4855dcefa1a1ecf8b2fbd7eae38b6f73a90f48d1
What's complete:
Full payment lifecycle — payMerchant, acceptPaymentWithRate, rejectPayment, markAsPaid
Merchant registration — registerMerchantBankDetails, updateMerchantBankDetails
USDC escrow using ERC20 transferFrom / transfer
Exchange rate locking — NGN/USDC rate is locked at acceptance time (scaled ×1e18), preventing rate slippage between acceptance and settlement
Custom error types for every failure case (NotYourPayment, AlreadyProcessed, InvalidRate, etc.)
Payment status machine: Pending → Accepted → Paid or Pending → Rejected
Event emission for all state transitions — PaymentCreated, PaymentAccepted, PaymentRejected, PaymentMarkedAsPaid, MerchantRegistered, MerchantUpdated
Bank details stored as keccak256 hashes on-chain for privacy; plaintext recoverable only from events
Unlimited bank detail updates via erase() before set() — fixing a Stylus bytes32 overwrite limitation
Three separate dashboards, each fully functional:
Merchant Dashboard
View all incoming payments with live NGN/USD exchange rate
Accept payments (locks rate on-chain) or reject (triggers USDC refund)
Register and update bank details (collapsible update form, pre-filled with current values)
Real-time event indexing for MerchantRegistered + MerchantUpdated — always shows latest bank details
rfce (payment reference) recovered from PaymentCreated events and displayed as human-readable strings
Payer (Transact) Page
Send USDC to any registered merchant
Input payment reference (rfce), amount, and merchant address
USDC approval + payment in two steps
Admin Dashboard
View all payments across all merchants
"Mark as Paid" per payment with per-button processing state (Set-based locking — multiple buttons can process simultaneously without blocking each other)
Merchant bank details recovered from events and displayed alongside each payment
Shared technical details across all dashboards:
writeContractAsync + waitForTransactionReceipt — toasts only fire after on-chain confirmation, not on wallet popup
No hardcoded gas parameters — MetaMask estimates dynamically (fixes "max fee less than base fee" errors)
Rich toast notifications for every action with context-aware loading → waiting → success/error states
All components that need inputs are inlined in JSX (not defined as sub-components) to prevent focus loss on keystrokes
Decision | Why |
|---|---|
Stylus (Rust) over Solidity | Lower gas costs, Rust's type safety, Arbitrum-native |
Rate locked at acceptance | Protects merchant from slippage between acceptance and NGN transfer |
Bank details as hashes | Privacy — account numbers not publicly readable on-chain |
Event sourcing for plaintext | Hash stored on-chain; original string lives only in the event log |
| Stylus bytes32 slots corrupt on 3rd+ overwrite without zeroing first |
Chainlink price feed (USDC/USD) | Off-chain NGN/USD rate combined with on-chain USDC price for accurate NGN amounts |
Contract deployed and verified on Arbitrum Sepolia
Merchant can register and update bank details
Payer can send USDC and create a payment
Merchant can accept (rate locks) or reject (refund fires)
Admin can mark payments as paid
All three dashboards reflect live on-chain state via event indexing
Exchange rate pulled live from Chainlink + external FX API
Smart Contract: Rust + Arbitrum Stylus SDK
Chain: Arbitrum Sepolia (testnet)
Frontend: Next.js, TypeScript, TailwindCSS
Wallet: Privy (embedded wallet + external wallet support)
Chain interaction: Wagmi + Viem
Price data: Chainlink USDC/USD feed + exchangerate.host for NGN
Token: USDC (6 decimals)
None