Skip to content

wallet-api: add STRK20 compute_and_invoke action - #412

Open
winsznx wants to merge 1 commit into
starkware-libs:masterfrom
winsznx:wallet-api/strk20-compute-and-invoke
Open

winsznx wants to merge 1 commit into
starkware-libs:masterfrom
winsznx:wallet-api/strk20-compute-and-invoke

Conversation

@winsznx

@winsznx winsznx commented Sep 17, 2026

Copy link
Copy Markdown

Summary

Adds STRK20_COMPUTE_AND_INVOKE_ACTION, which exposes the privacy pool's ComputeAndInvoke client action through the Wallet API.

Follow-up to starknet-io/types-js#77. @PhilippeR26 confirmed there that STRK20_ACTION in types-js mirrors this spec, so the action has to land here first.

Why

ComputeAndInvoke is the only path where the pool derives identity_key inside the proof and passes it to a contract. It's live in the deployed pool (ClientAction::ComputeAndInvoke) and has been supported by the SDK since starkware-libs/starknet-privacy#853, but STRK20_ACTION has no variant for it, so no wallet-based dapp can reach it.

invoke can't stand in for it. A contract called through invoke only sees calldata the dapp chose, so any identity it receives is whatever the dapp wrote.

Shape

Mirrors ComputeAndInvokeInput in packages/privacy/src/actions.cairo:

Pool field Spec field
contract_address contract, as in invoke
compute_additional_data compute_additional_data
invoke_additional_data invoke_additional_data

Field names are snake_case to match this file (dapp_name, collect_policy) and the pool struct. The issue proposed camelCase, and types-js will follow whatever lands here. Both arrays are optional and default to empty, which matches the pool (empty spans are accepted) and the SDK's ComputeAndInvokeDetails.

The schema description records the pool behaviour a dapp author needs. Each point is checked against main:

  • privacy_compute receives [identity_key, ...compute_additional_data] and must return a non-empty result (EMPTY_COMPUTE_RESULT)
  • privacy_invoke_with_computation receives [...compute_result, ...invoke_additional_data]
  • deposits returned by the invoke go through the same _apply_invoke_and_deposits path as invoke, so the existing open-note fill rule applies unchanged
  • at most one of invoke or compute_and_invoke per transaction (assert_and_advance_phase)

Placeholders

The open question on the issue was whether the two arrays should accept ${poolAddress} and ${openNoteIds[N]}. This PR says yes, by reusing STRK20_CALLDATA_ITEM.

invoke_additional_data needs ${openNoteIds[N]} in practice. A contract that returns capital to the user has to name the open note it deposits into, and the dapp can't know that ID when it writes the request. We hit this directly: Limen's anonymizer takes the challenge id as its only compute_additional_data item, snapshots its balance in privacy_compute, and takes the return note's ID as its only invoke_additional_data item, returning an OpenNoteDeposit for it. Three clearances on mainnet do exactly that:

Through the SDK the note ID comes from the call builder. Through the Wallet API, a placeholder is the only way to express it.

The SDK already hands the compute-and-invoke builder exactly these two values. Its callback receives InvokeCalldataBuilderArgs { openNotes, withdrawals, poolAddress }, the same args invoke gets.

Both values are known before proving. Open note IDs are fixed when the actions are assembled, and privacy_compute runs later, during proof generation, so substitution works for compute_additional_data as well. One calldata item type across all three arrays keeps the wallet's substitution logic in one place.

identity_key and compute_result need no placeholder. The pool prepends both, and the dapp can't supply either.

Open questions

  • If the wallet assembles shadow_account_invoke as an invoke-phase action, it's also mutually exclusive with compute_and_invoke. I left that out of the description because I don't know how the wallet builds it.
  • The wallet_strk20InvokeTransaction and prepare descriptions refer to "open notes filled by invoke actions". I left them alone, as feat(wallet-api): add STRK20 sub-account support #400 did, since the new action's description states the rule itself. Happy to broaden that wording if you'd rather.

Checks

  • npm run format_check and npm run check_component_uniqueness pass
  • node validate.js wallet-api/wallet_rpc.json output is identical to master
  • Validated payloads against STRK20_ACTION with ajv. Accepted: Limen's mainnet request shape (a literal challenge id plus ${openNoteIds[0]}), a request with no data arrays, ${poolAddress} in compute data, existing invoke payloads. Rejected: a missing contract, an unknown placeholder. With the new oneOf entry removed, the compute-and-invoke payload is rejected, so the test isn't passing vacuously.

Exposes the privacy pool's ComputeAndInvoke client action, the only path where
the pool derives identity_key inside the proof and passes it to a contract.
Mirrors ComputeAndInvokeInput. Calldata arrays reuse STRK20_CALLDATA_ITEM so
dapps can reference open note IDs they cannot know when writing the request.
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.

1 participant