Skip to content
big14wayPublic

About

Invoice financing for African traders: global investors fund verified invoices in USDG/USDC on Arbitrum and Robinhood Chain.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

EarnX

Get paid when you ship, not when your buyer pays.

EarnX turns a verified export invoice into cash for an African exporter today. Investors anywhere fund it in Paxos USDG (or Circle USDC) and earn the yield when the buyer pays. Everything that moves money is enforced by smart contracts on Robinhood Chain and Arbitrum.

Live app → earnx-app.vercel.app · Contracts · Robinhood Chain protocol · Arbitrum Sepolia protocol


For judges: the five-minute tour

Live app earnx-app.vercel.app (Robinhood Chain testnet by default; switch to Arbitrum in the header)
One invoice, every step on-chain Invoice #19 on Robinhood Chain: submitted by a passkey account → verified, priced by the Stylus engine, record minted → buyer confirmed (signed statement on IPFS) → funded, exporter paid in the same transaction → repaid by the buyer → claimed by the investor
Contracts Deployments, source-verified on Blockscout · Solidity · Rust risk engine
Tests 29 Foundry tests including fuzzing, 6 Rust tests, run in CI on every push
Sponsor technology Where each one is used
Demo video On the HackQuest project page; its script and every transaction it shows are in docs/video

The problem

A confirmed export order is not cash. An exporter pays farmers, processors and freight up front, then waits weeks or months for the buyer to pay. Banks rarely lend against those invoices, so good orders are turned down, or sold to middlemen at a discount.

  • $74–92 billion of trade finance requested by African businesses went unmet in 2024 (African Development Bank).
  • 37% of trade finance applications from African firms were rejected between 2020 and 2024 (same source).
  • Africa's factoring market was about €50 billion in 2024; Afreximbank estimates it must reach €240 billion to close the SME gap (Afreximbank via GTR).

Why I'm building EarnX

Mama Dora on her farm

My mother, Mama Dora, is a farmer in Delta State, Nigeria. She grows cassava and other crops, and for as long as I can remember her harvest has paid for everything in our home.

Then my father had a stroke. The hospital needed money that week. Like most Nigerian families, we had no health insurance: of every ₦1,000 spent on healthcare in Nigeria, about ₦720 comes straight out of a family's own pocket (World Bank).

It happened just after harvest, when a farmer has the most to show and the least cash in hand. What money she had went to the farmhands who had helped bring the crop in, and it still wasn't enough to pay them all. The harvest was worth far more than the hospital bill, but it wasn't money yet.

So we did what farming families across Africa do. We sold part of the crop cheaply, just to get cash quickly, and we went to the bank. Between the fees and the interest rate, the loan cost far more than we could carry, and it bankrupted us.

I built EarnX so that the value of work already done reaches people when they need it, at a fair price. We start with African exporters, whose invoices we can verify on-chain today. Every invoice we fund is a family that doesn't have to choose between the harvest and the hospital.

— Godswill Idolor, founder, and son of a Delta State farmer


What EarnX does

For exporters

  • Sign in with a fingerprint or Face ID (a passkey smart account). No wallet app, no seed phrase, and network fees are sponsored.
  • Upload the invoice and shipping documents. They go to IPFS; their fingerprint goes on-chain.
  • Once verified and fully funded, up to 90% of the invoice lands in your account in the same transaction.
  • Every verified invoice mints a non-transferable record to you: an on-chain trade history that belongs to you, not to a bank's filing cabinet.

For investors

  • Browse real invoices with their terms, risk score and documents, without connecting a wallet.
  • Fund any amount from 1 USDG. When the buyer pays, claim your share of principal plus yield.
  • Check for yourself that an invoice's documents still match what the verifier reviewed: the app hashes them in your browser and compares with the chain.

How it works

sequenceDiagram
    autonumber
    actor E as Exporter (passkey)
    participant S as Pre-screen (/api/verify)
    participant C as Buyer confirmation (/api/confirm)
    participant P as EarnXProtocol
    participant R as Risk engine (Stylus)
    actor B as Buyer
    actor I as Investors
    E->>P: submitInvoice(amount, due date, buyer, docs CID + hash)
    E->>S: run the pre-screen
    S->>S: documents match the hash · quantity × price = total<br/>World Bank price · no duplicate on either chain · exporter's limit
    opt invoice above $1,000
        B->>C: sign the statement built from the on-chain facts
        C-->>S: signed statement on IPFS
    end
    S->>P: verifyInvoice(risk score), or rejectInvoice(reason)
    P->>R: quote(risk score, tenor, amount)
    R-->>P: APR + advance
    P-->>E: soulbound record NFT minted
    I->>P: invest(USDG)
    P-->>E: advance paid in the transaction that completes funding (1% to the reserve)
    B->>P: repay(amount), in parts or in full
    I->>P: claim() pro-rata principal + yield
    Note over P: Past due + grace period: anyone can markDefault.<br/>The first-loss reserve covers investor principal, and recoveries refill it.
Loading

Invoice lifecycle, enforced by EarnXProtocol:

stateDiagram-v2
    [*] --> Submitted: submitInvoice
    Submitted --> Funding: verifyInvoice / verifyInvoiceWithSig
    Submitted --> Rejected: rejectInvoice
    Submitted --> Cancelled: cancelInvoice
    Funding --> Funded: invest reaches the target, exporter paid
    Funding --> Cancelled: cancelInvoice (refunds investors)
    Funded --> Repaid: repay in full
    Funded --> Defaulted: markDefault after due date + grace
    Defaulted --> Defaulted: repay (recoveries)
Loading

Pricing is computed on-chain by the Rust engine from a published formula, so nobody, including EarnX, can override it:

  • APR = 8% + 0.15% per risk point + 0.01% per 3 days of term beyond 30 + 0.25% above $50k or 0.5% above $100k, kept between 5% and 50%.
  • Advance = 90% − 0.25% per risk point above 30 − 5% for terms over 120 days, kept between 70% and 90%.
  • Risk scores above 80 cannot be funded.

Who stands behind an invoice

Exporter not verified Business verified
Approved automatically up to $1,000 per invoice $250,000 per invoice
Buyer confirmation Optional, shown to investors Required above $1,000
Effect on the risk score −5, and −5 more once the buyer confirms

What keeps it honest

  • Short and self-liquidating. Each advance is tied to one shipment and repaid when that buyer pays. Terms are capped at 365 days on-chain.
  • First-loss reserve. 1% of every advance, plus any capital partners add, covers investor principal before investors lose anything. It can only be used for that.
  • Documents you can check. Each invoice stores the keccak256 of a manifest listing every document and its own hash. A verifier signature is bound to that exact hash.
  • Know who stands behind it. Exporters who haven't verified their business are approved automatically only up to $1,000 per invoice. Verification is an on-chain registry (VERIFIED_EXPORTER_ROLE on the protocol), granted after a reviewer checks the business against its national registry; the request is encrypted before it is stored.
  • The buyer confirms the debt. Above $1,000 the buyer must sign a statement built from the invoice's on-chain facts: they ordered the goods, the invoice is genuine, and they will pay the EarnX contract. Wallet and passkey signatures (ERC-1271 / ERC-6492) are checked and the signed statement is pinned to IPFS for anyone to re-check. A confirmed buyer or a verified business also lowers the risk score, and so the price.
  • No double financing. The pre-screen rejects an invoice that reuses any document, the same bundle, or the same invoice number for the same buyer on either chain.
  • Over-invoicing is caught. Unit prices are compared with World Bank commodity benchmarks; far above market is rejected.
  • No hidden levers. The admin can pause new activity and allow-list stablecoins. It cannot move investor funds.

Try it

  1. Open earnx-app.vercel.app and pick a network (Robinhood Chain or Arbitrum).
  2. Browse Invest. Invoices marked sample are fictional and seeded for the demo; invoice #6 on each chain has already gone through the whole cycle to Repaid.
  3. To fund one, get testnet ETH (Robinhood, Arbitrum) and test USDG or USDC, connect a wallet and invest from 1 USDG.
  4. To see the exporter side, go to Get paid early, sign in with a passkey or wallet, upload a PDF and submit. The automated pre-screen checks the documents and opens the invoice for funding within seconds.

Deployments

Network EarnXProtocol EarnXInvoiceNFT Settlement
Robinhood Chain testnet (46630) 0xA7fC55ca10c05aA2a0e0Cef5e00f15B08Caf4a99 0x7c2e27323578C67B4c2E847024D80091586503d6 Paxos USDG
Arbitrum Sepolia (421614) 0x0D0C0eE2a93D4E6d912da43810Ca8f327BDc7341 0xc9A10EDA07ea8D90dB95254540efb7F00907f888 Paxos USDG, Circle USDC

Rust risk engine (Stylus): Robinhood Chain 0x454aeA0eDA332a09FFc61C5799B336AEa24Cd863 · Arbitrum Sepolia 0xb78d4d4FDCBd5e2E73405091138B08bd1707d551

The Solidity contracts are source-verified on Blockscout.

Architecture

flowchart LR
    subgraph web["Web app · React + Vite"]
        UI["Exporter · buyer · investor pages"]
    end
    subgraph acct["Accounts"]
        PK["Passkey smart account<br/>ZeroDev Kernel v3.1 · ERC-4337"]
        WL["Browser wallet<br/>wagmi + RainbowKit"]
    end
    subgraph api["Serverless functions · Vercel"]
        UP["/api/upload"]
        VF["/api/verify · pre-screen"]
        CF["/api/confirm · buyer statements"]
        KY["/api/kyb · encrypted requests"]
        RP["/api/rpc · read-only proxy"]
    end
    subgraph chain["Robinhood Chain testnet · Arbitrum Sepolia"]
        P["EarnXProtocol<br/>Solidity · OpenZeppelin 5.7"]
        RE["Risk engine<br/>Rust on Arbitrum Stylus"]
        NFT["EarnXInvoiceNFT<br/>ERC-5192 soulbound"]
        TK[("Paxos USDG · Circle USDC")]
    end
    IP[("IPFS via Pinata")]
    AL[("Alchemy")]
    WB[("World Bank Pink Sheet")]
    UI --> PK & WL
    PK -- "sponsored user operations" --> P
    WL -- "transactions" --> P
    UI --> UP & VF & CF & KY & RP
    UP --> IP
    CF --> IP
    KY -- "AES-256-GCM" --> IP
    VF -- "VERIFIER_ROLE key" --> P
    VF -. "documents" .-> IP
    VF -. "benchmarks" .-> WB
    RP --> AL --> P
    P -- "quote()" --> RE
    P -- "mint, status" --> NFT
    P <-->|"stablecoins in and out"| TK
Loading
Part What it is
contracts/ Foundry project. EarnXProtocol (lifecycle, pricing, reserve) and EarnXInvoiceNFT (ERC-5192 soulbound records with on-chain SVG metadata). OpenZeppelin 5.7: AccessControl, SafeERC20, ReentrancyGuard, Pausable, EIP-712, Nonces. 29 tests including fuzz tests; CI on every push.
contracts/stylus/risk-engine Rust risk engine on Arbitrum Stylus. Prices every invoice on-chain from a published formula: APR = 8% + 0.15% per risk point + term and size premiums; advance = 90%, reduced for higher risk and long terms. No storage, no owner; 4.3 KB of WASM with Rust unit tests.
app/ Vite + React + TypeScript, wagmi + RainbowKit for wallets, ZeroDev Kernel v3.1 for passkey accounts with sponsored gas, Tailwind. ABIs and addresses are generated from contracts/ so the app cannot drift from the chain.
app/api/upload Serverless function that pins documents to IPFS through Pinata and returns the manifest CID and hash. The Pinata key never reaches the browser.
app/api/verify Automated pre-screen for the testnet: re-fetches the documents from IPFS, checks them against the on-chain hash, the market price and every invoice on both chains for duplicates, applies the business-verification limit and buyer-confirmation rule, then verifies or rejects the invoice with a key that holds VERIFIER_ROLE and nothing else.
app/api/confirm Buyer confirmation: serves the statement for an invoice, checks the buyer's signature (EOA, ERC-1271 or ERC-6492) and pins the signed statement to IPFS, indexed by invoice.
app/api/kyb Business verification requests, encrypted with AES-256-GCM before they are pinned. app/scripts/kyb-requests.mjs decrypts them for the reviewer and prints the on-chain command that records the result.
contracts/              Foundry project: EarnXProtocol, EarnXInvoiceNFT, tests, deploy and seed scripts
contracts/stylus/       Rust risk engine for Arbitrum Stylus
app/                    React app
app/api/                Serverless functions: upload, verify, confirm, kyb, rpc, prices
app/scripts/            Contract sync, World Bank benchmark sync, business-verification review
docs/video/             The pitch video's script, recorder config and the transactions it shows

Sponsor technology

Technology How EarnX uses it Where
Robinhood Chain Main deployment; the app's default network contracts/deployments/46630.json
Paxos USDG The settlement stablecoin on both chains: investments, payouts, repayments, claims contracts/deployments/
Arbitrum Stylus The risk engine that prices every invoice, written in Rust contracts/stylus/risk-engine
ZeroDev Passkey smart accounts and the paymaster that sponsors exporters' gas app/src/lib/passkey.ts
OpenZeppelin AccessControl, SafeERC20, ReentrancyGuard, Pausable, EIP-712, Nonces contracts/src
Alchemy RPC for the app (behind a read-only proxy) and for the serverless functions app/api/rpc.ts, app/src/lib/serverRpc.ts

Why Robinhood Chain and Arbitrum. Both are Arbitrum chains with low fees and fast blocks. Robinhood Chain is built for real-world assets and has USDG natively; Arbitrum has deep stablecoin liquidity and native USDC. The same contracts run on both.

Built during the Arbitrum Open House Singapore buildathon

Everything before the buildathon is tagged pre-buildathon (an earlier Mantle Sepolia version). See every change since → EarnX also had an earlier Arbitrum prototype, entered in Arbitrum Open House NYC from a separate codebase; none of that code is in this repository.

During the buildathon we:

  • rewrote the contracts from scratch: the previous contract accepted deposits but had no payout, repayment or claim path, and approved every invoice automatically;
  • added the first-loss reserve, EIP-712 verifier signatures bound to document hashes, and soulbound trade records;
  • wrote a risk engine in Rust on Arbitrum Stylus that prices every new invoice on-chain, and plugged it into the protocol on both chains;
  • wrote the test suite and CI, then deployed and verified on Robinhood Chain testnet and Arbitrum Sepolia with Paxos USDG;
  • rebuilt the app around live on-chain data (the old one showed hardcoded figures), added passkey accounts with sponsored gas, IPFS uploads and the automated verifier;
  • added the trust layer: tiered limits from an on-chain business-verification registry, signed buyer confirmations, a cross-chain duplicate check, and a World Bank market-price check;
  • removed hardcoded credentials and the unused Morph/Mantle-era code.

Security and limitations

  • Testnet only. The contracts are not audited. Do not use real funds.
  • Verification is the trust point. On the testnet an automated pre-screen approves small invoices from unverified exporters and larger ones only with a verified business and the buyer's signature. Business checks are manual today; before mainnet they move to a licensed identity partner, and buyer contacts are verified independently of the exporter (today a buyer is whoever holds the account that signs). The contract already accepts any approved verifier, including signed approvals from off-chain reviewers.
  • Repayment depends on the buyer. The reserve softens defaults but cannot remove them. Default rates and reserve levels are shown publicly in the app.

Run it locally

git clone --recurse-submodules https://github.com/big14way/earnx.git && cd earnx

# contracts (needs Foundry)
cd contracts && forge test && cd ..

# app
cd app && npm install && cp .env.example .env.local   # add a Reown project ID (and ZeroDev for passkeys)
npm run dev

Deployment scripts and the sample-invoice seeder are documented in contracts/README.md.

License

MIT

About

Invoice financing for African traders: global investors fund verified invoices in USDG/USDC on Arbitrum and Robinhood Chain.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages