Skip to content

TurbinePB-Q425-Kanbanization/solana-escrow

Repository files navigation

Solana Escrow Program

Overview

A decentralized escrow smart contract built on Solana using the Anchor framework. This program enables trustless token swaps between two parties, where one party (the maker) deposits tokens and specifies what they want to receive in return, and another party (the taker) can fulfill the trade. This escrow program facilitates atomic token swaps on the Solana blockchain. It uses Program Derived Addresses (PDAs) for secure account management and supports both the classic SPL Token program and Token Extensions (Token-2022) through the Token Interface.

User Stories

As a Maker (Token Seller)

Story 1: Create an Escrow Offer

As a token seller,
I want to create an escrow offer by depositing my tokens,
So that I can trade them for other tokens without trusting a counterparty.

Acceptance Criteria:

  • I can deposit tokens of type A (mint_a) into a secure escrow vault
  • I can specify the exact amount of tokens of type B (mint_b) I want to receive
  • The escrow is created with a unique seed, allowing me to create multiple escrows
  • The deposited tokens are locked in a Program Derived Address (PDA) vault
  • The escrow account stores all relevant information (maker, mints, amounts, seed)
  • I can verify the escrow creation on-chain via transaction signature

Business Value: Enables trustless token trading without requiring counterparties to trust each other directly.


Story 2: Cancel/Refund an Escrow

As a token seller,
I want to cancel my escrow offer and retrieve my deposited tokens,
So that I can get my tokens back if market conditions change or I change my mind.

Acceptance Criteria:

  • I can call the refund function to retrieve my deposited tokens
  • Only I (the maker) can refund my own escrow
  • The refund operation is atomic - either fully succeeds or fails
  • The escrow account and vault are closed after successful refund
  • I receive rent exemption from closed accounts
  • All my original tokens (mint_a) are returned to my associated token account

Business Value: Provides flexibility and protects makers from permanent token lockup.


Story 3: Receive Payment from Taker

As a token seller,
I want to automatically receive tokens when a taker fulfills my escrow,
So that I complete the trade without additional manual steps.

Acceptance Criteria:

  • When a taker fulfills my escrow, I automatically receive the required tokens (mint_b)
  • The transfer happens atomically with the taker receiving my tokens
  • No partial fills - either the full trade executes or it fails
  • My associated token account for mint_b is created automatically if needed
  • I receive the exact amount specified in the escrow

Business Value: Ensures secure, automatic trade execution without manual intervention.


As a Taker (Token Buyer)

Story 4: Discover Available Escrows

As a token buyer,
I want to browse and discover available escrow offers,
So that I can find trades that match my needs.

Acceptance Criteria:

  • I can query the blockchain for all escrow accounts created by makers
  • Each escrow displays the deposited token type (mint_a) and amount
  • Each escrow shows the required token type (mint_b) and amount needed
  • I can filter escrows by maker, token types, or exchange rate
  • I can verify escrow validity and availability before attempting to take it

Business Value: Enables efficient discovery of trading opportunities.


Story 5: Accept and Complete an Escrow

As a token buyer,
I want to accept an escrow offer and complete the token swap,
So that I can exchange my tokens for the escrowed tokens.

Acceptance Criteria:

  • I can call the take function to fulfill an escrow in a single transaction
  • I deposit the required tokens (mint_b) directly to the maker's account
  • I receive the tokens (mint_a) from the escrow vault automatically
  • The trade is atomic - both token transfers happen or neither does
  • My associated token account for mint_a is created automatically if needed
  • The escrow is automatically closed after successful trade
  • I receive the exact amount of tokens (mint_a) that were deposited

Business Value: Provides a secure, one-step process to complete token swaps.


As a Developer

Story 6: Integrate Escrow Program

As a developer,
I want to integrate this escrow program into my application,
So that I can offer escrow services to my users.

Acceptance Criteria:

  • The program provides clear, well-documented instruction interfaces
  • All accounts are automatically validated using Anchor's account constraints
  • The program follows standard Solana patterns (PDAs, ATAs)
  • Type-safe client libraries are generated from the IDL
  • Comprehensive test suite demonstrates proper usage
  • The program supports both classic SPL Token and Token-2022 programs
  • Error messages are clear and actionable

Business Value: Reduces integration time and ensures secure, correct implementation.

Architecture

Program Structure

solana-escrow/
├── programs/
│   └── solana-escrow/
│       └── src/
│           ├── lib.rs              # Main program entry point
│           ├── instructions/
│           │   ├── make.rs         # Create escrow instruction
│           │   ├── take.rs         # Accept escrow instruction
│           │   ├── refund.rs       # Cancel escrow instruction
│           │   └── mod.rs          # Instruction module exports
│           └── state/
│               └── mod.rs          # Escrow state definition
├── tests/
│   └── solana-escrow.ts           # Integration tests
└── Anchor.toml                     # Anchor configuration

Data Structures

Escrow Account

pub struct Escrow {
    pub seed: u64,        // Unique identifier for the escrow
    pub maker: Pubkey,    // Public key of the escrow creator
    pub mint_a: Pubkey,   // Token type being deposited
    pub mint_b: Pubkey,   // Token type desired in return
    pub receive: u64,     // Amount of mint_b tokens required
    pub bump: u8,         // PDA bump seed
}

Architectural Diagram

System Overview

System Overview Diagram

Data Flow Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                              MAKE Instruction Flow                          │
└─────────────────────────────────────────────────────────────────────────────┘

┌──────────┐         ┌──────────────┐         ┌──────────────┐         ┌──────────┐
│  Maker   │────────▶│ Escrow PDA   │────────▶│    Vault     │◄────────│ Mint A   │
│ (Signer) │         │   Account    │         │    (ATA)     │         │          │
└──────────┘         │              │         │              │         └──────────┘
                     │ • seed: u64  │         │ Holds:       │
                     │ • maker: PK  │         │ mint_a tokens│
                     │ • mint_a: PK │         │              │
                     │ • mint_b: PK │         │ Authority:   │
                     │ • receive: u64│        │ Escrow PDA   │
                     │ • bump: u8   │         │              │
                     └──────────────┘         └──────────────┘
                            │                         ▲
                            │ Creates &               │
                            │ Initializes             │ Receives deposit
                            │                         │
                     ┌──────┴──────┐
                     │             │
              ┌──────▼─────┐ ┌─────▼──────┐
              │  Mint A    │ │  Mint B    │
              │ (deposited)│ │ (desired)  │
              └────────────┘ └────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                              TAKE Instruction Flow                          │
└─────────────────────────────────────────────────────────────────────────────┘

┌──────────┐                                                                   ┌──────────┐
│  Taker   │                                                                   │  Maker   │
│ (Signer) │                                                                   │          │
└────┬─────┘                                                                   └─────┬────┘
     │                                                                               │
     │ 1. Deposit mint_b tokens                                                      │
     │    (amount = escrow.receive)                                                  │
     │                                                                               │
     └──────────────┐                                                    ┌───────────┘
                    │                                                    │
                    ▼                                                    ▼
         ┌───────────────────┐                              ┌─────────────────────────┐
         │ Taker ATA (mint_b)│────────Transfer─────────────▶│ Maker ATA (mint_b)      │
         │                   │                              │ (auto-created if needed)│
         └───────────────────┘                              └─────────────────────────┘
                    │                                                    ▲
                    │                                                    │ Receives
                    │                                                    │ payment
                    │                                                    │
     ┌──────────────┴──────────────┐
     │                             │
     │ 2. Withdraw mint_a tokens   │
     │    from vault               │
     │                             │
     ▼                             ▼
┌──────────────────────────────────────────────────────────────┐
│                   Escrow PDA (Signs)                         │
│  seeds: [b"escrow", maker.key(), seed]                       │
│  bump: escrow.bump                                           │
└──────────────────────────────────────────────────────────────┘
     │                             │
     │ Authority for               │
     │ vault transfer              │
     │                             │
     ▼                             ▼
┌───────────────────┐                              ┌──────────────────────┐
│ Vault ATA (mint_a)│────────Transfer─────────────▶│ Taker ATA (mint_a)   │
│                   │                              │ (auto-created if needed)│
│ Holds: mint_a     │                              │                      │
└───────────────────┘                              └──────────────────────┘
     │                                                    ▲
     │                                                    │
     │ 3. Close vault account                             │ Receives
     │    Return rent to maker                            │ tokens
     └────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│                            REFUND Instruction Flow                          │
└─────────────────────────────────────────────────────────────────────────────┘

┌──────────┐
│  Maker   │
│ (Signer) │
└────┬─────┘
     │
     │ Must be the escrow creator
     │
     └──────────────┐
                    │
                    ▼
         ┌──────────────────────┐
         │   Escrow PDA Account │
         │   Validates:         │
         │   • maker matches    │
         │   • seeds match      │
         └──────────────────────┘
                    │
                    │ Signs with PDA
                    │
                    ▼
         ┌──────────────────────┐
         │  Vault ATA (mint_a)  │
         │  Holds: mint_a tokens│
         └──────────────────────┘
                    │
                    │ 1. Transfer all tokens
                    │
                    ▼
         ┌──────────────────────┐
         │ Maker ATA (mint_a)   │
         │ Receives refund      │
         └──────────────────────┘
                    ▲
                    │
                    │ 2. Close vault
                    │    Return rent
                    │
         ┌──────────┴───────────┐
         │   Maker (receives    │
         │   rent + tokens)     │
         └──────────────────────┘

Account Relationship Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│                          Account Ownership Model                            │
└─────────────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────────┐
│                                MAKER                                     │
│  ┌───────────────────────────────────────────────────────────────────┐   │
│  │ • System Account (Pubkey)                                         │   │
│  │ • Owns:                                                           │   │
│  │   ├─ Maker ATA (mint_a) ──────────────┐                           │   │
│  │   │   Authority: Maker                │                           │   │
│  │   │   Purpose: Source of deposit      │                           │   │
│  │   │                                   │                           │   │
│  │   └─ Maker ATA (mint_b) ──────────────┼───┐                       │   │
│  │       Authority: Maker                │   │                       │   │
│  │       Purpose: Receives payment       │   │                       │   │
│  │                                       │   │                       │   │
│  │   Creates:                            │   │                       │   │
│  │   └─ Escrow PDA ──────────────────────┼───┼──────────┐            │   │
│  │       Seeds: [b"escrow", maker, seed] │   │          │            │   │
│  │       Owner: Program                  │   │          │            │   │
│  └───────────────────────────────────────┼───┼──────────┼────────────┘   │
└──────────────────────────────────────────┼───┼──────────┼────────────────┘
                                           │   │          │
                                           │   │          │
┌──────────────────────────────────────────┼───┼──────────┼────────────────┐
│                                TAKER     │   │          │                │
│  ┌───────────────────────────────────────┼───┼──────────┼────────────┐   │
│  │ • System Account (Pubkey)             │   │          │            │   │
│  │ • Owns:                               │   │          │            │   │
│  │   ├─ Taker ATA (mint_a) ──────────────┼───┼──────────┼───┐        │   │
│  │   │   Authority: Taker                │   │          │   │        │   │
│  │   │   Purpose: Receives tokens        │   │          │   │        │   │
│  │   │                                   │   │          │   │        │   │
│  │   └─ Taker ATA (mint_b) ──────────────┼───┼──────────┼───┼───┐    │   │
│  │       Authority: Taker                │   │          │   │   │    │   │
│  │       Purpose: Source of payment      │   │          │   │   │    │   │
│  └───────────────────────────────────────┼───┼──────────┼───┼───┼────┘   │
└──────────────────────────────────────────┼───┼──────────┼───┼───┼────────┘
                                           │   │          │   │   │
                                           │   │          │   │   │
┌──────────────────────────────────────────┼───┼──────────┼───┼───┼────────┐
│                          ESCROW PROGRAM  │   │          │   │   │        │
│  ┌───────────────────────────────────────┼───┼──────────┼───┼───┼─────┐  │
│  │ • Program ID: 2cBUB65rt9MQ...         │   │          │   │   │     │  │
│  │ • Owns:                               │   │          │   │   │     │  │
│  │   └─ Escrow PDA ──────────────────────┘   │          │   │   │     │  │
│  │       Seeds: [b"escrow", maker, seed]     │          │   │   │     │  │
│  │       Stores: escrow state                │          │   │   │     │  │
│  │                                           │          │   │   │     │  │
│  │   Controls:                               │          │   │   │     │  │
│  │   └─ Vault ATA ───────────────────────────┘          │   │   │     │  │
│  │       Mint: mint_a                                   │   │   │     │  │
│  │       Authority: Escrow PDA                          │   │   │     │  │
│  │       Purpose: Holds deposited tokens                │   │   │     │  │
│  └──────────────────────────────────────────────────────┼───┼───┼─────┘  │
└─────────────────────────────────────────────────────────┼───┼───┼────────┘
                                                          │   │   │
                                                          │   │   │
                    ┌─────────────────────────────────────┘   │   │
                    │                                         │   │
                    ▼                                         ▼   ▼
        ┌──────────────────────┐                    ┌──────────────────────┐ 
        │  TOKEN FLOWS         │                    │  ACCOUNT CREATION    │ 
        │                      │                    │                      │ 
        │  MAKE:               │                    │  Maker ATA (mint_b): │ 
        │  maker_ata_a ───────▶│ vault              │  Created by taker    │ 
        │                      │                    │  during take()       │
        │  TAKE:               │                    │                      │ 
        │  taker_ata_b ───────▶│ maker_ata_b        │  Taker ATA (mint_a): │ 
        │  vault ─────────────▶│ taker_ata_a        │  Created by taker    │ 
        │                      │                    │  during take()       │ 
        │  REFUND:             │                    │                      │ 
        │  vault ─────────────▶│ maker_ata_a        │  Vault ATA:          │ 
        │                      │                    │  Created by maker    │ 
        └──────────────────────┘                    │  during make()       │ 
                                                    └──────────────────────┘ 

Program Instruction Flow Summary

User Transaction Flow:

┌────────────────────────────────────────────────────────────────────────────┐
│                              make(seed, deposit, receive)                  │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 1. Validate accounts (maker signer, mints valid)                     │  │
│  │ 2. Derive Escrow PDA: [b"escrow", maker.key(), seed]                 │  │
│  │ 3. Initialize Escrow account with state                              │  │
│  │ 4. Create Vault ATA (owned by Escrow PDA)                            │  │
│  │ 5. Transfer deposit amount from maker_ata_a to vault                 │  │
│  │ 6. Return success                                                    │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────────────────────┐
│                              take()                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 1. Validate accounts (taker signer, escrow exists)                   │  │
│  │ 2. Verify escrow PDA matches maker and seed                          │  │
│  │ 3. Create maker_ata_b if needed (payer: taker)                       │  │
│  │ 4. Create taker_ata_a if needed (payer: taker)                       │  │
│  │ 5. Transfer receive amount from taker_ata_b to maker_ata_b           │  │
│  │ 6. Withdraw all tokens from vault to taker_ata_a (PDA signs)         │  │
│  │ 7. Close vault account (rent to maker, PDA signs)                    │  │
│  │ 8. Close escrow account (rent to maker)                              │  │
│  │ 9. Return success                                                    │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────────────────────┐
│                              refund()                                      │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │ 1. Validate accounts (maker signer, escrow exists)                   │  │
│  │ 2. Verify maker matches escrow.maker                                 │  │
│  │ 3. Verify escrow PDA seeds match                                     │  │
│  │ 4. Transfer all tokens from vault to maker_ata_a (PDA signs)         │  │
│  │ 5. Close vault account (rent to maker, PDA signs)                    │  │
│  │ 6. Close escrow account (rent to maker)                              │  │
│  │ 7. Return success                                                    │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────────┘

Key Components

  1. Escrow PDA: Program Derived Address created with seeds [b"escrow", maker.key(), seed]

    • Acts as the authority for the vault
    • Stores escrow state and parameters
    • Can be closed after trade completion or refund
  2. Vault: Associated Token Account owned by the Escrow PDA

    • Holds the deposited tokens (mint_a)
    • Transfers tokens to taker upon successful trade
    • Returns tokens to maker upon refund
  3. Associated Token Accounts (ATAs):

    • Maker ATA (mint_a): Source of deposit
    • Maker ATA (mint_b): Receives tokens from taker
    • Taker ATA (mint_a): Receives tokens from vault
    • Taker ATA (mint_b): Source of payment

Instructions

make(seed, deposit, receive)

Creates a new escrow offer.

Parameters:

  • seed: u64 - Unique identifier for this escrow
  • deposit: u64 - Amount of mint_a tokens to deposit
  • receive: u64 - Amount of mint_b tokens required

Accounts:

  • Maker (signer)
  • Mint A & Mint B
  • Maker ATA (mint_a)
  • Escrow PDA (init)
  • Vault ATA (init)

take()

Accepts an escrow offer and completes the trade.

Accounts:

  • Taker (signer)
  • Maker
  • Mint A & Mint B
  • Taker ATA (mint_a) - may be created if needed
  • Taker ATA (mint_b)
  • Maker ATA (mint_b) - may be created if needed
  • Escrow PDA
  • Vault ATA

refund()

Cancels an escrow and returns deposited tokens to the maker.

Accounts:

  • Maker (signer)
  • Mint A
  • Maker ATA (mint_a)
  • Escrow PDA
  • Vault ATA

Project Structure

solana-escrow/
├── programs/                          # Solana program source code
│   └── solana-escrow/
│       ├── Cargo.toml                 # Rust dependencies
│       └── src/
│           ├── lib.rs                 # Main program entry point & instruction router
│           ├── instructions/          # Instruction implementations
│           │   ├── mod.rs             # Instruction module exports
│           │   ├── make.rs            # Create escrow instruction
│           │   ├── take.rs            # Accept escrow instruction
│           │   └── refund.rs          # Cancel escrow instruction
│           └── state/                 # Program state definitions
│               └── mod.rs             # Escrow account structure
├── tests/                             # Integration tests
│   └── solana-escrow.ts              # Test suite using Anchor & Mocha
├── migrations/                        # Deployment scripts
│   └── deploy.ts                     # Program deployment script
├── target/                           # Build artifacts
│   ├── deploy/                       # Deployed program binaries
│   ├── idl/                          # Generated IDL files
│   └── types/                        # TypeScript type definitions
├── app/                              # Frontend application (if applicable)
├── Anchor.toml                       # Anchor configuration
├── Cargo.toml                        # Workspace Cargo configuration
├── package.json                      # Node.js dependencies
├── tsconfig.json                     # TypeScript configuration
└── README.md                         # This file

Setup & Installation

Prerequisites

  • Rust: Latest stable version (1.70+)

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • Solana CLI: v1.18 or higher

    sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
  • Anchor CLI: v0.32.1 or higher

    cargo install --git https://github.com/coral-xyz/anchor avm --locked --force
    avm install latest
    avm use latest
  • Node.js: v18+ and Yarn

    # Install Node.js via nvm (recommended)
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
    nvm install 18
    nvm use 18
    
    # Install Yarn
    npm install -g yarn

Installation

  1. Clone the repository:
git clone <repository-url>
cd solana-escrow
  1. Install Node.js dependencies:
yarn install
  1. Build the program:
anchor build

This command will:

  • Compile the Rust program
  • Generate the IDL (Interface Definition Language)
  • Create TypeScript types
  • Build the program binary
  1. Run the test suite:
anchor test

This will:

  • Start a local Solana validator
  • Deploy the program
  • Run all integration tests
  • Display transaction signatures and results

Verify Installation

After installation, verify everything works:

# Check Solana version
solana --version

# Check Anchor version
anchor --version

# Check Rust version
rustc --version

# List programs (should show escrow program if deployed)
solana program show <program-id>

Development

Local Development Workflow

  1. Start a local Solana validator:
solana-test-validator

This starts a local blockchain with test accounts funded with SOL.

  1. Configure Solana CLI for localnet:
solana config set --url localhost
  1. In another terminal, build and deploy:
# Build the program
anchor build

# Deploy to local validator
anchor deploy

# Or build and deploy in one step
anchor build && anchor deploy
  1. Run tests:
# Run all tests (starts validator automatically)
anchor test

# Run tests against existing validator
anchor test --skip-local-validator

Devnet Deployment

  1. Configure for devnet:
solana config set --url devnet
  1. Get devnet SOL:
solana airdrop 2 $(solana address)
  1. Update Anchor.toml with your wallet path (if different from default):
[provider]
wallet = "~/.config/solana/id.json"  # Update this path
  1. Deploy to devnet:
anchor build
anchor deploy
  1. Verify deployment:
solana program show <program-id> --url devnet

Testing

The test suite (tests/solana-escrow.ts) includes:

  • Setup Tests: Creating test mints and token accounts
  • Make Tests: Creating escrow offers
  • Take Tests: Accepting escrow offers and completing trades
  • Refund Tests: Canceling escrows and retrieving tokens

Run specific test suites:

# Run all tests
yarn test

# Run with verbose output
anchor test --skip-local-validator -- --verbose

Code Generation

After modifying the program, regenerate types:

# Build generates IDL and types automatically
anchor build

# Generated files are in:
# - target/idl/anchor_escrow.json
# - target/types/anchor_escrow.ts

Security Considerations

Security Features

  • PDA Authority: The escrow PDA acts as the vault authority, ensuring only the program can manage deposits

    • Vault tokens cannot be withdrawn without program execution
    • PDA derivation uses deterministic seeds preventing unauthorized access
  • Account Validation: All accounts are validated using Anchor's constraints

    • has_one: Ensures account relationships are correct (e.g., escrow.maker matches)
    • seeds: Validates PDA derivation matches expected seeds
    • mut: Enforces mutability constraints
    • signer: Ensures required signatures are present
  • Atomic Operations: Trades are atomic - either both parties receive tokens or the transaction fails

    • No intermediate states where one party has advantage
    • Transaction rollback on any error
  • No Partial Fills: Escrows must be taken in full or refunded entirely

    • Prevents ambiguity and simplifies state management
    • Clear refund conditions (only maker can refund)

Security Best Practices

  1. Always verify program ID before interacting with the program
  2. Validate escrow accounts using PDA derivation
  3. Check token amounts before executing trades
  4. Monitor escrow state for unexpected changes
  5. Use testnet/devnet for testing before mainnet deployment

Known Limitations

  • ⚠️ Escrows cannot be partially filled
  • ⚠️ No time-based expiration (escrows persist until taken or refunded)
  • ⚠️ No price or rate validation (users must verify rates manually)
  • ⚠️ Maker cannot update escrow parameters (must refund and recreate)

Token Account Visualization

Token Account Diagram

API Reference

Program Instructions

make(seed: u64, deposit: u64, receive: u64)

Creates a new escrow offer.

Parameters:

  • seed: u64 - Unique identifier for this escrow (allows multiple escrows per maker)
  • deposit: u64 - Amount of mint_a tokens to deposit (in token's base units)
  • receive: u64 - Amount of mint_b tokens required (in token's base units)

Accounts Required:

  • maker - The escrow creator (signer, mutable)
  • mint_a - Token mint being deposited (immutable)
  • mint_b - Token mint desired in return (immutable)
  • maker_ata_a - Maker's associated token account for mint_a (mutable)
  • escrow - Escrow PDA account (will be initialized)
  • vault - Vault associated token account (will be initialized, owned by escrow PDA)
  • associated_token_program - Associated Token Program
  • token_program - Token Program Interface (SPL Token or Token-2022)
  • system_program - System Program

Returns: Result<()>

Example:

await program.methods
  .make(new BN(seed), new BN(1e6), new BN(1e6))
  .accounts({
    maker: maker.publicKey,
    mintA: mintA.publicKey,
    mintB: mintB.publicKey,
    makerAtaA: makerAtaA,
    escrow: escrowPDA,
    vault: vaultPDA,
    associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
    tokenProgram: TOKEN_PROGRAM_ID,
    systemProgram: SystemProgram.programId,
  })
  .signers([maker])
  .rpc();

take()

Accepts an escrow offer and completes the atomic token swap.

Parameters: None (all data read from escrow account)

Accounts Required:

  • taker - The person accepting the escrow (signer, mutable)
  • maker - The escrow creator (mutable)
  • mint_a - Token mint in the vault (immutable)
  • mint_b - Token mint required as payment (immutable)
  • taker_ata_a - Taker's ATA for mint_a (init if needed, mutable)
  • taker_ata_b - Taker's ATA for mint_b (mutable)
  • maker_ata_b - Maker's ATA for mint_b (init if needed, mutable)
  • escrow - Escrow PDA account (mutable, will be closed)
  • vault - Vault ATA containing deposited tokens (mutable, will be closed)
  • associated_token_program - Associated Token Program
  • token_program - Token Program Interface
  • system_program - System Program

Returns: Result<()>

Example:

await program.methods
  .take()
  .accounts({
    taker: taker.publicKey,
    maker: maker.publicKey,
    mintA: mintA.publicKey,
    mintB: mintB.publicKey,
    takerAtaA: takerAtaA,
    takerAtaB: takerAtaB,
    makerAtaB: makerAtaB,
    escrow: escrowPDA,
    vault: vaultPDA,
    associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
    tokenProgram: TOKEN_PROGRAM_ID,
    systemProgram: SystemProgram.programId,
  })
  .signers([taker])
  .rpc();

refund()

Cancels an escrow and returns deposited tokens to the maker.

Parameters: None

Accounts Required:

  • maker - The escrow creator (signer, mutable)
  • mint_a - Token mint in the vault (immutable)
  • maker_ata_a - Maker's ATA for mint_a (mutable)
  • escrow - Escrow PDA account (mutable, will be closed)
  • vault - Vault ATA containing deposited tokens (mutable, will be closed)
  • associated_token_program - Associated Token Program
  • token_program - Token Program Interface
  • system_program - System Program

Returns: Result<()>

Example:

await program.methods
  .refund()
  .accounts({
    maker: maker.publicKey,
    mintA: mintA.publicKey,
    makerAtaA: makerAtaA,
    escrow: escrowPDA,
    vault: vaultPDA,
    associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
    tokenProgram: TOKEN_PROGRAM_ID,
    systemProgram: SystemProgram.programId,
  })
  .signers([maker])
  .rpc();

Troubleshooting

Common Issues

  1. "Insufficient funds" error

    • Ensure your wallet has enough SOL for transaction fees
    • Check that you have enough tokens in your token accounts
  2. "Account not found" error

    • Verify all account addresses are correct
    • Ensure token accounts exist (use init_if_needed or create manually)
  3. "Invalid seeds" error

    • Verify PDA derivation matches the escrow's stored seeds
    • Check that the bump seed is correct
  4. "Constraint violation" error

    • Verify account relationships (maker, mint_a, mint_b match escrow)
    • Ensure signer constraints are satisfied

License

ISC

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Contribution Guidelines

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (anchor test)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

Development Standards

  • Follow Rust best practices and Solana/Anchor patterns
  • Write comprehensive tests for all new features
  • Update documentation for any API changes
  • Ensure code passes all linters and formatters

Acknowledgments

Support

For issues, questions, or suggestions, please open an issue on GitHub.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published