hackquest logo

SettlX

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.

ビデオ

プロジェクト画像 1
プロジェクト画像 2
プロジェクト画像 3
プロジェクト画像 4

テックスタック

Next
Web3
Rust
Node

説明

SettlX — De-risked Merchant Settlements

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.

Overview

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.

The Problem

  • 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

How It Works

Payer → SettlX Contract → Merchant

  1. Payer approves USDC to the contract

  2. Payer calls payMerchant()

  3. USDC is held in escrow

  4. Merchant calls acceptPaymentWithRate()

  5. Rate is locked on-chain

  6. USDC is transferred to admin treasury

  7. Admin calls markAsPaid() after NGN transfer

  8. Payment status becomes Paid

Payment Lifecycle

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


Smart Contract Architecture

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.

Core Smart Contract Capabilities

1. Create Payment (Escrow)

A payer sends USDC to the contract, which securely holds the funds in escrow until the merchant takes action.

2. Lock Exchange Rate

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.

3. Reject & Refund

If the merchant declines the transaction, funds are automatically refunded to the payer.

4. Confirm Settlement

After sending NGN to the merchant’s bank account, the admin confirms the payout on-chain, marking the payment as fully settled.

5. Merchant Bank Registration

Merchants register their bank details (stored as hashes for privacy) so off-chain NGN settlements can be executed securely.

Events

| 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.

Getting Started

Contract:

Prerequisites

  • Rust (stable toolchain)

  • cargo-stylus CLI

  • Arbitrum Sepolia ETH for deployment gas

Installation

  1. Clone the repository

git clone https://github.com/Chigozie0706/SettlX
cd SettlX
  1. For contract deployment

cd contract-stylus
  • Install 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/rpc
  • Contract Deployment:

  1. Deploy to Arbitrum Sepolia:

cargo stylus deploy \
  --endpoint='https://sepolia-rollup.arbitrum.io/rpc' \
  --private-key="YOUR_PRIVATE_KEY"
  1. Initialize the contract:

cast send CONTRACT_ADDRESS \
  "init(address)" \
  USDC_TOKEN_ADDRESS \
  --rpc-url https://sepolia-rollup.arbitrum.io/rpc \
  --private-key YOUR_PRIVATE_KEY
  1. Export ABI:

    cargo stylus export-abi --json > settlX.json

Deployed Contracts (Testnet)

| Contract           | Network          | Address                                      |
| ------------------ | ---------------- | -------------------------------------------- |
| SettlX             | Arbitrum Sepolia | `0x4855dcefa1a1ecf8b2fbd7eae38b6f73a90f48d1` |
| USDC (Test)        | Arbitrum Sepolia | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` |
| Chainlink USDC/USD | Arbitrum Sepolia | `0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3` |

FRONTEND:

The frontend is built with Next.js 16, Privy (wallet authentication), Wagmi v2, and Viem.

cd frontend
cd settlX
pnpm install
pnpm run dev

Key Frontend Features

  • Transact 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.

Tech Stack

| 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          |

Why Arbitrum Stylus?

  • Lower gas costs

  • Fast finality

  • Familiar Rust tooling

  • Strong DeFi ecosystem

License

MIT OR Apache-2.0

ハッカソンの進行状況

SettlX — Progress Summary

What We're Building

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:

  1. Payer sends USDC to a merchant via the SettlX contract — funds enter escrow

  2. Merchant accepts the payment and locks the current NGN/USDC exchange rate on-chain

  3. Admin transfers the NGN equivalent to the merchant's bank account, then marks the payment as Paid on-chain

  4. If the merchant rejects, USDC is automatically refunded to the payer

Smart Contract (Stylus / Rust)

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

Frontend (Next.js + Wagmi + Privy)

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

Key Technical Decisions

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

erase() before set() for updates

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

What's Working End-to-End

  • 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

Stack

  • 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

チームリーダー
CChigozie Jacob
プロジェクトリンク
エコシステムをデプロイ
ArbitrumArbitrum
業界
DeFi