Skip to content

Repository files navigation

 ██╗███╗   ██╗██╗   ██╗ ██████╗ ███████╗██╗
 ██║████╗  ██║██║   ██║██╔═══██╗██╔════╝██║
 ██║██╔██╗ ██║██║   ██║██║   ██║█████╗  ██║
 ██║██║╚██╗██║╚██╗ ██╔╝██║   ██║██╔══╝  ██║
 ██║██║ ╚████║ ╚████╔╝ ╚██████╔╝██║     ██║
 ╚═╝╚═╝  ╚═══╝  ╚═══╝   ╚═════╝ ╚═╝     ╚═╝

Decentralized Invoice Financing on Stellar Soroban

CI License: MIT Built on Stellar Soroban Next.js Supabase Live Demo

Live Demo · Docs · Contributing · Report Bug


What is InvoFi?

InvoFi is an open-source, decentralised invoice financing protocol built on Stellar Soroban. It solves a real problem: small and medium businesses often wait 30–90 days to get paid on invoices, starving them of working capital.

InvoFi lets businesses tokenise their invoices as on-chain assets and instantly receive financing from a global pool of investors. Investors earn yield. Businesses get liquidity. Everything is governed by smart contracts — no banks, no middlemen, no trust required.

Business registers invoice  →  Lenders compete with offers  →  Business accepts best offer
→  Funds available immediately  →  Business repays (full or partial)  →  Lender earns yield

Project Map

InvoFi lives across two repositories, split so the fast-moving app layer and the slow-moving, audit-bound contract layer stay decoupled:

Repo Contains Why separate
invofi (this repo) Next.js frontend (invofi/apps/frontend), docs, scripts, roadmap App-layer changes constantly; Node/npm CI; no audit dependency
invofi-contracts All Soroban Rust contracts — registry, financing, repayment, insurance, reputation, common Stable, auditable, slow-moving history; Rust-only CI; the repo that goes through the SCF Audit Bank

Smart contracts now live in a dedicated repo: invofi-contracts.


Live Demo

Frontend: invofi-five.vercel.app Contracts on Stellar Testnet (5-contract deployment):

A keeper automation (6-hourly GitHub Action) scans testnet, bumps contract-data TTLs, and marks past-due Financed invoices Overdue — see invofi/scripts/keeper.ts.

Deploy your own via the Deploy Contracts to Testnet workflow in invofi-contracts and set the three NEXT_PUBLIC_*_CONTRACT_ID variables in Vercel. Without a contract configured the app runs in alpha mode (off-chain only).

git clone https://github.com/Stellar-VaultLink/invofi.git
cd invofi/apps/frontend
cp .env.local.example .env.local   # fill in Supabase + contract values
npm install && npm run dev
# → http://localhost:3000

Key Features

For Businesses

  • Register invoices on-chain in under 60 seconds
  • Receive competing financing offers from a global investor pool
  • Accept the best offer and get immediate liquidity
  • Full and partial repayment tracked on-chain
  • No bank account or credit history needed — your invoice is the collateral

For Lenders / Investors

  • Browse a marketplace of verified on-chain invoices
  • Submit financing offers with custom interest rates and duration
  • Track active investments and yields in a live portfolio
  • Transparent partial repayment history on the Stellar blockchain
  • Receive a SEP-41 position token (POS) for every accepted offer and transfer your position to another wallet from your portfolio (Task 8)
  • Stake into the insurance coverage pool to back the protocol (Task 9) — and get payout on default up to the pool's balance (Task 10)
  • Screen borrowers by on-chain reputation score — one default outweighs two repayments (Task 11)

Protocol Properties

  • Trustless — all terms, state transitions, and repayments enforced by Soroban smart contracts
  • Transparent — every action is a public transaction on Stellar, auditable by anyone
  • Permissionless — anyone with a Stellar wallet can participate
  • Dual auth — email/password (Supabase) and Stellar wallet (Freighter or Lobstr)
  • Multi-currency — invoices denominated in XLM or USDC
  • Partial repayment — businesses can repay incrementally; offer stays Financed until fully cleared
  • Free to deploy — Vercel (free) + Supabase (free) + Stellar testnet

Architecture

┌────────────────────────────────────────────────────────────────────────────┐
│                              Browser (User)                                │
│                Next.js 14 App Router — deployed on Vercel                  │
│                                                                            │
│   ┌──────────────────────┐   ┌─────────────────────────────────────────┐   │
│   │ Email / Password auth │   │  Stellar wallet: Freighter / LOBSTR    │   │
│   │ via Supabase          │   │  @creit.tech/stellar-wallets-kit      │   │
│   │                       │   │  approved-wallets.ts allowlist (6A)    │   │
│   └──────────┬───────────┘   └─────────────────────┬───────────────────┘   │
└──────────────┼──────────────────────────────────────┼──────────────────────┘
               │                                      │ signs Soroban txs
               ▼                                      ▼
┌──────────────────────────┐   ┌──────────────────────────────────────────────┐
│          Supabase         │   │              @invofi/sdk (Task 15)           │
│   auth + app mirror +     │   │   typed contract client — apps/sdk          │
│   protocol_stats (T13)    │   └──────────────────────┬───────────────────────┘
└─────────────┬────────────┘                          │
              │                                       ▼
              │                 ┌─────────────────────────────────────────────────┐
              │                 │        Stellar Soroban — 6-contract system       │
              │                 │                                                 │
              │                 │   registry ──► financing ──► repayment           │
              │                 │      ▲            │  ▲          │                │
              │                 │      └────────────┼──┴──────────┘                │
              │                 │        insurance ─┘  └── reputation              │
              │                 │   position token (POS, SEP-41) minted on         │
              │                 │   accept_offer; restricted cross-contract auth   │
              │                 └─────────────────────┬───────────────────────────┘
              │                                       │ protocol events (RPC)
              ▼                                       ▼
┌──────────────────────────┐   ┌──────────────────────────────────────────────┐
│    /stats page (T14)      │◄──│  indexer (T13) — 6-hourly GitHub Action      │
│  reads protocol_stats     │   │  checkpointed event replay → protocol_stats  │
└──────────────────────────┘   └──────────────────────────────────────────────┘

keeper (T12) — 6-hourly GitHub Action: mark_overdue + TTL bumps (Soroban RPC)

No always-on backend server to manage. 100% free hosting.


Project Structure

invofi/
├── invofi/apps/
│   └── frontend/                     Next.js 14 web application
│       └── src/
│           ├── app/
│           │   ├── page.tsx          Landing page
│           │   ├── layout.tsx        Root layout + providers
│           │   ├── dashboard/        Business invoice dashboard
│           │   ├── invoices/         Create and view invoices
│           │   ├── marketplace/      Lender invoice browser
│           │   ├── portfolio/        Lender investment tracker
│           │   ├── profile/          User profile + display name
│           │   └── settings/         Account settings
│           ├── components/
│           │   ├── auth/             AuthGuard, WalletButton, WalletProvider,
│           │   │                     WalletSelectDialog (Freighter + Lobstr picker)
│           │   ├── common/           ConfirmDialog, StatsCard, StatsGrid,
│           │   │                     StatusBadge, PageHeader, EmptyState
│           │   ├── invoices/         InvoiceCard, InvoiceForm, InvoiceTable,
│           │   │                     OfferList
│           │   ├── layout/           Navbar (dark mode + a11y), Footer
│           │   └── ui/               shadcn/ui — button, dialog, table,
│           │                         badge, card, input, tabs, toast...
│           ├── hooks/                useInvoices, useOffers, useMarketplace,
│           │                         useLocalStorage, useDebounce, useMediaQuery
│           └── lib/
│               ├── contract.ts       Soroban contract call helpers (3 contracts)
│               ├── approved-wallets.ts  Approved-wallet allowlist (extension point)
│               ├── walletkit.ts      stellar-wallets-kit init + active-wallet signing
│               ├── horizon.ts        Stellar Horizon API helpers
│               ├── supabase.ts       Auth + database helpers
│               ├── formatters.ts     Amount, date, address formatters
│               ├── csv.ts            CSV export helpers
│               └── constants.ts      Network config, risk tiers, enums
├── scripts/
│   └── close-issues.sh              Bulk GitHub issue close
├── docs/
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
└── LICENSE

Smart Contract Reference

Contracts: invofi-registry, invofi-financing, invofi-repayment, invofi-insurance, invofi-reputation + the SEP-41 position token · live in invofi-contracts. The authoritative, always-current function reference and ADRs live in that repo — the summary below is a condensed overview of the protocol surface and may lag the contracts repo.

Invoice Fields

Field Type Description
id Symbol Unique invoice identifier
originator Address Stellar address of the business
amount i128 Invoice amount in stroops (10,000,000 stroops = 1 unit)
currency Symbol XLM or USDC
due_date u64 Unix timestamp of payment due date
status InvoiceStatus Pending → Financed → Repaid / Overdue / Cancelled / Disputed / Defaulted

FinancingOffer Fields

Field Type Description
id Symbol Unique offer identifier
invoice_id Symbol Invoice this offer targets
lender Address Stellar address of the investor
amount i128 Offer amount in stroops
currency Symbol XLM or USDC
interest_rate u32 Basis points (500 = 5.00%)
duration u64 Financing duration in seconds
amount_repaid i128 Running total of stroops repaid so far
status OfferStatus Pending → Accepted → Financed → Repaid / Rejected / Defaulted
funded_at u64 Unix timestamp when offer was accepted

Contract Functions

Function Auth Description
__constructor(admin, …) Deployer (at deploy) One-time setup runs atomically inside the deploy operation — no front-runnable initialize() (ADR-0005)
register_invoice(id, originator, amount, currency, due_date) Originator Register a new invoice; validates amount > 0 and due_date > now
get_invoice(id) Anyone Read invoice state
update_invoice_status(id, status) Admin / system Status transition helper (registry); cross-contract system transitions are caller-guarded
create_offer(offer_id, invoice_id, lender, amount, currency, rate, duration) Lender Submit a financing offer; validates amount > 0, rate > 0
get_offer(id) Anyone Read offer state
accept_offer(offer_id, originator) Business Accept offer → pulls lender's principal via prior token.approve, pays business; invoice → Financed
reject_offer(offer_id, originator) Business Reject a pending offer
repay_invoice(invoice_id, offer_id, repayer, amount) Business Pay amount stroops toward the outstanding balance. Offer stays Financed until amount_repaid >= principal + yield; then → Repaid
mark_overdue(invoice_id) Anyone Mark a past-due Financed invoice as Overdue
reclaim_invoice(invoice_id, offer_id, lender) Lender After 7-day grace period on Overdue invoice, marks offer Defaulted
get_invoices_by_status(status) Anyone Return all invoices matching a given InvoiceStatus
set_rate(admin, tier, rate_bps) Admin Set yield rate for risk tier A/B/C
get_rate(tier) Anyone Read the configured rate for a risk tier
transfer_admin(admin, new_admin) Admin Rotate the admin address
get_admin() Anyone Read the admin address
get_currency_token(currency) Anyone Read the settlement token for a currency (financing)
get_position_token() Anyone Read the configured SEP-41 position-token contract (financing)
raise_dispute(invoice_id, originator) Originator Mark a Financed invoice as Disputed
resolve_dispute(admin, invoice_id, target_status) Admin Resolve a Disputed invoice to a new status
get_lender_stats(lender) Anyone Return aggregated stats for a lender address
get_invoices_count() Anyone Total number of registered invoices
get_offers_count() Anyone Total number of financing offers
get_offers_by_status(status) Anyone Return all offers matching a given status
get_invoices_by_currency(currency) Anyone Return invoices denominated in a specific asset
get_invoices_due_before(timestamp) Anyone Return invoices due before a Unix timestamp
get_invoices_paginated(offset, limit) Anyone Page through all invoices
get_offers_paginated(offset, limit) Anyone Page through all offers
batch_get_invoices(ids) Anyone Fetch multiple invoices by ID in one call
version() Anyone Return the contract semver string

Protocol Events

Every state-mutating function publishes a Soroban contract event, so indexers and UIs can track protocol activity without polling. Topics are (event_name, subject_id) — filter by invoice/offer id without decoding payloads.

Event Emitted by Data
inv_reg register_invoice (originator, amount, due_date)
off_new create_offer (invoice_id, lender, amount, interest_rate)
off_acc accept_offer (invoice_id, lender, amount)
off_rej reject_offer invoice_id
off_wdr withdraw_offer lender
off_def reclaim_invoice (invoice_id, lender)
inv_rep repay_invoice (offer_id, amount, fully_repaid)
inv_ovd mark_overdue due_date
inv_cxl cancel_invoice originator
inv_dsp raise_dispute originator
inv_rsl resolve_dispute new_status

Invoice Lifecycle

register_invoice()
      │
      ▼
  [Pending] ────────────────────────────────────── reject_offer() ──► stays Pending
      │
  accept_offer() ── pays principal to business
      │
      ▼
  [Financed] ◄──────────────────────────────────── repay_invoice() (partial)
      │
      ├── repay_invoice() (balance cleared) ──────► [Repaid]
      │
      ├── mark_overdue() ────────────────────────► [Overdue]
      │                                                │
      │                                           reclaim_invoice()
      │                                           (after 7-day grace,
      │                                            keeper or lender)
      │                                                │
      │                                                ▼
      │                                    invoice → [Defaulted]  ◄── insurance
      │                                    offer  → [Defaulted]      pay_out +
      │                                                               reputation
      │                                                               recorded
      │
      └── raise_dispute() (originator) ──────────► [Disputed]
                                                       │
                                                   resolve_dispute() (admin)
                                                       │
                                                       ├──► [Financed]   (dispute withdrawn)
                                                       └──► [Cancelled]  (dispute upheld)

Tech Stack

Layer Technology Why
Smart Contracts Rust + Soroban SDK 22 Native Stellar contract platform
Frontend Next.js 14 (App Router) + TypeScript 5.5 Free Vercel deployment, SSR
Styling Tailwind CSS + shadcn/ui Fast, accessible, composable
Auth Supabase Free tier, row-level security
Wallet Freighter + LOBSTR (approved allowlist) via @creit.tech/stellar-wallets-kit Approving a 3rd wallet = one entry in approved-wallets.ts
Data Fetching TanStack Query v5 Caching, background refetch
Forms React Hook Form + Zod Type-safe validation
Icons Lucide React Consistent icon set
Stellar SDK @stellar/stellar-sdk v16 Contract calls, Horizon queries

Getting Started

Prerequisites

1. Clone

git clone https://github.com/Stellar-VaultLink/invofi.git
cd invofi

2. Set up Supabase

  1. Create a project at supabase.com.
  2. Run the schema below in SQL Editor.
  3. Copy your Project URL and Anon Key from Settings → API.

3. Configure environment

cd invofi/apps/frontend
cp .env.local.example .env.local
# Fill in NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_*_CONTRACT_ID

4. Run the frontend

npm install && npm run dev
# → http://localhost:3000

5. Build and test contracts

Contracts live in the dedicated invofi-contracts repo:

git clone https://github.com/Stellar-VaultLink/invofi-contracts.git
cd invofi-contracts
cargo test          # 110+ tests across all five crates
stellar contract build

6. Deploy contract to testnet

Use the one-click Deploy Contract GitHub Actions workflow in invofi-contracts (.github/workflows/deploy-contract.yml), or follow the deploy steps in its README.

After deploying, copy the three printed contract IDs into NEXT_PUBLIC_REGISTRY_CONTRACT_ID, NEXT_PUBLIC_FINANCING_CONTRACT_ID, and NEXT_PUBLIC_REPAYMENT_CONTRACT_ID in your .env.local or Vercel dashboard, then call initialize() on each contract once (the workflow does this automatically).


Supabase Setup

create table user_profiles (
  id uuid primary key references auth.users(id),
  email text not null,
  role text not null check (role in ('business', 'lender')),
  display_name text,
  wallet_address text,
  created_at timestamptz default now()
);

create table invoices (
  id text primary key,
  originator text not null,
  originator_id uuid references auth.users(id),
  amount text not null,
  currency text not null,
  due_date timestamptz not null,
  status text not null default 'Pending',
  created_at timestamptz default now()
);

create table financing_offers (
  id text primary key,
  invoice_id text references invoices(id),
  lender_id uuid references auth.users(id),
  lender text not null,
  amount text not null,
  currency text not null,
  interest_rate integer not null,
  duration integer not null,
  amount_repaid text not null default '0',
  status text not null default 'Pending',
  funded_at integer default 0,
  created_at timestamptz default now()
);

alter table user_profiles enable row level security;
alter table invoices enable row level security;
alter table financing_offers enable row level security;

create policy "Anyone can read invoices" on invoices for select using (true);
create policy "Owner can insert invoices" on invoices for insert with check (originator_id = auth.uid());
create policy "Owner can update invoices" on invoices for update using (originator_id = auth.uid());

create policy "Anyone can read offers" on financing_offers for select using (true);
create policy "Lender can insert offers" on financing_offers for insert with check (lender_id = auth.uid());
create policy "Parties can update offers" on financing_offers for update
  using (lender_id = auth.uid() or
    exists (select 1 from invoices where id = invoice_id and originator_id = auth.uid()));

create policy "Own profile" on user_profiles for all using (id = auth.uid());

Deployment (Vercel)

  1. Push fork to GitHub.
  2. Vercel → New Project → import → set Root Directory to invofi/apps/frontend.
  3. Add environment variables:
Variable Value
NEXT_PUBLIC_SUPABASE_URL Your Supabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY Your Supabase anon key
NEXT_PUBLIC_REGISTRY_CONTRACT_ID Output from stellar contract deploy (registry)
NEXT_PUBLIC_FINANCING_CONTRACT_ID Output from stellar contract deploy (financing)
NEXT_PUBLIC_REPAYMENT_CONTRACT_ID Output from stellar contract deploy (repayment)
NEXT_PUBLIC_STELLAR_NETWORK testnet
NEXT_PUBLIC_RPC_URL https://soroban-testnet.stellar.org
NEXT_PUBLIC_HORIZON_URL https://horizon-testnet.stellar.org

Roadmap

  • Core invoice registry contract (register, offer, accept, reject, repay, overdue, reclaim)
  • Partial repayment — amount_repaid tracking, offer stays Financed until balance cleared
  • Query helpers — get_invoices_by_status, get_invoices_by_currency, get_invoices_due_before, pagination, batch queries
  • Dispute lifecycle — raise_dispute / resolve_dispute with admin resolution
  • Lender stats — get_lender_stats tracking total offered, accepted, pending, repaid
  • Input validation — amount >= MIN_INVOICE_AMOUNT, due_date > now, interest_rate > 0, duration <= MAX_OFFER_DURATION_SECS
  • Next.js 14 frontend with multi-wallet support (Freighter + LOBSTR via @creit.tech/stellar-wallets-kit)
  • Alpha / demo mode — app runs fully off-chain when no contract is deployed; shows info banner
  • Supabase auth (email + wallet), dark mode, accessibility, SEO metadata
  • Marketplace and portfolio views, sortable InvoiceTable, StatsCard KPIs
  • Profile page, ConfirmDialog, EmptyState, LoadingSkeleton components
  • One-click Testnet deploy via GitHub Actions workflow
  • Protocol events (v0.3) — every state transition published on-chain for indexers and activity feeds
  • Marketplace sorting (newest, amount, due date) and Stellar Expert explorer links
  • Insurance coverage pool with payout on default (Tasks 9–10)
  • On-chain reputation scoring for originators (Task 11)
  • Keeper automation — 6-hourly TTL bump + overdue marking (Task 12)
  • SEP-41 token movement — accept_offer funds the business, repay_invoice repays principal + yield (Tasks 1–2)
  • Split into 5 auditable contract crates — registry / financing / repayment / insurance / reputation (Tasks 4–5)
  • Emergency pause / circuit breaker — admin-gated pause on every state-mutating function (Task 4A)
  • Event indexer + public /stats page — aggregates protocol activity (Tasks 13–14)
  • @invofi/sdk — shared typed contract client consumed by the frontend (Task 15)
  • Architecture Decision Records — ADR index in both repos (Task 16)
  • Deployer-bound initialization — __constructor on all contracts, no front-runnable initialize() (issue #75)
  • Compliance posture documented — KYC/SEP-12 roadmap, jurisdictions, securities-by-design (Task 17)
  • Mainnet deployment
  • Oracle-based invoice verification and risk scoring
  • Multi-signature treasury and escrow
  • KYC / AML with SEP-12 support
  • Contract upgradeability with timelock governance

Maintainers

@samjay8
@samjay8

Project maintainer & protocol owner

Contributors

Thanks to everyone who has contributed to InvoFi — the list below is generated automatically from the GitHub API whenever code lands on main. No action needed on your part after a merged PR.

samjay8
Samuel Ojetunde
Damieee
Oluwadamilare E

Contributing

Read CONTRIBUTING.md before opening a pull request. For bugs and features, use GitHub Issues.

Security

Do not open a public issue for security vulnerabilities. See SECURITY.md for responsible disclosure.

Compliance

See docs/compliance.md for the KYC/SEP-12 roadmap, jurisdictions avoided at launch, and the design analysis of why the current offer/lender flows are not structured as securities.

License

MIT © 2026 InvoFi Contributors. See LICENSE.

About

Decentralized invoice financing protocol on Stellar Soroban

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages