Back to blog

Build a Solana Escrow Program for Service Marketplaces (Anchor Blueprint)

|
| solana, anchor, smart-contracts, architecture, marketplace

A lot of teams want “something useful” on Solana and immediately jump to tokenomics. A better first product is usually boring and profitable: escrow.

If you run a service marketplace (design, consulting, dev gigs, AI tasks), you need one hard guarantee:

  • buyer funds are reserved,
  • seller gets paid only after acceptance,
  • disputes and timeouts are deterministic.

Solana is a good fit for this because transaction costs are small and execution is fast enough for normal product UX.

This article gives you a production-oriented blueprint using Anchor.

1. Product Scope (What This Program Should Do)

Keep v1 narrow:

  • Create escrow for one order
  • Fund escrow in stablecoin (for example USDC)
  • Mark work delivered
  • Buyer accepts and releases payment
  • Optional timeout-based cancellation

Do not start with arbitration marketplaces, reputation staking, and fee tokenomics in the same release.

2. Account Model

A clean account model removes most future pain.

#[account]
pub struct Escrow {
    pub escrow_id: u64,
    pub buyer: Pubkey,
    pub seller: Pubkey,
    pub mint: Pubkey,
    pub amount: u64,
    pub fee_bps: u16,
    pub created_at: i64,
    pub delivery_deadline: i64,
    pub status: EscrowStatus,
    pub bump: u8,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq)]
pub enum EscrowStatus {
    Created,
    Funded,
    Delivered,
    Released,
    Cancelled,
    Disputed,
}

Design notes:

  • Use a PDA escrow vault authority, never a private key wallet for custody.
  • Keep status transitions explicit.
  • Store all critical participants and amounts on-chain; do not trust off-chain payloads.

3. Instruction Set

A minimal but complete instruction set:

  1. create_escrow(escrow_id, seller, amount, deadline, fee_bps)
  2. fund_escrow()
  3. mark_delivered(proof_hash)
  4. accept_and_release()
  5. cancel_after_timeout()
  6. raise_dispute(reason_hash)

This is enough to ship real transactions and iterate safely.

4. Critical Security Invariants

These invariants should hold in every instruction:

  • Funds move only from escrow vault to allowed recipients.
  • Only buyer can call accept_and_release.
  • Only seller can call mark_delivered.
  • Timeout cancellation requires Clock::get()?.unix_timestamp > delivery_deadline.
  • State transitions are one-way and validated (Funded -> Delivered -> Released etc.).
  • Arithmetic on fees and payouts is checked (no overflow, no negative logic).

If any of these fail, you get real money bugs, not cosmetic bugs.

5. Example Release Flow

pub fn accept_and_release(ctx: Context<AcceptAndRelease>) -> Result<()> {
    let escrow = &mut ctx.accounts.escrow;

    require!(escrow.status == EscrowStatus::Delivered, EscrowError::InvalidStatus);
    require!(ctx.accounts.buyer.key() == escrow.buyer, EscrowError::Unauthorized);

    let fee = (escrow.amount as u128)
        .checked_mul(escrow.fee_bps as u128)
        .ok_or(EscrowError::MathOverflow)?
        / 10_000u128;

    let seller_amount = (escrow.amount as u128)
        .checked_sub(fee)
        .ok_or(EscrowError::MathOverflow)?;

    // Transfer seller payout from vault ATA -> seller ATA
    // Transfer fee from vault ATA -> platform fee ATA
    // (Use token program CPI with PDA signer seeds)

    escrow.status = EscrowStatus::Released;
    Ok(())
}

This example omits CPI boilerplate, but shows the core discipline:

  • strict status check,
  • strict caller check,
  • checked math,
  • state update only after valid transfer path.

6. Off-Chain Services You Still Need

Smart contracts are not enough for a production marketplace.

You still need:

  • Order API for business rules and metadata
  • Indexer/worker that tracks escrow account changes and signatures
  • Reconciliation DB mapping on-chain escrow IDs to platform order IDs
  • Notification service for delivery, acceptance, timeout warnings

The program secures value transfer. Your backend secures operability.

7. Testing Matrix (Do Not Skip)

Unit and integration tests should cover:

  • Happy path: create -> fund -> deliver -> release
  • Unauthorized calls by wrong signer
  • Double execution attempts
  • Deadline edge conditions
  • Fee rounding behavior on small amounts
  • Token account mismatch attempts

If your tests do not try to steal funds, they are incomplete.

8. Rollout Plan

A pragmatic rollout:

  1. Internal beta with capped amounts
  2. Mainnet limited cohort and allowlisted sellers
  3. Automated alerts for failed releases and stuck escrows
  4. Controlled expansion of amount limits

Treat this as payment infrastructure. Rollout discipline matters more than adding fancy features quickly.

9. Why This Is a Strong First Solana Product

Escrow gives immediate business value:

  • trust layer for marketplace transactions,
  • lower operational reconciliation overhead,
  • clear path to platform fees.

And technically, it trains your team on the hard parts that matter later:

  • account design,
  • signer and authority safety,
  • deterministic state machines,
  • production monitoring around on-chain flows.

Final Take

If you want a serious Solana use case, build escrow before chasing speculative mechanics.

You will get a useful product, real transaction volume, and a codebase your team can evolve into more advanced programs later.

Related posts

Cite this article

If you reference this post, please link to the original URL and credit the author.

Michal Drozd. "Build a Solana Escrow Program for Service Marketplaces (Anchor Blueprint)". https://www.michal-drozd.com/en/blog/solana-escrow-program-marketplace/ (Published February 24, 2026).