Skip to content

About

E-commerce platform showcasing Stellar/Soroban blockchain payments - USDC checkout, escrow contracts, and Freighter wallet integration

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Β 
Β 

Latest commit

Β 

History

165 Commits

Folders and files

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

Repository files navigation

ShoeSafari β€” Online Footwear Store on Stellar

A real, operating footwear store β€” not a demo β€” with Stellar USDC checkout

CI License: MIT Next.js Stellar PRs Welcome Security

ShoeSafari is a live online footwear store that sells products and accepts USDC payments on the Stellar network. The store has processed more than $10,000 USDC in product sales on Stellar. Customers can browse footwear, place orders, and pay from their own Freighter wallet.

This is not a demo or mock storefront. ShoeSafari sells real products to customers and processes real USDC product payments on Stellar.

ShoeSafari's storefront and Stellar integration are open source. The live store has processed more than $10,000 USDC in product sales on Stellar. Developers can study and improve the commerce implementation. Testnet instructions in this repository are for development only; never use production funds while testing.


Deep Stellar Integration

The full design rationale β€” escrow, multi-token support, event indexing, and pre-flight fee simulation β€” lives in docs/ARCHITECTURE.md.

In short, payments are non-custodial and refundable:

buyer ──pay──▢ contract (escrow) ──dispatch──▢ merchant
                     β”‚
                     └──refund──▢ buyer (on-chain)
  • Order registry on-chain β€” every order records { buyer, amount, token, timestamp, status } and transitions Pending β†’ Paid β†’ Shipped/Refunded.
  • Multi-token β€” any SEP-41 token the merchant whitelists (add_token): USDC and native XLM out of the box.
  • Escrow β€” funds stay in the contract until the merchant dispatches, or go straight back to the buyer on refund.
  • Real-time indexing β€” the storefront polls getEvents (cursor-paginated) and decodes pay/dispatch/refund events live (lib/stellar/indexer.ts).
  • Pre-flight simulation β€” every payment is simulated first so resource fees are reported and failures are caught before the buyer signs (lib/stellar/simulate.ts).
  • Readiness checks β€” account funding, trustline, and token balance are all verified before building the transaction (lib/stellar/account.ts).

Table of Contents


Highlights

  • Next.js 14 App Router + Tailwind CSS storefront (catalog, cart, checkout, admin, blog).
  • Soroban checkout with escrow β€” a Rust smart contract moves USDC (or native XLM) from the buyer's wallet into an on-chain escrow, records the order, and releases it to the merchant on dispatch or refunds it on-chain.
  • Freighter wallet integration with network guard, pre-flight simulation, readiness checks, real-time getEvents indexing, and an explorer link on success.
  • Testnet development flow β€” brand-new accounts can be funded via friendbot, so testing takes under a minute.
  • Testnet USDC + native XLM (Stellar Asset Contract) are available for development and contract testing. Testnet is separate from live purchases.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Storefront (Next.js / React / Tailwind)                          β”‚
β”‚                                                                   β”‚
β”‚  app/checkout/page.tsx                                            β”‚
β”‚    β”œβ”€ components/StellarCheckoutButton.jsx  "Pay with USDC"       β”‚
β”‚    β”œβ”€ components/StellarOrderWatch.jsx      live event monitor    β”‚
β”‚    └─ lib/stellar/                                              β”‚
β”‚         β”œβ”€ checkout.ts          payment flow                      β”‚
β”‚         β”œβ”€ account.ts           trustline / balance / friendbot   β”‚
β”‚         β”œβ”€ simulate.ts          pre-flight fee simulation         β”‚
β”‚         β”œβ”€ indexer.ts           getEvents cursor listener         β”‚
β”‚         β”œβ”€ freighter.ts         wallet connect/sign               β”‚
β”‚         β”œβ”€ scval.ts             ScVal builders                    β”‚
β”‚         └─ events.ts            event decoding                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚  invokeHostFunction(pay) via RPC
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  contracts/checkout  (Rust Β· Soroban SDK 27)                      β”‚
β”‚                                                                   β”‚
β”‚  order registry: order_id -> Order {buyer, amount, token, status} β”‚
β”‚  pay(token, buyer, order_id, amount)   buyer β†’ escrow (contract)  β”‚
β”‚  dispatch(order_id)                    escrow β†’ merchant          β”‚
β”‚  refund(order_id)                      escrow β†’ buyer             β”‚
β”‚  add_token / remove_token              SEP-41 whitelist           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚  SEP-41 transfer + contract events
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Stellar network (testnet / mainnet)                              β”‚
β”‚  Ledger stores PaymentReceived / OrderShipped / OrderRefunded     β”‚
β”‚  Stellar Asset Contracts: USDC + native XLM                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The pay function

Param Type Meaning
token Address Whitelisted SEP-41 token (USDC SAC or native XLM SAC)
buyer Address The paying wallet (must authorize)
order_id BytesN<32> 32-byte unique order identifier
amount i128 Raw token units (USDC = 7 decimals)

pay escrows amount from buyer into the contract, marks the order Paid, and emits a PaymentReceived event:

topics: ["pay", token, buyer, merchant, order_id]
data:   { amount }

The merchant then calls dispatch(order_id) to release the escrow (emits dispatch) or refund(order_id) to return it to the buyer (emits refund). The storefront decodes these events live and from confirmed transactions to display receipts and finish orders.

Full design decisions, the escrow model, and how the pieces fit together: docs/ARCHITECTURE.md.

Repository Layout

A clean split between frontend, contracts, and config:

shoesafari/
β”œβ”€β”€ app/                            # Frontend β€” Next.js App Router
β”‚   β”œβ”€β”€ (landingpage)/              #   landing sections (Hero, Stellar, AboutUs…)
β”‚   β”œβ”€β”€ checkout/page.tsx           #   checkout with the Stellar/USDC stage
β”‚   β”œβ”€β”€ shop/                       #   product catalog + product details
β”‚   β”œβ”€β”€ collections/                #   collections listing
β”‚   β”œβ”€β”€ admin/                      #   admin product management
β”‚   └── profile/login/              #   authentication
β”œβ”€β”€ components/                     # Shared UI (Stellar checkout/wallet buttons, Toast…)
β”œβ”€β”€ lib/                            # Client-side libraries
β”‚   β”œβ”€β”€ stellar/                    #   Soroban payment library
β”‚   β”‚   β”œβ”€β”€ config.ts               #     network / contract / token config
β”‚   β”‚   β”œβ”€β”€ freighter.ts            #     wallet connect / signing
β”‚   β”‚   β”œβ”€β”€ scval.ts                #     ScVal builders + decoders
β”‚   β”‚   β”œβ”€β”€ checkout.ts             #     payWithStellar() payment flow
β”‚   β”‚   β”œβ”€β”€ account.ts              #     trustline / balance / friendbot
β”‚   β”‚   β”œβ”€β”€ simulate.ts             #     pre-flight resource-fee simulation
β”‚   β”‚   β”œβ”€β”€ indexer.ts              #     getEvents cursor listener
β”‚   β”‚   └── events.ts               #     contract event decoding
β”‚   └── AuthContext.jsx             #   auth + cart context
β”œβ”€β”€ contracts/
β”‚   └── checkout/                   # Contracts β€” Rust Soroban smart contract
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ lib.rs              #   entry points (initialize, pay, dispatch, refund…)
β”‚       β”‚   β”œβ”€β”€ order.rs            #   Order struct + status lifecycle
β”‚       β”‚   β”œβ”€β”€ storage.rs          #   persistent storage + TTL management
β”‚       β”‚   β”œβ”€β”€ events.rs           #   PaymentReceived / OrderShipped / OrderRefunded…
β”‚       β”‚   β”œβ”€β”€ errors.rs           #   typed error codes
β”‚       β”‚   └── test.rs             #   mock-token + native-asset integration tests
β”‚       β”œβ”€β”€ Cargo.toml
β”‚       └── README.md               #   contract interface + manual CLI examples
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ ARCHITECTURE.md             # Deep Stellar integration design rationale
β”‚   └── STELLAR_API.md              # Exported helper API reference
β”œβ”€β”€ scripts/
β”‚   └── deploy-testnet.sh           # one-command build + deploy + initialize
β”œβ”€β”€ public/                         # Static assets (product images)
β”œβ”€β”€ .env.local.example              # Config β€” environment variable template
β”œβ”€β”€ package.json                    # Frontend dependencies + scripts
└── LICENSE

Tech Stack

Layer Technology
Frontend Next.js 14 (App Router), React, Tailwind CSS, Firebase
Payments @stellar/stellar-sdk 16, @stellar/freighter-api 6
Smart chain Rust, Soroban SDK 27, Stellar CLI
Currency USDC + native XLM via the Stellar Asset Contract (7 decimals)

Prerequisites

Install the following before getting started:

Tool Version / Notes Install
Node.js 18.18+ (bundles npm) https://nodejs.org
Rust stable, with the wasm32v1-none target `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs
Stellar CLI latest (stellar --version) brew install stellar-cli or via cargo/docs
Freighter browser wallet extension (Chrome / Firefox) https://freighter.app

Rust note: a C toolchain/LLVM is required to compile the Soroban contract. On macOS install Xcode Command Line Tools (xcode-select --install).

Verify your setup:

node --version      # v18.18+ or newer
cargo --version     # 1.7x+
stellar --version   # latest

Getting Started

1. Clone the repository

git clone https://github.com/ShoeSafari-Org/ShoeSafari.git
cd ShoeSafari

2. Install dependencies

npm install

3. Configure environment variables

Copy the template and fill in your values:

cp .env.local.example .env.local

A minimal Stellar-only configuration (the rest of the app runs with the existing Firebase/Mongo values you already use):

# --- Stellar / Soroban payments ---
NEXT_PUBLIC_STELLAR_NETWORK=testnet
# NEXT_PUBLIC_STELLAR_RPC_URL=https://soroban-testnet.stellar.org
# NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015

# Deployed checkout contract id (see "Smart Contract Deployment" below)
NEXT_PUBLIC_CHECKOUT_CONTRACT_ID=

# USDC token contract (testnet default; set for mainnet)
# NEXT_PUBLIC_USDC_CONTRACT_ID=CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA

# Display-only: the merchant wallet that receives USDC payments.
# The authoritative value lives on-chain, set during contract initialize.
# PUBLIC_MERCHANT_ADDRESS=

4. Run the local dev server

npm run dev

Open http://localhost:3000 β€” you should land on the storefront home page. To see the Stellar checkout, add an item to your cart and visit the checkout page.

Until you deploy the contract (next section), NEXT_PUBLIC_CHECKOUT_CONTRACT_ID is empty and the Stellar payment stage stays disabled β€” that's expected.

Smart Contract Deployment (Testnet)

The checkout contract lives in contracts/checkout/. Deploying it is a four-part pipeline: build β†’ test β†’ deploy β†’ initialize.

Step 1 β€” Build the contract

cd contracts/checkout

# Install the Soroban wasm target (one time)
rustup target add wasm32v1-none

# Build the optimized release wasm
stellar contract build

stellar contract build compiles with Cargo and optimizes the wasm by default. The artifact is written to contracts/checkout/target/wasm32v1-none/release/shoesafari_checkout.wasm.

Alternatively, the manual Cargo route (optimize with a newer CLI's stellar contract build --optimize, or the legacy stellar contract optimize --wasm <file> --out <file>):

cd contracts/checkout
cargo build --target wasm32v1-none --release

Step 2 β€” Test the contract

The test suite uses a self-contained mock token plus the real Stellar Asset Contract for native XLM, so no deployment or network access is needed:

cd contracts/checkout
cargo test

Expected output includes the full order lifecycle β€” escrow + dispatch, refund, native-XLM payments, token whitelist, duplicate-order, not-initialized, zero-amount, double-init, and merchant-change cases.

Step 3 β€” Set up a testnet identity

Generate a funded keypair that the Stellar CLI will use as the deployer:

# Back at the repo root
stellar keys generate alice --network testnet --fund

alice is the default identity used by scripts/deploy-testnet.sh and by the examples below. Swap the name/flag to match your own keyring.

Step 4 β€” Deploy to testnet

stellar contract deploy \
  --wasm contracts/checkout/target/wasm32v1-none/release/shoesafari_checkout.wasm \
  --source-account alice \
  --network testnet

The command prints a contract id:

Contract: CBL2LFZKZJ4DHANUKYQXHFTTBFEUQ3QYIG4M5CLVND6FRRQTJTY4Q7WG

Save it β€” you'll need it for the next two steps.

Step 5 β€” Initialize with your merchant wallet

The contract requires a one-time initialize call that sets the merchant wallet receiving every future payment. The merchant address must authorize the transaction, so this must be the merchant's own account:

stellar contract invoke \
  --id <CONTRACT_ID> \
  --source-account alice \
  --network testnet \
  -- \
  initialize \
  --merchant G...YOUR_MERCHANT_ADDRESS...

Verify it took effect:

stellar contract invoke --id <CONTRACT_ID> --network testnet -- merchant

Expected output is the merchant address you just set. An order cannot be paid before this step succeeds.

Warning: the merchant address you pass here authorizes every release from escrow. Triple-check it before submitting on mainnet. This store ships un-initialized on purpose so each team authorizes its own merchant.

Step 5b β€” Whitelist the tokens you accept

Funds can only be escrowed with tokens the merchant has approved. Add USDC and native XLM (testnet values):

stellar contract invoke --id <CONTRACT_ID> --source-account alice --network testnet -- \
  add_token --token CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA

stellar contract invoke --id <CONTRACT_ID> --source-account alice --network testnet -- \
  add_token --token CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC

Verify with stellar contract invoke --id <CONTRACT_ID> --network testnet -- is_token_allowed --token <TOKEN>.

Step 6 β€” Wire the deployed contract to the storefront

Add the contract id to .env.local:

NEXT_PUBLIC_CHECKOUT_CONTRACT_ID=<CONTRACT_ID>

Restart the dev server and the "Pay with USDC" stage on the checkout page activates.

Convenience script

scripts/deploy-testnet.sh automates Steps 1, 4, and 5 (build β†’ deploy β†’ initialize). It initializes the contract with the given merchant address, or with the deploying account's own public key when none is supplied, and whitelists USDC + native XLM:

./scripts/deploy-testnet.sh                  # merchant = deployer's public key
./scripts/deploy-testnet.sh G...YOUR_MERCHANT...  # explicit merchant

It prints the NEXT_PUBLIC_CHECKOUT_CONTRACT_ID to paste into .env.local.

Paying with Stellar (testnet)

  1. Install Freighter and set the network to Testnet (Settings β†’ Network β†’ Testnet).
  2. Open the checkout page, connect Freighter, and tap Pay with USDC.
  3. The app checks your account (funding it via friendbot if new), verifies your USDC trustline and balance, and simulates the transaction to estimate fees.
  4. Approve the transaction in Freighter. The contract escrows the exact amount (7-decimal USDC) and emits a PaymentReceived event; the live order monitor shows it landing on-chain in real time.
  5. Confirm the payment on the explorer link shown after success.

Mainnet: set NEXT_PUBLIC_STELLAR_NETWORK=mainnet, point NEXT_PUBLIC_USDC_CONTRACT_ID at the mainnet USDC SAC contract, set NEXT_PUBLIC_NATIVE_ASSET_CONTRACT_ID (mainnet native id differs from testnet), redeploy the contract, and initialize it with your real merchant account.

Environment Variables Reference

Variable Required Purpose
NEXT_PUBLIC_STELLAR_NETWORK no testnet (default) or mainnet
NEXT_PUBLIC_STELLAR_RPC_URL no Soroban RPC endpoint (testnet default)
NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE no Network passphrase (testnet default)
NEXT_PUBLIC_CHECKOUT_CONTRACT_ID yes* Deployed checkout contract (C…)
NEXT_PUBLIC_USDC_CONTRACT_ID no USDC token contract (testnet default)
NEXT_PUBLIC_NATIVE_ASSET_CONTRACT_ID no Native XLM SAC (verified testnet default)
PUBLIC_MERCHANT_ADDRESS no Display-only merchant wallet (on-chain value is authoritative)
NEXT_PUBLIC_FIREBASE_* yes Firebase config (existing storefront)
MONGO_DB_URI yes Mongo URI (existing storefront)

* Required for the Stellar payment stage; empty until you deploy the contract.

npm run build validates required public Firebase, EmailJS, and checkout configuration before Next.js compiles. Testnet may use the documented RPC, passphrase, and token defaults. Mainnet builds must explicitly set the RPC URL and USDC/native token contract IDs. CI uses nonfunctional placeholders to check the build without production credentials; validation errors name variables but never print their values. Run npm run validate:production-env to check a deployment environment directly.

Security Notes

  • Merchant authorization is on-chain. The initialize transaction sets the wallet that owns the contract and can release escrow, and requires that merchant's signature. Verify it before submitting, especially on mainnet.
  • Escrow, not custody. Funds move buyer β†’ contract β†’ merchant only via dispatch, or back to the buyer via refund. Neither party can withdraw to an arbitrary address, and an order can only be paid once (OrderAlreadyPaid).
  • Token whitelist. Only tokens the merchant added with add_token can fund orders (TokenNotAllowed otherwise).
  • Amounts are enforced in the contract. amount <= 0 is rejected and the escrowed amount is exactly what the buyer signed for.
  • Client totals are convenience only. Verify payments against the emitted PaymentReceived event server-side if you operate a fulfillment backend.
  • Keys never leave the browser. Freighter holds private keys; the store only ever asks for signatures.

Contributing

Community contributions are welcome. Please read CONTRIBUTING.md before opening a pull request. As this code supports a live store, keep production credentials private and test payment changes on testnet unless a maintainer explicitly directs otherwise.

License

MIT β€” see LICENSE.

About

E-commerce platform showcasing Stellar/Soroban blockchain payments - USDC checkout, escrow contracts, and Freighter wallet integration

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages