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.
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.
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.
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 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.
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,
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.
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
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
}┌─────────────────────────────────────────────────────────────────────────────┐
│ 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 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() │
└──────────────────────┘
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 │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────┘
-
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
-
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
-
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
Creates a new escrow offer.
Parameters:
seed: u64- Unique identifier for this escrowdeposit: u64- Amount of mint_a tokens to depositreceive: u64- Amount of mint_b tokens required
Accounts:
- Maker (signer)
- Mint A & Mint B
- Maker ATA (mint_a)
- Escrow PDA (init)
- Vault ATA (init)
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
Cancels an escrow and returns deposited tokens to the maker.
Accounts:
- Maker (signer)
- Mint A
- Maker ATA (mint_a)
- Escrow PDA
- Vault ATA
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
-
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
- Clone the repository:
git clone <repository-url>
cd solana-escrow- Install Node.js dependencies:
yarn install- Build the program:
anchor buildThis command will:
- Compile the Rust program
- Generate the IDL (Interface Definition Language)
- Create TypeScript types
- Build the program binary
- Run the test suite:
anchor testThis will:
- Start a local Solana validator
- Deploy the program
- Run all integration tests
- Display transaction signatures and results
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>- Start a local Solana validator:
solana-test-validatorThis starts a local blockchain with test accounts funded with SOL.
- Configure Solana CLI for localnet:
solana config set --url localhost- 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- Run tests:
# Run all tests (starts validator automatically)
anchor test
# Run tests against existing validator
anchor test --skip-local-validator- Configure for devnet:
solana config set --url devnet- Get devnet SOL:
solana airdrop 2 $(solana address)- Update Anchor.toml with your wallet path (if different from default):
[provider]
wallet = "~/.config/solana/id.json" # Update this path- Deploy to devnet:
anchor build
anchor deploy- Verify deployment:
solana program show <program-id> --url devnetThe 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 -- --verboseAfter 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-
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 seedsmut: Enforces mutability constraintssigner: 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)
- Always verify program ID before interacting with the program
- Validate escrow accounts using PDA derivation
- Check token amounts before executing trades
- Monitor escrow state for unexpected changes
- Use testnet/devnet for testing before mainnet deployment
⚠️ 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)
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 Programtoken_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();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 Programtoken_program- Token Program Interfacesystem_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();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 Programtoken_program- Token Program Interfacesystem_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();-
"Insufficient funds" error
- Ensure your wallet has enough SOL for transaction fees
- Check that you have enough tokens in your token accounts
-
"Account not found" error
- Verify all account addresses are correct
- Ensure token accounts exist (use
init_if_neededor create manually)
-
"Invalid seeds" error
- Verify PDA derivation matches the escrow's stored seeds
- Check that the bump seed is correct
-
"Constraint violation" error
- Verify account relationships (maker, mint_a, mint_b match escrow)
- Ensure signer constraints are satisfied
ISC
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
anchor test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- 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
- Built with Anchor Framework
- Uses Solana Program Library (SPL)
- Compatible with Token-2022 Program
For issues, questions, or suggestions, please open an issue on GitHub.

