Fix byte-array PDA seeds deriving with a Borsh length prefix - #1101
Fix byte-array PDA seeds deriving with a Borsh length prefix#1101latent-9 wants to merge 1 commit into
Conversation
A Vec<u8> instruction argument used as a PDA seed keeps its Borsh sizePrefixTypeNode(u32, bytes) type when converted from an Anchor IDL. Anchor derives byte-array seeds from the raw bytes without the length prefix, so the generated client computes a different PDA than the on-chain program. String seeds already strip the prefix; byte-array seeds were the missing case. Extend the argument-seed conversion to also recognize a size-prefixed bytes argument and emit a raw bytesTypeNode seed.
🦋 Changeset detectedLatest commit: 943692c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
OMG I'm so sorry I was cleaning up some stale branches yesterday and I think I've accidentally deleted your branch. How rude of me. Let me just triage this with the AI reviewer first before I trouble you again. 🙏 |
trevor-cortex
left a comment
There was a problem hiding this comment.
Summary
Fixes PDA derivation for Vec<u8> instruction arguments used as seeds in Anchor v01 IDLs. Anchor derives byte-array seeds from the raw bytes, but the converted argument type kept its Borsh sizePrefixTypeNode(u32, bytesTypeNode()) encoding, so generated clients computed a different PDA than the on-chain program. The fix mirrors the existing isBorshString special case with an isBorshBytes counterpart that emits a raw bytesTypeNode() seed.
This is correct: bytes in an Anchor IDL is the Borsh encoding of Vec<u8> (u32 length prefix + data), while create_program_address receives the unprefixed slice via AsRef<[u8]>. Fixed-size arrays ([u8; N]) are unaffected since they carry no prefix, so this closes out the remaining variable-length case alongside strings.
Notes
- The new test mirrors the existing string-prefix test one-to-one, and the changeset is a patch bump on the independently-versioned
@codama/nodes-from-anchor, starting with a verb per CONTRIBUTING — all consistent with repo conventions. - Behavior note for anyone tracking downstream impact: any client currently generated from an IDL with a
Vec<u8>seed will start deriving a different (now correct) PDA after this fix. That's the point of the fix, but worth remembering if a consumer somehow depended on the old, wrong derivation. - This touches the same
argbranch as #990 (nested seed path resolution), so whichever lands second will need a trivial rebase. The two changes are logically independent. - Optional refactor, not blocking:
isBorshStringandisBorshBytesshare thesizePrefixTypeNode+ u32 prefix checks; a small helper likeisBorshSizePrefixed(type, innerKind)could collapse the duplication if this pattern grows a third case.
|
Let me know if you're happy to resubmit (again so sorry) otherwise I'm happy to re-open a similar PR a bit later if you'd rather not. |
|
Please re-open, happy to let you handle it. |
Problem
A
Vec<u8>instruction argument used as a PDA seed keeps its BorshsizePrefixTypeNode(u32, bytesTypeNode())type when converted from an Anchor IDL. Anchor derives byte-array seeds from the raw bytes without the length prefix, so the generated client computes a different PDA than the on-chain program.Minimal reproduction of the derivation difference, for seed data
[1, 2, 3, 4, 5]:create_program_address(&[seed], program)):CREFgTpumervLBfVvvuLx6w2yvgYCGGiXwcoozu22VHK3mS84rEyJwNSpaYHeJN9umbi4FPZ94pkUg4Wv5hPBJ1sStringseeds already strip the prefix (see theisBorshStringcheck); byte-array seeds were the missing case.Change
Extend the argument-seed conversion in
pdaSeedNodeFromAnchorV01to also recognize a Borsh size-prefixedbytesargument and emit a rawbytesTypeNodeseed, matching the on-chain derivation.Tests
Adds
it removes the bytes prefix from arg Anchor seeds, mirroring the existing string-prefix test. The full@codama/nodes-from-anchorsuite passes.Note
This is complementary to #990, which resolves nested seed paths in the same function. That PR does not change the byte-array seed behavior addressed here.