Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ runs:
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 20
node-version-file: '.nvmrc'

- name: Get pnpm store directory
id: pnpm-store
Expand Down
10 changes: 4 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ config.json

keys/

# Playwright output
apps/web/playwright-report/
apps/web/test-results/

# TypeScript incremental build cache
apps/web/tsconfig.tsbuildinfo
# Webapp output
webapp/playwright-report/
webapp/test-results/
webapp/tsconfig.tsbuildinfo

# TypeDoc generated API docs
clients/typescript/docs/
Expand Down
13 changes: 8 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Build Commands

```bash
# Full build (deploy keys → program .so → IDL → clients → TS client dist)
# Full build (program .so → IDL → clients → TS client dist)
just build

# Individual steps
Expand All @@ -21,12 +21,14 @@ just build-program # Build .so binary only (cargo build-sbf)
just build-client # Build TypeScript client (tsup)

# Formatting and linting
just fmt # cargo fmt + biome format
just fmt # cargo fmt + prettier
just check # fmt-check + lint-check

# Testing (program uses LiteSVM in-crate; client uses Vitest)
# Testing
just test # All tests (program + client)
just test-program # cargo test-sbf
just unit-test # Rust unit tests
just integration-test # Rust LiteSVM integration tests
just test-program # backwards-compatible alias for unit-test
just test-client # Vitest against Surfpool
just test-and-benchmark # CU report → cu_report.md

Expand Down Expand Up @@ -85,7 +87,8 @@ clients/typescript/src/generated/ (auto-generated; wrapped by hand-written SDK

### Testing

- Rust: LiteSVM-based, located in `program/src/tests/` (in-crate). Run via `cargo test-sbf`.
- Rust unit tests: located in `program/src/tests/`. Run via `just unit-test`.
- Rust integration tests: LiteSVM-based workspace crate in `tests/integration-tests/`. Run via `just integration-test`.
- TypeScript: Vitest against Surfpool, in `clients/typescript/test/`. Includes Squads + Swig smart-wallet integration tests and security-focused tests.
- CU benchmarks: set `CU_REPORT=1` to write `cu_report.md` (posted as PR comment in CI).

Expand Down
51 changes: 23 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ subscriptions/
├── webapp/ # Demo UI (React) + local API server
│ ├── src/ # React app (routes, components, hooks)
│ ├── api/ # Node.js API server (faucet, deploy, config)
│ ├── patches/ # pnpm patch overrides for webapp deps
│ └── scripts/ # Environment init, mock USDC minting
├── scripts/ # Shell scripts (validator, webapp launcher)
├── docs/ # Architecture Decision Records
Expand All @@ -67,8 +66,7 @@ subscriptions/
├── .githooks/ # Git hooks (pre-push: fmt + lint checks)
├── keys/ # Program keypair (gitignored)
├── justfile # Build/test/dev task runner
├── codama.js # Codama client generation config
├── codama-visitors.mjs # Codama visitors (event authority PDA, defaults)
├── scripts/generate-clients.ts # Codama client generation script
└── txtx.yml # Surfpool runbook config
```

Expand Down Expand Up @@ -126,15 +124,9 @@ curl -sL https://run.surfpool.run/ | bash

6. Node.js (required by `webapp/` scripts)

## Keypair and Program ID

Local workflows use `keys/subscriptions-keypair.json` as the source keypair. The `just build` and `just build-program` recipes copy it to `target/deploy/` and verify that the keypair matches the `declare_id!` in `lib.rs`.

The keypair is checked into the repository. If it is missing, `prepare-deploy-keys` will error and prompt you to restore it:
## Program ID

```bash
git show <commit>^:keys/subscriptions-keypair.json > keys/subscriptions-keypair.json
```
The program ID is declared in `program/src/lib.rs`. Local Surfpool workflows install the program at that canonical address via `runbooks/surfnet-setup`, so a checked-in program keypair is not required for local tests.

Print the program ID at any time:

Expand All @@ -161,19 +153,21 @@ The `justfile` is the main entrypoint for day-to-day development.
| Recipe | Description |
| ------------------------- | ------------------------------------------------------------- |
| `just test` | Run program tests + client integration tests |
| `just test-program` | Run Rust SBF tests (`cargo test-sbf` with LiteSVM) |
| `just test-program` | Backwards-compatible alias for `just unit-test` |
| `just unit-test` | Run Rust unit tests |
| `just integration-test` | Run Rust LiteSVM integration tests |
| `just test-client` | Run TypeScript integration tests (vitest with Surfpool) |
| `just test-and-benchmark` | Run tests and generate `cu_report.md` with compute unit usage |

### Code Quality

| Recipe | Description |
| ----------------- | -------------------------------------------------- |
| `just check` | Run `fmt-check` + `lint-check` |
| `just fmt-check` | Check Rust and TypeScript formatting |
| `just fmt` | Auto-format Rust and TypeScript |
| `just lint-check` | Check Rust (clippy) and TypeScript (biome) linting |
| `just lint` | Lint with auto-fix |
| Recipe | Description |
| ----------------- | ------------------------------------------- |
| `just check` | Run `fmt-check` + `lint-check` |
| `just fmt-check` | Check Rust and TypeScript formatting |
| `just fmt` | Auto-format Rust and TypeScript |
| `just lint-check` | Check Rust (clippy) and TypeScript (ESLint) |
| `just lint` | Lint with auto-fix |

### Cleanup

Expand Down Expand Up @@ -259,23 +253,24 @@ just webapp-clean # also removes generated state

## Security Audit

`subscriptions` has been audited by [Cantina](https://cantina.xyz). View the [audit report](audits/report-cli-cantina-db2ffeea-c85c-4f35-b188-e861cdcd785d-solana-subscriptions.pdf).
`subscriptions` has been audited by [Cantina](https://cantina.xyz). View the [audit report](audits/report-cli-cantina-db2ffeea-c85c-4f35-b188-e861cdcd785d-solana-multi-delegator.pdf).

The external audit baseline is commit `18a50bc21c4b91ed62e612109c371f41200385e8`, and audit fixes were implemented and verified through commit `b4b0345f9fd616e1355b7b6628362283fd6b1691`.

Audit status, audited-through commit, and the current unaudited delta are tracked in [audits/AUDIT_STATUS.md](audits/AUDIT_STATUS.md).

## CI Pipeline

The GitHub Actions workflow (`.github/workflows/ci.yml`) runs on PRs and pushes to `main`:
GitHub Actions runs split workflows on PRs and pushes to `main`:

| Job | Description |
| -------------------- | ---------------------------------------------------- |
| **build** | Build program + client, upload artifacts |
| **unit-test** | `just test-program` (Rust SBF tests) |
| **lint** | `just check` (formatting + clippy + biome) |
| **integration-test** | Start Surfpool, run TypeScript integration tests |
| **benchmark** | (PRs only) Generate CU report and post as PR comment |
| Workflow | Description |
| ------------- | ---------------------------------------------------- |
| **Build** | Build program and clients |
| **Test** | Run Rust unit, Rust integration, and TS client tests |
| **Format** | Check Rust and TypeScript formatting |
| **Lint** | Check Rust clippy and TypeScript ESLint |
| **Benchmark** | Generate CU report and post it as a PR comment |
| **IDL Check** | Verify committed IDL and generated clients are fresh |

## Architecture Docs

Expand Down
5 changes: 3 additions & 2 deletions clients/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"scripts": {
"build": "tsup",
"test": "vitest run --config vitest.config.ts",
"clean": "rm -rf dist && rm -rf src/generated",
"clean": "rm -rf dist",
"clean:generated": "rm -rf src/generated",
"docs": "npx typedoc"
},
"dependencies": {
Expand All @@ -38,6 +39,6 @@
"tsup": "^8.3.0",
"tweetnacl": "^1.0.3",
"typescript": "^5.7.0",
"vitest": "^2.1.8"
"vitest": "^4.1.5"
}
}
3 changes: 0 additions & 3 deletions clients/typescript/test/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ async function createTestClient(payer: KeyPairSigner) {

type KitClient = Awaited<ReturnType<typeof createTestClient>>;

// Backward-compatible alias for requested naming.
export const getSmartWalletlist = getSmartWalletList;

export type WalletProvider = {
name: string;
createWallet(testSuite: IntegrationTest): Promise<Wallet>;
Expand Down
24 changes: 4 additions & 20 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,6 @@ program-id:
# Build recipes
# ============================================

# Check if rebuild is needed (exits 0 if rebuild needed, 1 if up-to-date)
[private]
needs-rebuild target source:
#!/usr/bin/env bash
if [[ -f "{{target}}" ]] && [[ "{{source}}" -ot "{{target}}" ]]; then
echo "✓ {{target}} is up-to-date"
exit 1
fi

# Build everything (program + clients)
build: build-program build-client

Expand Down Expand Up @@ -96,14 +87,8 @@ generate-client: generate-clients

# Build TypeScript client
build-client: generate-clients
#!/usr/bin/env bash
set -euo pipefail

if just needs-rebuild "{{ts_client_dir}}/dist/index.js" "clients/typescript/src/generated/index.ts" 2>/dev/null; then
cd {{ts_client_dir}}
pnpm run build
echo "✓ TypeScript client built"
fi
cd {{ts_client_dir}} && pnpm run build
@echo "✓ TypeScript client built"

# ============================================
# Test recipes
Expand Down Expand Up @@ -240,11 +225,10 @@ clean:
pkill -f "solana-test-validator" 2>/dev/null || true
pkill -f "surfpool" 2>/dev/null || true

echo "Cleaning program..."
echo "Cleaning program build artifacts..."
cargo clean
rm -f {{idl_file}}

echo "Cleaning client..."
echo "Cleaning client build artifacts..."
cd {{ts_client_dir}} && pnpm run clean || true
cd -

Expand Down
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"type": "module",
"private": true,
"packageManager": "pnpm@10.15.1+sha512.34e538c329b5553014ca8e8f4535997f96180a1d0f614339357449935350d924e22f8614682191264ec33d1462ac21561aff97f6bb18065351c162c7e8f6de67",
"workspaces": [
"clients/*"
],
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check .",
Expand Down Expand Up @@ -38,5 +35,14 @@
"tsx": "^4.20.5",
"typescript": "^5.9.3",
"typescript-eslint": "^8.54.0"
},
"pnpm": {
"overrides": {
"bn.js": "5.2.3",
"flatted": "3.4.2",
"minimatch": "9.0.9",
"picomatch": "4.0.4",
"rollup": "4.60.2"
}
}
}
Loading
Loading