Skip to content

Add clear-signing display directives to the interface - #494

Merged
lorisleiva merged 2 commits into
mainfrom
loris/clear-signing-displays
Aug 14, 2026
Merged

Add clear-signing display directives to the interface#494
lorisleiva merged 2 commits into
mainfrom
loris/clear-signing-displays

Conversation

@lorisleiva

Copy link
Copy Markdown
Member

This PR annotates all 17 active stake instructions with clear-signing display metadata, using the display directives introduced in codama 0.11.0, and regenerates the IDL and clients.

  • Intents and interpolated sentences for every instruction (e.g. Withdraw ${data.args} from ${accounts.stake} to ${accounts.recipient}); the four lamport arguments (split, withdraw, moveStake, moveLamports) render as SOL (Amount: 2.5 SOL).
  • Struct-typed tuple args (initialize, setLockup*, authorize*WithSeed) are flattened into the fallback list, with field labels authored on the target types (Locked Until, Authority Type, New Authority, …) so account-state rendering benefits too.
  • The unixTimestamp fields carry labels in Rust; the date-time display lives on the unixTimestamp alias in codama.mjs, where the alias is created. Account-state extras: SOL displays on rentExemptReserve and delegation.stake, _reserved hidden.
  • Sysvars, the unused account, and discriminators are hidden from the fallback list; renames follow the conventions of the other annotated programs (From/To, Stake Account, Base Key, …).
  • Bumps codama/codama-macros to 0.11.0, JS codama to ^1.10.1, and @codama/renderers-rust to ^3.1.3 (its bundled visitors crash on the new IDL otherwise). Two small codama.mjs guards compensate for empty child arrays now being omitted from the generated IDL; the remaining renderer template gap is tracked upstream.

Note on the regenerated Rust client diffs: the changes to the 17 generated instruction files come from the renderers-rust 3.1.0 → 3.1.3 bump, not from the display work (display metadata does not affect client codegen — the JS client output is byte-identical). In particular, renderers-rust 3.1.1 (renderers-rust#82) fixed swapped is_writable/is_signer flags on remaining accounts in the CPI builders, which means the currently published solana-stake-client sets those flags incorrectly for callers of invoke_with_remaining_accounts / invoke_signed_with_remaining_accounts. This PR picks up that fix; a patch release of the Rust client may be worth cutting after merge.

Verified with cargo check --features codama, clippy, fmt, the interface test suite (63 tests), compilation of the regenerated Rust client, and by rendering every instruction end-to-end through @codama/dynamic-instructions 0.4.0.

This PR annotates all 17 active stake instructions with clear-signing display metadata, using the display directives introduced in codama 0.11.0, and regenerates the IDL and clients.

- Intents and interpolated sentences for every instruction (e.g. `Withdraw ${data.args} from ${accounts.stake} to ${accounts.recipient}`); the four lamport arguments (`split`, `withdraw`, `moveStake`, `moveLamports`) render as SOL (`Amount: 2.5 SOL`).
- Struct-typed tuple args (`initialize`, `setLockup*`, `authorize*WithSeed`) are flattened into the fallback list, with field labels authored on the target types (`Locked Until`, `Authority Type`, `New Authority`, …) so account-state rendering benefits too.
- The `unixTimestamp` fields carry labels in Rust; the date-time display lives on the `unixTimestamp` alias in `codama.mjs`, where the alias is created. Account-state extras: SOL displays on `rentExemptReserve` and `delegation.stake`, `_reserved` hidden.
- Sysvars, the `unused` account, and discriminators are hidden from the fallback list; renames follow the conventions of the other annotated programs (`From`/`To`, `Stake Account`, `Base Key`, …).
- Bumps `codama`/`codama-macros` to 0.11.0, JS `codama` to ^1.10.1, and `@codama/renderers-rust` to ^3.1.3 (its bundled visitors crash on the new IDL otherwise). Two small `codama.mjs` guards compensate for empty child arrays now being omitted from the generated IDL; the remaining renderer template gap is tracked upstream.

**Note on the regenerated Rust client diffs**: the changes to the 17 generated instruction files come from the renderers-rust 3.1.0 → 3.1.3 bump, not from the display work (display metadata does not affect client codegen — the JS client output is byte-identical). In particular, renderers-rust 3.1.1 ([renderers-rust#82](codama-idl/renderers-rust#82)) fixed swapped `is_writable`/`is_signer` flags on remaining accounts in the CPI builders, which means the currently published `solana-stake-client` sets those flags incorrectly for callers of `invoke_with_remaining_accounts` / `invoke_signed_with_remaining_accounts`. This PR picks up that fix; a patch release of the Rust client may be worth cutting after merge.

Verified with `cargo check --features codama`, clippy, fmt, the interface test suite (63 tests), compilation of the regenerated Rust client, and by rendering every instruction end-to-end through `@codama/dynamic-instructions` 0.4.0.
@lorisleiva

lorisleiva commented Aug 14, 2026

Copy link
Copy Markdown
Member Author

Rendered output for review

To make this JSON diff easier to review, every instruction below is rendered end-to-end through @codama/dynamic-instructions#getInstructionDisplay using synthetic sample data. Each collapsed line shows the interpolated intent at a glance (addresses abridged); expand for the full render showing both presentation modes a wallet chooses between — the interpolated sentence, or the intent-with-fields fallback screen. Address formatting (truncation, .sol names, token symbols) is left to the consuming wallet, so raw base58 appears in the full renders.

Note: rendered from the IDL after the codama.mjs visitors, since the raw idl.json links UnixTimestamp/Epoch to aliases that are only added there — including the unixTimestamp date-time display shown in the lockup fields.

initialize — Initialize stake account 7dHbW…7ARj
Interpolated intent:
│ Initialize stake account 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Initialize stake account
│   Staker: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
│   Withdrawer: HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH
│   Locked Until: 2026-08-06T07:06:40.000Z
│   Locked Until Epoch: 750
│   Custodian: 6QuXb6mB6WmRASP2y8AavXh6aabBXEH5ZzrSH5xRrgSm
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
authorize (staker) — Set the Staker authority of 7dHbW…7ARj to 3Wnd5…PxJX
Interpolated intent:
│ Set the Staker authority of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX

Intent + fields (fallback):
│ Update stake authority
│   New Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Authority Type: Staker
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
authorize (withdrawer) — Set the Withdrawer authority of 7dHbW…7ARj to 3Wnd5…PxJX
Interpolated intent:
│ Set the Withdrawer authority of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX

Intent + fields (fallback):
│ Update stake authority
│   New Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Authority Type: Withdrawer
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
delegateStake — Delegate 7dHbW…7ARj to vote account HN7cA…YWrH
Interpolated intent:
│ Delegate 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to vote account HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH

Intent + fields (fallback):
│ Delegate stake
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Vote Account: HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
split — Split 2.5 SOL from 7dHbW…7ARj into BPFLo…1111
Interpolated intent:
│ Split 2.5 SOL from 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj into BPFLoaderUpgradeab1e11111111111111111111111

Intent + fields (fallback):
│ Split stake
│   Amount: 2.5 SOL
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   New Stake Account: BPFLoaderUpgradeab1e11111111111111111111111
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
withdraw — Withdraw 2.5 SOL from 7dHbW…7ARj to DRpbC…21hy
Interpolated intent:
│ Withdraw 2.5 SOL from 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC86PZ8okm21hy

Intent + fields (fallback):
│ Withdraw stake
│   Amount: 2.5 SOL
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Recipient: DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC86PZ8okm21hy
│   Withdraw Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
deactivate — Deactivate 7dHbW…7ARj
Interpolated intent:
│ Deactivate 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Deactivate stake
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
setLockup — Update the lockup of 7dHbW…7ARj
Interpolated intent:
│ Update the lockup of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Set stake lockup
│   Locked Until: 2026-08-06T07:06:40.000Z
│   Locked Until Epoch: 750
│   Custodian: 6QuXb6mB6WmRASP2y8AavXh6aabBXEH5ZzrSH5xRrgSm
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
merge — Merge CiDwV…AQz3 into 4Nd1m…DB4T
Interpolated intent:
│ Merge CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3 into 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T

Intent + fields (fallback):
│ Merge stake accounts
│   To: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
│   From: CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
authorizeWithSeed — Change an authority of 7dHbW…7ARj
Interpolated intent:
│ Change an authority of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Update stake authority
│   New Authority: BPFLoaderUpgradeab1e11111111111111111111111
│   Authority Type: Withdrawer
│   Authority Seed: example authoritySeed
│   Authority Owner: DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC86PZ8okm21hy
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Base Key: BPFLoaderUpgradeab1e11111111111111111111111
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
initializeChecked — Initialize stake account 7dHbW…7ARj
Interpolated intent:
│ Initialize stake account 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Initialize stake account
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
│   Withdraw Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
authorizeChecked (staker) — Set the Staker authority of 7dHbW…7ARj to 3Wnd5…PxJX
Interpolated intent:
│ Set the Staker authority of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX

Intent + fields (fallback):
│ Update stake authority
│   Authority Type: Staker
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   New Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
authorizeChecked (withdrawer) — Set the Withdrawer authority of 7dHbW…7ARj to 3Wnd5…PxJX
Interpolated intent:
│ Set the Withdrawer authority of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX

Intent + fields (fallback):
│ Update stake authority
│   Authority Type: Withdrawer
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   New Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
authorizeCheckedWithSeed — Set an authority of 7dHbW…7ARj to 3Wnd5…PxJX
Interpolated intent:
│ Set an authority of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj to 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX

Intent + fields (fallback):
│ Update stake authority
│   Authority Type: Withdrawer
│   Authority Seed: example authoritySeed
│   Authority Owner: DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC86PZ8okm21hy
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Base Key: BPFLoaderUpgradeab1e11111111111111111111111
│   New Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   Lockup Authority: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS
setLockupChecked — Update the lockup of 7dHbW…7ARj
Interpolated intent:
│ Update the lockup of 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Set stake lockup
│   Locked Until: 2026-08-06T07:06:40.000Z
│   Locked Until Epoch: 750
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
│   New Authority: 3Wnd5Df69KitZfUoPYZU438eFRNwGHkhLnSAWL65PxJX
getMinimumDelegation(fallback only) Get minimum stake delegation
Intent + fields:
│ Get minimum stake delegation
deactivateDelinquent — Deactivate delinquent stake 7dHbW…7ARj
Interpolated intent:
│ Deactivate delinquent stake 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj

Intent + fields (fallback):
│ Deactivate delinquent stake
│   Stake Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
│   Delinquent Vote Account: 6QuXb6mB6WmRASP2y8AavXh6aabBXEH5ZzrSH5xRrgSm
│   Reference Vote Account: 7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj
moveStake — Move 2.5 SOL of active stake from CiDwV…AQz3 to 4Nd1m…DB4T
Interpolated intent:
│ Move 2.5 SOL of active stake from CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3 to 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T

Intent + fields (fallback):
│ Move stake
│   Amount: 2.5 SOL
│   From: CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3
│   To: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
moveLamports — Move 2.5 SOL from CiDwV…AQz3 to 4Nd1m…DB4T
Interpolated intent:
│ Move 2.5 SOL from CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3 to 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T

Intent + fields (fallback):
│ Move unstaked SOL
│   Amount: 2.5 SOL
│   From: CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3
│   To: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T
│   Stake Authority: 4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T

@lorisleiva
lorisleiva requested a review from joncinque August 14, 2026 10:58
joncinque
joncinque previously approved these changes Aug 14, 2026

@joncinque joncinque left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good! For the set-authority variants, is it possible to include what kind of authority it is? ie have "Set stake authority..." and "Set withdrawal authority..."?

Review feedback on #494: the interpolated intents for authorize and
authorizeChecked now render the StakeAuthorize variant, e.g. "Set the
Withdrawer authority of ... to ...", instead of the generic "Set an
authority of ...". Enum placeholders resolve through the variant's
display label since @codama/dynamic-instructions 0.4.0.

The authorizeWithSeed and authorizeCheckedWithSeed sentences are
unchanged: their StakeAuthorize sits inside the args struct and
interpolation placeholders do not support nested paths yet; their
fallback field lists still carry the Authority Type field.

Clients are unaffected (display metadata does not drive codegen).

@joncinque joncinque left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks great, thanks!

@lorisleiva

Copy link
Copy Markdown
Member Author

Good shout for the authority type, I couldn't do it with the two *WithSeed variants because the authority type is nested inside a sub-struct and the standard doesn't support that yet but I made a note of that.

@lorisleiva
lorisleiva merged commit 5f22394 into main Aug 14, 2026
25 checks passed
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