Skip to content
Β 
Β 

Latest commit

Β 

History

324 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

StellarUrithi-Bidz πŸ”¨

On-Chain Auction Protocol for African Art & Cultural Artifacts on Stellar

License: MIT Stellar Rust


Overview

StellarUrithi-Bidz is an open-source, on-chain auction protocol purpose-built for African art and cultural artifacts. Whether digital (NFTs) or physical (custodian-attested), every item is auctioned transparently on Stellar with escrowed bids and automatic royalty distribution.

Key Features

  • Three Auction Formats: English (ascending), Dutch (descending), and Sealed-Bid (commit-reveal)
  • On-Chain Escrow: All bids are locked in the contract until auction resolution β€” trustless and transparent
  • Automatic Royalties: Original creators receive their royalty on every hammer sale β€” no manual intervention
  • Physical-Item Bridge: Custodians/galleries attest to physical item possession before an auction opens
  • Real-Time Updates: WebSocket-powered live bid feed and auction state changes
  • Low Fees: Settled on Stellar for sub-second, near-zero-fee finality

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        FRONTEND (Next.js 14)                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Auctions β”‚  β”‚  Create  β”‚  β”‚  My Bids  β”‚  β”‚  Admin Panel  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                         β”‚ Freighter Wallet                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  BACKEND INDEXER (Node.js)                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ Event Indexerβ”‚  β”‚  WebSocket   β”‚  β”‚    REST API         β”‚   β”‚
β”‚  β”‚ (Soroban RPC)β”‚  β”‚  (Socket.IO) β”‚  β”‚  (Express)          β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚         β”‚                 β”‚                      β”‚               β”‚
β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
β”‚                           β”‚ PostgreSQL                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   STELLAR SOROBAN                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                 UrithiAuction Contract                     β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚
β”‚  β”‚  β”‚ English  β”‚  β”‚  Dutch   β”‚  β”‚ Sealed-Bid β”‚  β”‚ Escrow  β”‚ β”‚  β”‚
β”‚  β”‚  β”‚  Module  β”‚  β”‚  Module  β”‚  β”‚   Module   β”‚  β”‚ Module  β”‚ β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚
β”‚  β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                        β”‚  β”‚
β”‚  β”‚                    β”‚Royalty Split β”‚                        β”‚  β”‚
β”‚  β”‚                    β”‚   Module     β”‚                        β”‚  β”‚
β”‚  β”‚                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    CUSTODIAN PORTAL (Next.js)                     β”‚
β”‚  Physical-item attestation β€” upload IPFS docs, verify possession β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

StellarUrithi-Bidz/
β”œβ”€β”€ contracts/                    # Soroban Smart Contracts (Rust)
β”‚   β”œβ”€β”€ Cargo.toml               # Workspace root
β”‚   └── auction/
β”‚       β”œβ”€β”€ Cargo.toml
β”‚       └── src/
β”‚           β”œβ”€β”€ lib.rs           # Contract entry point
β”‚           β”œβ”€β”€ types.rs         # Data structures & enums
β”‚           β”œβ”€β”€ english.rs       # English auction logic
β”‚           β”œβ”€β”€ dutch.rs         # Dutch auction logic
β”‚           β”œβ”€β”€ sealed_bid.rs    # Sealed-bid logic
β”‚           β”œβ”€β”€ escrow.rs        # Fund locking & refunds
β”‚           β”œβ”€β”€ royalty.rs       # Royalty calculation & distribution
β”‚           β”œβ”€β”€ events.rs        # Event emission helpers
β”‚           └── test.rs          # Comprehensive test suite
β”‚
β”œβ”€β”€ backend/                     # Indexer & API Server
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ tsconfig.json
β”‚   └── src/
β”‚       β”œβ”€β”€ index.ts             # Main entry point
β”‚       β”œβ”€β”€ db/
β”‚       β”‚   └── index.ts         # PostgreSQL connection & queries
β”‚       β”œβ”€β”€ indexer/
β”‚       β”‚   └── event_indexer.ts # Stellar event poller
β”‚       β”œβ”€β”€ ws/
β”‚       β”‚   └── socket_server.ts # WebSocket manager
β”‚       β”œβ”€β”€ routes/
β”‚       β”‚   └── auctions.ts      # REST API endpoints
β”‚       └── services/
β”‚           └── logger.ts        # Winston logger
β”‚
β”œβ”€β”€ frontend/                    # Main Web Application
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ next.config.js
β”‚   β”œβ”€β”€ tailwind.config.ts
β”‚   β”œβ”€β”€ tsconfig.json
β”‚   └── src/
β”‚       β”œβ”€β”€ app/
β”‚       β”‚   β”œβ”€β”€ layout.tsx       # Root layout
β”‚       β”‚   β”œβ”€β”€ page.tsx         # Home β€” auction listings
β”‚       β”‚   β”œβ”€β”€ globals.css      # Global styles
β”‚       β”‚   β”œβ”€β”€ auctions/[id]/   # Auction detail page
β”‚       β”‚   β”œβ”€β”€ create/          # Create auction page
β”‚       β”‚   β”œβ”€β”€ my-bids/         # Bid history page
β”‚       β”‚   └── admin/           # Admin panel
β”‚       β”œβ”€β”€ components/
β”‚       β”‚   β”œβ”€β”€ auction/
β”‚       β”‚   β”‚   └── AuctionCard.tsx
β”‚       β”‚   └── layout/
β”‚       β”‚       β”œβ”€β”€ Navbar.tsx
β”‚       β”‚       └── Footer.tsx
β”‚       β”œβ”€β”€ hooks/
β”‚       β”‚   └── useWebSocket.ts  # Real-time update hooks
β”‚       β”œβ”€β”€ lib/
β”‚       β”‚   β”œβ”€β”€ api.ts           # Backend API client
β”‚       β”‚   └── stellar.ts       # Stellar/Soroban helpers
β”‚       └── providers/
β”‚           └── wallet.tsx       # Freighter wallet provider
β”‚
β”œβ”€β”€ custodian-portal/            # Custodian Admin App
β”‚   β”œβ”€β”€ package.json
β”‚   └── src/
β”‚       └── app/
β”‚           β”œβ”€β”€ layout.tsx
β”‚           β”œβ”€β”€ globals.css
β”‚           └── page.tsx         # Attestation dashboard
β”‚
└── README.md

Getting Started

Prerequisites

  • Docker & Docker Compose (for one-command local dev)
  • Rust (1.75+) with wasm32-unknown-unknown target (for contracts)
  • Soroban CLI (>= 22.0.0): cargo install soroban-cli
  • jq (JSON processor): brew install jq or apt install jq
  • Node.js 18+ (if running services directly)
  • Freighter Wallet browser extension
  • Pinata account (for IPFS storage)

Docker Quick Start (recommended)

One command starts the full stack β€” PostgreSQL, backend, frontend, and custodian portal:

# Start all services
docker compose up --build

# Start in detached mode
docker compose up --build -d

# View logs
docker compose logs -f

# Stop everything
docker compose down

# Stop and remove volumes (resets database)
docker compose down -v

After startup:

Note: Set CONTRACT_ID and PINATA_JWT in a .env file (or export them) before starting. The compose file reads them via ${CONTRACT_ID} and ${PINATA_JWT}.

1. Smart Contracts

Quick Deploy (recommended)

# Interactive deployment wizard β€” guides you through everything
./deploy.sh

# Or use the Makefile directly
make all

Both will: check prerequisites β†’ build β†’ test β†’ deploy to testnet β†’ initialize β†’ verify.

Manual Steps

cd contracts

# Build contracts
make build-release

# Run tests
make test

# Generate identity & fund (testnet)
make keys   # generates 'alice' identity
make fund   # funds via Friendbot

# Optimize WASM
make optimize

# Deploy to Stellar testnet
make deploy-testnet

# Initialize the contract
make initialize

# Verify deployment
make verify

Available Make Targets

Target Description
make help Show all targets and variables
make build Compile debug
make build-release Compile release (optimized)
make test Run all tests
make test-verbose Run tests with full output
make optimize Strip & optimize WASM
make keys Generate testnet identity
make fund Fund via Friendbot
make deploy-testnet Deploy to testnet
make deploy-mainnet Deploy to mainnet ⚠️
make initialize Initialize contract on-chain
make verify Query contract state
make verify-events Check emitted events
make demo Run end-to-end demo
make lint Clippy lint
make fmt Format code
make clean Remove build artifacts
make all Full pipeline

2. Backend Indexer

cd backend

# Install dependencies
npm install

# Set environment variables
cp .env.example .env
# Edit .env with your Postgres credentials and contract ID

# Start the indexer and API server
npm run dev

3. Frontend

cd frontend

# Install dependencies
npm install

# Set environment variables
cp .env.example .env.local

# Start the development server
npm run dev

Visit http://localhost:3000 β€” connect your Freighter wallet and start bidding!

4. Custodian Portal

cd custodian-portal

npm install
npm run dev

Visit http://localhost:3001


Environment Variables

Backend (backend/.env.example)

PORT=4000
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=stellar_urithi_bidz
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
STELLAR_RPC_URL=https://soroban-testnet.stellar.org
CONTRACT_ID=<deployed_contract_address>
FRONTEND_URL=http://localhost:3000

Frontend (frontend/.env.example)

NEXT_PUBLIC_CONTRACT_ID=<deployed_contract_address>
NEXT_PUBLIC_STELLAR_NETWORK=testnet
NEXT_PUBLIC_API_URL=http://localhost:4000
NEXT_PUBLIC_WS_URL=http://localhost:4000
NEXT_PUBLIC_PINATA_GATEWAY=https://gateway.pinata.cloud

Auction Formats

Format How It Works Best For
English Ascending bids. Highest bidder wins when timer expires. Popular, well-known format.
Dutch Price drops over time. First to "buy now" wins instantly. Quick sales, price discovery.
Sealed-Bid Bids are hidden (commit-reveal). Highest valid bid revealed at close. High-value items, privacy-sensitive.

Royalty Flow

Every hammer sale automatically distributes proceeds:

Winning Bid (100%)
β”œβ”€β”€ Seller receives   (net after fees)
β”œβ”€β”€ Creator royalty   (royalty_bps / 10000 Γ— bid)
└── Platform fee      (platform_fee_bps / 10000 Γ— bid)

Example: 1000 XLM bid with 5% royalty (500 bps) and 2.5% platform fee (250 bps):

  • Seller: 925 XLM
  • Creator: 50 XLM
  • Platform: 25 XLM

Physical Item Bridge

For physical artifacts, the flow includes a custodian attestation step:

  1. Seller lists item with item_type: Physical and assigns a custodian address
  2. Custodian inspects the physical item, uploads documentation (photos, condition report) to IPFS
  3. Custodian calls attest_physical_item on the contract with the IPFS hash
  4. Auction activates β€” bidding begins

This ensures physical items are verified by a trusted third party before funds are committed.


License

MIT Β© StellarUrithi-Bidz Contributors

Built with ❀️ for African art and culture. Powered by Stellar.

About

Urithi Auctions is an on-chain auction protocol for African art and cultural artifacts, built on Stellar.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages