Skip to content

Resolve nested seed paths in v01 PDA extraction#990

Open
ioxde wants to merge 7 commits into
codama-idl:mainfrom
ioxde:nested-pda-seeds
Open

Resolve nested seed paths in v01 PDA extraction#990
ioxde wants to merge 7 commits into
codama-idl:mainfrom
ioxde:nested-pda-seeds

Conversation

@ioxde
Copy link
Copy Markdown

@ioxde ioxde commented Apr 9, 2026

This is a direct follow-up to #984 which left the nested path handling as a TODO.

PDA seeds with nested paths like mint.authority or args.owner were skipped. This PR resolves them by looking up the field type from IDL type definitions.

{ kind: 'account', path: 'mint.authority' } + a Mint type def with authority: pubkey -> variablePdaSeedNode('mintAuthority', publicKeyTypeNode())

{ kind: 'arg', path: 'args.owner' } where args is a struct with owner: pubkey -> variablePdaSeedNode('owner', publicKeyTypeNode())

Program seeds with nested paths still skip (with a warning). pdaSeedNodeFromAnchorV01 can now return undefined.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 9, 2026

🦋 Changeset detected

Latest commit: 48b8986

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@codama/nodes-from-anchor Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ioxde ioxde force-pushed the nested-pda-seeds branch 2 times, most recently from 4902b1e to 60bfce9 Compare April 12, 2026 23:31
@lorisleiva
Copy link
Copy Markdown
Member

@trevor-cortex

Copy link
Copy Markdown

@trevor-cortex trevor-cortex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR resolves nested seed paths (e.g. mint.authority, args.owner) in v01 PDA extraction, which were previously left as a TODO and silently skipped. It introduces a resolveNestedFieldType helper that walks struct fields (inline or via IDL type definitions) to determine the leaf type. The function pdaSeedNodeFromAnchorV01 can now return undefined when resolution fails, and callers handle this gracefully by skipping the PDA default value.

Additionally, the PR adds self-referential seed detection — if a seed references the account being derived, the PDA default is skipped with a warning.

Key things to watch

  1. Breaking return type change: pdaSeedNodeFromAnchorV01 now returns | undefined. This is a well-handled breaking change internally — all call sites check for undefined — but any external consumers of this export would need updating.

  2. Self-referential detection: The new self-referential check (lines 131–138 in InstructionAccountNode.ts) correctly catches cases like vault referencing itself, and nested paths like guard.mint where the account name matches the seed's account reference. The test for my_guard with path: 'my_guard.mint' is a good edge case.

  3. Nested program paths: Program seeds with nested paths are still explicitly skipped with a warning — this is a reasonable incremental choice since program seeds with nested paths are rare.

Notes for subsequent reviewers

  • The resolveNestedFieldType helper only handles structTypeNode and definedTypeLinkNode. Other wrappers (e.g. optionTypeNode) would fall through and return undefined. This seems fine for now — real-world IDL seeds shouldn't reference optional fields — but worth keeping in mind.
  • The InstructionNode.test.ts change for the distribution account is interesting: it confirms the self-referential detection works at the integration level (the account distribution has a seed path: 'distribution.group_mint' referencing itself, so the PDA default is correctly omitted).
  • Test coverage is thorough: nested account paths, nested arg paths, unresolvable types, self-referential accounts, prefixed nested groups, and program seed edge cases are all covered.

Comment thread packages/nodes-from-anchor/src/v01/PdaSeedNode.ts
Comment thread packages/nodes-from-anchor/src/v01/InstructionAccountNode.ts Outdated
Comment thread packages/nodes-from-anchor/test/v01/InstructionAccountNode.test.ts
Comment thread packages/nodes-from-anchor/test/v01/InstructionAccountNode.test.ts
Comment thread packages/nodes-from-anchor/src/v01/ProgramNode.ts Outdated
Comment thread packages/nodes-from-anchor/src/v01/InstructionAccountNode.ts
Comment thread packages/nodes-from-anchor/src/v01/PdaSeedNode.ts
Comment thread packages/nodes-from-anchor/src/v01/PdaSeedNode.ts
Comment thread packages/nodes-from-anchor/src/v01/PdaSeedNode.ts Outdated
Comment thread packages/nodes-from-anchor/src/v01/PdaSeedNode.ts Outdated
Comment thread packages/nodes-from-anchor/test/v01/InstructionNode.test.ts
Comment thread packages/nodes-from-anchor/test/v01/pdaSeedNode.test.ts Outdated
@ioxde ioxde force-pushed the nested-pda-seeds branch from 60bfce9 to 2702c2c Compare April 14, 2026 23:58
* found while rebasing onto main
@ioxde ioxde force-pushed the nested-pda-seeds branch from 2702c2c to a37264c Compare April 15, 2026 00:04
@ioxde
Copy link
Copy Markdown
Author

ioxde commented Apr 15, 2026

I think I addressed all comments outside of the logWarn vs throw question. Let me know if you have any other questions / concerns.

Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for all the changes and sorry for the late re-review.

Just one last little thing that caught my attention and after that this is good to go. Thank you for your patience. 🙏

Comment on lines +147 to +148
expect(nodes?.definition).toEqual(variablePdaSeedNode('0Bar', numberTypeNode('u8')));
expect(nodes?.value).toEqual(pdaSeedValueNode('0Bar', argumentValueNode('0Bar')));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This worries me a bit because most languages will refuse to render a variable that starts with a numerical value. I wonder if we should just use the whole path as the seed name. So here it would become foo0Bar. That way, it would technically not be possible for a variable to start with a number because we always start with the array of InstructionArgumentNodes.

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.

3 participants