Skip to content

feat: atas & other well known programs#83

Closed
amilz wants to merge 2 commits intocodama-idl:mainfrom
amilz:feat/well-known-programs
Closed

feat: atas & other well known programs#83
amilz wants to merge 2 commits intocodama-idl:mainfrom
amilz:feat/well-known-programs

Conversation

@amilz
Copy link
Contributor

@amilz amilz commented Mar 13, 2026

  • Auto-inject well-known programs: New SetWellKnownProgramsVisitor runs automatically in DefaultPlugin.on_root_node_set() after CombineModulesVisitor. Scans the final RootNode for ProgramLinkNode references in instruction default values and injects matching well-known programs into additional_programs if not already present. Zero config — no extra plugin, no boilerplate struct.
  • ata() shorthand directive: Simple handler for associated token PDA default values. Takes 3 positional seed values and hardcodes the fixed seed names (owner, tokenProgram, mint) and program link automatically.
  • Well-known registry: associatedToken, system, token, token2022, memo — with addresses and PDAs. Easy to extend.

Before / After

// BEFORE: 11 lines of boilerplate struct + verbose pda() syntax

#[derive(CodamaPda)]
#[codama(program(name = "associatedToken", address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"))]
#[codama(seed(name = "owner", type = public_key))]
#[codama(seed(name = "tokenProgram", type = public_key))]
#[codama(seed(name = "mint", type = public_key))]
pub struct AssociatedToken;

// ... in instruction:
#[codama(account(
    name = "vault",
    writable,
    default_value = pda("associatedToken", program = "associatedToken", [
        seed("owner", account("escrow")),
        seed("tokenProgram", account("tokenProgram")),
        seed("mint", account("mint"))
    ])
))]

// AFTER: just this

#[codama(account(
    name = "vault",
    writable,
    default_value = ata(account("escrow"), account("tokenProgram"), account("mint"))
))]

The pda(...) syntax still works if you need full control:

#[codama(account(
    name = "vault",
    writable,
    default_value = pda(
        "associatedToken",
        program = "myCustomAtaProgram",
        [
            seed("owner", account("escrow")),
            seed("tokenProgram", account("tokenProgram")),
            seed("mint", account("mint"))
        ]
    )
))]

Design decisions

  • Opted for integrating directly into DefaultPlugin rather than a standalone plugin since ATA is ubiquitous in Solana programs — adding a separate add_plugin() call for something almost everyone needs would defeat the zero-config goal.
  • ata() takes positional seed values (not named seeds) — the seed names are always owner/tokenProgram/mint for an ATA, so the shorthand hardcodes them.
  • The visitor runs after CombineModulesVisitor so it sees the fully assembled tree. It only injects programs that are (a) referenced and (b) not already present.
  • No program override on ata() — if you need a custom ATA-like program, use pda() directly. Keeps the shorthand opinionated and simple (I've never once seen anyone override ATA program).
  • The well-known registry also covers programs referenced via default_value = program("system") etc. — if a ProgramLinkNode reference exists but the program isn't in the tree, the visitor injects it with the correct address.

Test plan

  • cargo test -p codama-korok-visitors — 15 integration tests in tests/set_well_known_programs_visitor.rs (injection of each program, deduplication, unknown refs ignored, sub-instruction traversal, multiple programs, argument/extra_argument collection, additional programs)
  • cargo test -p codama-attributes — 8 inline unit tests for ata parser (positional seeds, different account names, argument seeds, mixed types, error cases)
  • cargo test -p codama-korok-plugins — plugin integration
  • Verified end-to-end against escrow program — IDL output matches expected format with auto-injected associatedToken program

LMK what you think @lorisleiva

amilz added 2 commits March 13, 2026 12:01
Add SetWellKnownProgramsVisitor that scans the final RootNode for
ProgramLinkNode references in instruction default values and auto-injects
matching well-known programs (associatedToken, system, token, token2022,
memo) into additional_programs. Runs by default in DefaultPlugin — no
extra configuration needed.

Add ata() shorthand syntax for associated token PDA default values:
  ata(account("owner"), account("tokenProgram"), account("mint"))
which expands to the equivalent PdaValueNode with fixed seed names.
Move SetWellKnownProgramsVisitor tests from inline #[cfg(test)] to
tests/set_well_known_programs_visitor.rs to match the existing pattern
where all visitor tests live in the tests/ directory.
@amilz
Copy link
Contributor Author

amilz commented Mar 20, 2026

replaced with #84

@amilz amilz closed this Mar 20, 2026
@lorisleiva
Copy link
Member

@amilz I can find some time next week to create that TokenPlugin now that the architecture is ready for it. ☺️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants