feat: preserve richer IDL metadata in stack specs#116
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR extends the IDL metadata preserved in Arete stack specs: it adds Codama PDA resolution (inline and link-resolved), fielded enum variants (struct and tuple payload shapes), optional account tracking, and the
Confidence Score: 5/5Safe to merge; all changes are additive, old specs deserialize unchanged, and every new PDA degradation path logs a warning and returns None rather than producing wrong data. The core IDL parsing changes are well-tested with four new integration-level tests covering PDA link nodes, inline PDAs, optional accounts, fielded enums, and the isSigner 'either' flag. The backward-compat strategy (COMPATIBLE_AST_VERSIONS + skip_serializing_if on the new fields) ensures existing stack.json files continue to load and round-trip correctly. The sign-extension logic in codama_constant_seed_bytes was verified to handle positive, negative, and overflow cases correctly. The two findings raised are both non-blocking nits. arete-idl/src/parse.rs is the largest change and deserves the closest read; in particular codama_constant_seed_bytes numeric encoding and the codama_account_pda degradation paths. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Caller
participant parse as parse_idl_content
participant root as codama_root_to_idl_spec
participant ix as codama_instruction_to_idl
participant pda as codama_account_pda
participant seed as codama_constant_seed_bytes
Caller->>parse: parse_idl_content(json)
parse->>parse: try serde IdlSpec
alt not IdlSpec
parse->>parse: try serde CodamaRoot
parse->>root: "codama_root_to_idl_spec(&root)"
root->>root: build pda_defs HashMap
loop each instruction
root->>ix: "codama_instruction_to_idl(instr, &pda_defs)"
loop each account
ix->>pda: codama_account_pda(account, pda_defs)
alt pdaValueNode with pdaLinkNode
pda->>pda: lookup pda_defs[name]
else inline pdaNode
pda->>pda: use inline seeds
end
loop each constantPdaSeedNode
pda->>seed: codama_constant_seed_bytes(value, seed_type)
seed-->>pda: "Vec<u8> or None"
end
pda-->>ix: Some(IdlPda) or None
end
ix-->>root: IdlInstruction
end
root-->>parse: IdlSpec
end
parse-->>Caller: "Result<IdlSpec, String>"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Caller
participant parse as parse_idl_content
participant root as codama_root_to_idl_spec
participant ix as codama_instruction_to_idl
participant pda as codama_account_pda
participant seed as codama_constant_seed_bytes
Caller->>parse: parse_idl_content(json)
parse->>parse: try serde IdlSpec
alt not IdlSpec
parse->>parse: try serde CodamaRoot
parse->>root: "codama_root_to_idl_spec(&root)"
root->>root: build pda_defs HashMap
loop each instruction
root->>ix: "codama_instruction_to_idl(instr, &pda_defs)"
loop each account
ix->>pda: codama_account_pda(account, pda_defs)
alt pdaValueNode with pdaLinkNode
pda->>pda: lookup pda_defs[name]
else inline pdaNode
pda->>pda: use inline seeds
end
loop each constantPdaSeedNode
pda->>seed: codama_constant_seed_bytes(value, seed_type)
seed-->>pda: "Vec<u8> or None"
end
pda-->>ix: Some(IdlPda) or None
end
ix-->>root: IdlInstruction
end
root-->>parse: IdlSpec
end
parse-->>Caller: "Result<IdlSpec, String>"
Reviews (4): Last reviewed commit: "fix(arete-a4-sdk): stabilize auth_lifecy..." | Re-trigger Greptile |
CodamaValueNode::Number was u64, so any Codama IDL carrying a negative
constant seed value (e.g. {"number":-1} for an i8 seed) hit a hard
serde_json deserialization error that aborted the entire instruction
parse — the #[serde(other)] arm only catches unknown kind strings, not
a failed inner deserialization.
Switch the field to i64 (covers all signed/unsigned widths a single
numeric PDA-seed literal can carry) and make codama_constant_seed_bytes
sign-extension-aware: the truncation guard now accepts valid negative
values like -1_i8 (0xFF sign-extended) and rejects genuine overflow,
while widening (e.g. i64 literal into an i128 slot) sign-extends
instead of zero-padding.
SteelDiscriminant.value stays u64; the call site now uses
u64::try_from with a clear error for negatives, preserving the
non-negative discriminant invariant previously enforced by the hard
serde failure.
CodamaSignerFlag::Tag caught any string that wasn't true/false, but is_either() only recognised "either" — any other tag value (e.g. a future Codama extension like "readonly") resolved to is_signer=false with no doc annotation and no error, silently producing incorrect signer behaviour. Add unknown_tag() returning any tag other than "either", and emit a doc annotation (signer: "<tag>" unrecognised isSigner tag; treated as non-signer) so callers can see why an account was treated as a non-signer instead of getting incorrect behaviour with no indication.
codama_account_pda returned None for a range of conditions (unknown pdaLinkNode name, unsupported seed kind, numeric type mismatch, missing binding) — all silently degrading the account to UserProvided. An incorrectly-structured Codama IDL would produce a stack spec that looked valid but omitted PDA derivation data, with no way to tell why a known PDA was not being resolved without inspecting source code. Add tracing::debug! for the benign no-PDA-default path and tracing::warn! at each genuine resolution failure (unknown link, missing binding, unsupported seed kind, unencodable constant), keyed on account and seed names so a mis-structured IDL is diagnosable from logs.
The first token's expiry sat only 1s past the refresh buffer, so the `set_token` "is expiring" check tripped whenever a loaded CI runner introduced >1s between the token endpoint issuing the token and the SDK validating it. Bump the first expiry to 75s (15s headroom) and the refresh-wait timeout to 20s to match the resulting ~15s refresh delay.
No description provided.