Files
descro/CLAUDE.md
2026-05-18 22:40:15 +02:00

4.9 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

Solana Programs (Rust)

# Build (registry must be built first — descro depends on it)
cargo build-sbf --manifest-path programs/descro_ext_resolvers/Cargo.toml && \
cargo build-sbf --manifest-path programs/descro/Cargo.toml

# Test (programs must be built first — tests load .so via include_bytes!)
cargo test --manifest-path programs/descro/Cargo.toml
cargo test --manifest-path programs/descro_ext_resolvers/Cargo.toml

# Single test / specific file
cargo test --manifest-path programs/descro/Cargo.toml -- test_create_escrow
cargo test --manifest-path programs/descro/Cargo.toml --test test_resolve

# Lint / Format
cargo clippy --manifest-path programs/descro/Cargo.toml
cargo fmt --manifest-path programs/descro/Cargo.toml

TypeScript SDK (sdk/)

No build step — consumed as raw TypeScript via transpilePackages in the app. Install from repo root:

yarn install

App (app/)

# Dev server (Turbopack)
yarn workspace descro-app run dev

# Production build (generates tamagui.generated.css then runs next build)
yarn workspace descro-app run build

Repository Structure

programs/
├── descro/                    — Escrow Program
└── descro_ext_resolvers/      — Resolver Registry
sdk/                           — @descro/sdk TypeScript client (workspace package)
├── src/
│   ├── idl/                   — Anchor-generated IDL JSON files
│   ├── escrow.ts              — EscrowClient (instruction builders + fetchers)
│   ├── registry.ts            — RegistryClient
│   ├── listener.ts            — WebSocket subscriptions
│   ├── pda.ts                 — PDA derivation helpers + program IDs
│   ├── types.ts               — TypeScript types matching on-chain state
│   └── index.ts               — Re-exports + DescroSdk convenience class
app/                           — Next.js + Tamagui playground (workspace package)
├── src/app/                   — Next.js App Router pages + providers
├── src/components/            — UI components (EscrowDetail, ResolverPanel, …)
└── src/hooks/                 — useEscrows, useEscrowDetail

Architecture

Yarn Workspaces

Root package.json declares workspaces: ["sdk", "app"]. The repo uses nodeLinker: node-modules (in .yarnrc.yml) because Next.js Turbopack does not support Yarn PnP. Run yarn install from the repo root.

The app depends on the SDK via "@descro/sdk": "workspace:*" and lists it in transpilePackages in next.config.ts so Next.js compiles the TypeScript source directly (no SDK build step needed).

Two-Program Protocol

descro depends on descro_ext_resolvers (with features = ["cpi"]). Communication is one-way: escrow → registry via CPI. The registry does not depend on the escrow.

Escrow Program (descro)

State: EscrowAccount PDA holds trade state. SOL is held in a separate Vault PDA (system-owned, data-free).

PDA seeds:

  • Escrow: ["escrow", seller_pubkey, escrow_id_le_bytes]
  • Vault: ["vault", escrow_account_pubkey]

Instruction flow:

create_escrow (seller) → deposit (buyer) → complete (buyer)
                                         → dispute (buyer|seller) → resolve (resolver)
cancel (seller, only from AwaitingDeposit)

SOL transfers use raw invoke / invoke_signed (not Anchor's CPI helpers) because Anchor 1.0.x changed CpiContext::new to take Pubkey instead of AccountInfo.

Resolver Registry (descro_ext_resolvers)

State: ResolverEntry PDA at ["resolver", authority_pubkey]. Tracks name, type, fee, and resolution stats.

CPI authorization: Only the escrow program may call update_stats, enforced via an ["escrow_authority"] PDA that only the escrow program can sign for. The registry verifies seeds::program = ESCROW_PROGRAM_ID.

Optional CPI: resolve() checks resolver_entry.data_is_empty() before calling the registry — unregistered resolvers still work.

Anchor / SDK Notes

  • Anchor 1.0.x: CpiContext::new takes Pubkey not AccountInfo; use UncheckedAccount<'info> with /// CHECK: instead of AccountInfo<'info> in account structs; #[derive(InitSpace)] + #[max_len(N)] for strings.
  • @coral-xyz/anchor@0.32.x: Use new Program(idl, provider) — the IDL's address field provides the program ID. The 3-argument form new Program(idl, programId, provider) is broken in 0.32.x.
  • LiteSVM tests: each tests/common/mod.rs has setup(), PDA helpers, send()/try_send(), ix_* builders, and read_* deserializers. test_resolve_with_registry.rs loads both .so files to test the full CPI flow.

Program IDs

Program ID
descro DjVR4EuYV6USMJFfsGZwhZ3y8rtWsmG8EvDY96GTqqi3
descro_ext_resolvers GwUPAKs3HHzCpj8uhet4NAnxk9GWNwfrYbpihu5DyFp