anchor-029-to-030
Automate 80%+ of the Anchor 0.29 → 0.30 migration for Solana Rust programs. Updates Cargo.toml dependencies, fixes Rust API breaking changes, and migrates TypeScript client code.
# Anchor v0.29 → v0.30 Codemod
Automated migration tool for upgrading Solana Anchor projects from v0.29 to v0.30.
Built with [ast-grep](https://ast-grep.github.io/) (sg/jssg engine) + Codemod workflow.
Submitted to the [Boring AI Hackathon](https://dorahacks.io/hackathon/boring-ai/detail) on DoraHacks.
## Quick Start
```bash
# Install ast-grep (jssg engine)
cargo install ast-grep
# Navigate to your Anchor 0.29 project
cd /path/to/your-anchor-project
# Preview changes (dry run)
sg scan --config /path/to/anchor-029-to-030-codemod/sgconfig.yml .
# Apply changes
sg scan --apply --config /path/to/anchor-029-to-030-codemod/sgconfig.yml .
# Migrate all Cargo.toml files under current directory (safe mode)
# No-arg mode: uses `rg` when installed; otherwise uses `find` (skips ./target and ./.git)
# Safe mode default: does NOT force `idl-build` feature on anchor-lang
bash /path/to/anchor-029-to-030-codemod/migrate-cargo.sh
# Or migrate one specific Cargo.toml
bash /path/to/anchor-029-to-030-codemod/migrate-cargo.sh programs/your-program/Cargo.toml
# Optional aggressive mode: force add `idl-build` on anchor-lang
bash /path/to/anchor-029-to-030-codemod/migrate-cargo.sh --with-idl-build programs/your-program/Cargo.toml
# Format after migration
cargo fmt --all
```
**Version note:** this codemod upgrades on-chain crates to **`anchor-lang` / `anchor-spl` `0.30.1`**, which matches the commonly installed **`anchor-cli 0.30.1`** patch line and avoids patch-mismatch warnings.
## Migration Coverage
Covers all **23 breaking changes** from the official Anchor **0.30.0** changelog (release notes); `migrate-cargo.sh` pins **`anchor-lang` / `anchor-spl` `0.30.1`** to match common `anchor-cli 0.30.1` installs:
### Automation Boundary (for evaluation)
| Layer | What it handles | Evaluation claim |
|------|------------------|------------------|
| Deterministic rules/scripts | Well-scoped mechanical rewrites only | **Primary automation claim** (safety first) |
| AI step | Edge cases, project-specific cleanup, semantic decisions | Coverage extension, not counted as deterministic fix |
| Manual follow-up | Rare repo-specific dependency/build reconciliation | Explicitly tracked in validation notes |
Current practical claim:
- **Deterministic auto-fix:** 6 high-confidence migration classes
- **AI-assisted coverage:** 11 classes
- **Reminder/separate handling:** 6 classes
- **Overall workflow automation target:** 80%+ with deterministic + AI pipeline
### Auto-fixed (6 items)
| Change | Rule / Script |
|--------|--------------|
| `ctx.bumps.get("x").unwrap()` → `.copied()` | `anchor-bumps-option-type.yml` |
| `AnchorProvider(conn, wallet, {})` → 2 args | `anchor-ts-provider-init.yml` |
| `new Program(idl, programId[/PROGRAM_ID][, provider])` migration | `anchor-ts-program-id-arg-*` (4 scoped Program rules) |
| `anchor-lang = "0.29.x"` → `0.30.1` (optional `--with-idl-build`) | `migrate-cargo.sh` |
| `anchor-spl = "0.29.x"` → `0.30.1` | `migrate-cargo.sh` |
| Remove `idl-parse` / `seeds` features + add `overflow-checks` | `migrate-cargo.sh` |
### Marked for AI review (11 items)
| Change | Rule / Handler |
|--------|---------------|
| `anchor_spl::shared_memory` removed | `anchor-remove-shared-memory.yml` (TODO) |
| `CLOSED_ACCOUNT_DISCRIMINATOR` removed | `anchor-remove-closed-account-discriminator.yml` (warning) |
| `anchor_syn::idl` → `anchor_lang_idl` imports | `anchor-idl-import-path.yml` (TODO) |
| Optional account bump types `u8` → `Option<u8>` | AI step |
| IDL enums `#[non_exhaustive]` | AI step |
| `accounts()` no longer accepts resolvable accounts | `anchor-ts-auto-accounts-system-program`, `anchor-ts-auto-accounts-clock`, `anchor-ts-auto-accounts-rent`, `anchor-ts-auto-accounts-token-program` |
| camelCase method names | AI step |
| Remove discriminator functions | AI step |
| Remove `associated` / `associatedAddress` methods | AI step |
| Remove `anchor-deprecated-state` feature | AI step |
| `anchor-syn` features removed | AI step |
### Zero-FP Guardrails
- `Program` constructor rewrite is now **strictly scoped** to explicit `programId`/`PROGRAM_ID` forms (2-arg and 3-arg with provider); it does not rewrite arbitrary argument forms.
- `.accounts()` migration rules are scoped to explicit `.accounts({...})` calls only; non-`.accounts()` object arguments are ignored.
- Cargo feature cleanup only edits `anchor-lang` / `anchor-syn` dependency lines (no global string replacement across unrelated crates).
### CLI reminders (4 items)
| Change | Handler |
|--------|---------|
| `build-bpf` → `build-sbf` | AI step prompt |
| `idl upgrade` closes buffer | AI step prompt |
| Remove `--jest` option | AI step prompt |
| Solana upgraded to 1.18.8 | AI step prompt |
### Separate codemod (2 items)
| Change | Handler |
|--------|---------|
| IDL v0 → v1 schema migration | Tracked as separate codemod |
| `anchor-syn` idl-parse/seeds removal | AI step + Cargo.toml sed (anchor-lang/anchor-syn lines) |
## Project Structure
```
anchor-029-to-030-codemod/
├── codemod.yaml # Codemod Registry package metadata
├── workflow.yaml # workflow: 多段 YAML ast-grep(rules/*.yml)→ Cargo 脚本 → AI → fmt
├── sgconfig.yml # ast-grep root config: ruleDirs → rules/
├── migrate-cargo.sh # Cargo.toml dependency migration script
├── CLAUDE.md # AI-readable project documentation
├── 需求文档.md # Chinese requirements document
├── README.md # This file
│
├── rules/ # ast-grep YAML rules (5 files, 13 rules)
│ ├── anchor-bumps-option-type.yml
│ ├── anchor-idl-import-path.yml
│ ├── anchor-remove-shared-memory.yml
│ ├── anchor-remove-closed-account-discriminator.yml
│ └── anchor-ts-provider-init.yml # 9 rules: provider, 4 Program variants, 4 auto-accounts variants
│
└── test-fixtures/ # Test fixtures for rule validation
├── old_program.rs # Rust 0.29 patterns
└── old_program.ts # TypeScript 0.29 patterns + false-positive tests
```
## Testing
### Synthetic fixtures
```bash
export PATH="$HOME/.cargo/bin:$PATH"
# Scan Rust fixtures
sg scan --config sgconfig.yml test-fixtures/old_program.rs
# Scan TypeScript fixtures
sg scan --config sgconfig.yml test-fixtures/old_program.ts
```
### Real-world projects (validated)
| Project | Git | Dry-run | Apply | Build | Notes |
|---------|-----|---------|-------|-------|-------|
| Anchor official `v0.29.0` (framework mono-repo) | https://github.com/solana-foundation/anchor/tree/v0.29.0 | PASS | PASS | FAIL | Workflow works, but this repo is Anchor framework source (not a typical target program repo), so build failures are not used as codemod success criteria. |
| `solana-presale-smart-contract` | https://github.com/rustjesty/solana-presale-smart-contract | PASS | PASS | PASS (`anchor build --no-idl`) | Required post-migration dependency cleanup in target repo: remove hard-pinned legacy deps and align to Anchor 0.30 dependency graph. |
Validation date: `2026-05-01 (UTC+8)`
Command shape used in both real repos:
```bash
ROOT="$(pwd)"
npx codemod workflow run -w /path/to/anchor-029-to-030-codemod/workflow.yaml \
-t "$ROOT" --param "target=$ROOT" \
--dry-run --no-interactive --allow-dirty --allow-fs --allow-child-process
```
### Local verification in this repository
Verified in this repo (2026-04-30):
- `npx codemod workflow validate -w workflow.yaml` passed
- `npx codemod workflow run -w workflow.yaml -t <fixture> --param target=<fixture> --dry-run` passed (ast-grep steps + workflow wiring)
- `sg scan --config sgconfig.yml test-fixtures/old_program.rs` matched expected Rust patterns
- `sg scan --config sgconfig.yml test-fixtures/old_program.ts` matched expected TypeScript patterns
For reproducible real-repo evidence recording, use local template: `REAL_WORLD_VALIDATION_TEMPLATE.md`.
### Safety vs Coverage Modes
- **Safe mode (default script behavior):** prioritizes lower false-positive risk; does not force `idl-build`.
- **Coverage mode (workflow default):** `workflow.yaml` runs `migrate-cargo.sh --with-idl-build` to align with Anchor 0.30 breaking requirement around IDL build.
## Using the Full Workflow
If you have the Codemod CLI installed:
```bash
npx codemod workflow validate -w workflow.yaml
npx codemod workflow run -w workflow.yaml -t /path/to/anchor-project --param target=/path/to/anchor-project --dry-run
npx codemod workflow run -w workflow.yaml -t /path/to/anchor-project --param target=/path/to/anchor-project
```
Notes:
- **YAML `ast-grep` steps** expect `config_file` to point at **rule YAML** (each rule has a top-level `id`). That is what lives under `rules/`. Do not point `config_file` at `sgconfig.yml` (that file uses `ruleDirs` and will fail Codemod parsing with `missing field id`).
- **Shell steps** (`migrate-cargo.sh`, `cargo fmt`) run with the host working directory, not `-t`. Pass the same Anchor repo path for `-t` and `--param target=...` so Cargo steps execute inside the project being migrated.
## Hackathon
- **Category**: Production-grade Migration Recipes (XL tier)
- **Pre-approved**: Anchor v0.29 → v0.30 Rust API changes — Changelog
- **Coverage**: 23/23 breaking changes mapped (6 deterministic auto-fix + 11 AI-assisted + 6 reminders/separate handling)
- **False-positive policy**: deterministic rules are intentionally narrow; zero-FP target applies to deterministic transforms (AI/manual layer handles ambiguous cases)
### Evaluator Notes
- Deterministic transforms are intentionally conservative to minimize false positives on real repositories.
- Ambiguous or project-specific migration cases are explicitly delegated to the AI/manual layer instead of risky auto-rewrites.
- Workflow execution is reproducible on real open-source repos with documented dry-run/apply/build evidence.
- Safety-first defaults are provided for scripts, while workflow mode enables stronger breaking-change coverage when required.
## License
MIT