Skip to content

feat: typed instruction construction & execution pipeline (IDL → codegen → SDK → adapters)#115

Draft
adiman9 wants to merge 5 commits into
mainfrom
tx-construction
Draft

feat: typed instruction construction & execution pipeline (IDL → codegen → SDK → adapters)#115
adiman9 wants to merge 5 commits into
mainfrom
tx-construction

Conversation

@adiman9

@adiman9 adiman9 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

End-to-end typed instruction construction & execution: round-trip an Anchor/Steel IDL all the way from a stack spec through codegen into a callable, type-safe TypeScript client surface that signs and broadcasts transactions via pluggable wallet adapters. The core SDK stays RPC-free; everything network-related lives behind a WalletAdapter boundary.

1. Richer IDL metadata in stack specs

arete-idl now preserves the metadata required to build instructions, not just read state.

  • Enum variant payloads: IdlEnumVariant / IdlEnumVariantSnapshot carry fields (named struct fields or tuple elements). Fieldless variants serialize byte-identically to older snapshots (skip_serializing_if = "Vec::is_empty"), so existing stack specs don't churn.
  • Anchor discriminator fix: global:{name} is now snake_cased before hashing, matching Anchor's runtime discriminator derivation.
  • PDA declarations: the pdas! macro (new in arete-macros) lets a stack declare program-derived addresses the IDL doesn't embed (e.g. Steel programs). ORE declares treasury, config, board, miner, automation.
  • IDL spec emission (arete-macros/src/stream_spec/idl_spec.rs, writer.rs, versioned.rs) and interpreter versioned AST carry the new shapes through to codegen.
  • stacks/ore/.arete/OreStream.stack.json regenerated from the richer snapshot.

2. Typed instruction runtime in the TypeScript SDK

The core SDK gains a data-driven instruction runtime. No imperative serialization code is shipped — handlers are metadata consumed by a factory.

  • instructions/executor.tscreateInstructionHandler factory + executeInstruction / buildInstruction. Handlers expose ordered accounts, argNames, errors, and a generic build; the executor resolves accounts, serializes args, and broadcasts via the WalletAdapter.
  • instructions/serializer.ts — Borsh arg serialization driven by an ArgSchema[] (primitives, structs, enums, arrays, options).
  • instructions/seed-serializer.ts + pda.ts + pda-dsl.ts — canonical PDA seed serialization and a small DSL (literal, account, arg, bytes, pda).
  • instructions/account-resolver.ts — categorizes accounts (signer, pda, known, userProvided) and resolves them in order, with validateAccountResolution.
  • instructions/error-parser.ts — parses program errors against IDL error metadata; throws typed InstructionError carrying programError.
  • wallet/types.ts — the WalletAdapter boundary, BuiltInstruction / BuiltAccountMeta, SendOptions, ConfirmationLevel, SendResult. Core is RPC-free by design.
  • client.tsArete.connect(stack, { wallet }) exposes a typed client.instructions.<name>(params) surface (with .build() for batching) and client.transaction([...]). Default wallet is overridable per call. Removed the old instructions/confirmation.ts (now adapter-owned).
  • react/useInstructionMutation hook (idle/pending/success/error, signature, reset) and provider/stack wiring.
  • Tests: client.test.ts, instructions.test.ts, seed-serializer.test.ts (~760 new test lines).

3. Reference wallet adapters

Two adapter packages implementing WalletAdapter, owning blockhash, message compilation, signing, send, and confirmation.

  • @usearete/adapter-web3js@solana/web3.js v0-message-based adapter. createKeypairWalletAdapter for Node/bots and createWalletAdapter for browser/wallet-standard signers. Supports batching via client.transaction([...]).
  • @usearete/adapter-kit@solana/kit (functional web3.js successor) adapter using createSolanaRpc / createSolanaRpcSubscriptions.

4. Typed instruction handler codegen

interpreter/src/typescript_instructions.rs (new, ~1970 lines) consumes InstructionDef[] from a stack spec and emits data-driven handlers targeting the core createInstructionHandler factory.

  • Emits per-instruction Params / Error types and a handler const (discriminator, ordered accounts with PDA configs, arg schema, error table).
  • Per-program error scoping: flat naming for single-program stacks, namespaced (<Stack><Program>ProgramError) for multi-program stacks.
  • PDA resolution: flattens the stack's PDA registry; warns on conflicting cross-program definitions and degrades gracefully on unresolvable PDAs.
  • Wired into cli/src/commands/sdk.rs so a4 sdk emits the handlers.
  • Golden fixture: interpreter/tests/golden/ore-close-instruction.expected.ts — shows the generated oreCloseInstruction handler (board/treasury PDAs, system program, OreCloseParams).

5. Ore stack update

stacks/ore/.arete/OreStream.stack.json refreshed with the richer instruction/PDA metadata that the rest of the PR consumes.

Architecture notes

  • RPC-free core: the SDK only produces BuiltInstruction objects; adapters own all network semantics. This keeps the core testable and library-agnostic.
  • Data-driven handlers: codegen emits metadata + typed shapes, not serialization code. The runtime interprets the metadata, so handler output is small and auditable (see the golden fixture).
  • Account categories: signer / pda / known / userProvided drive resolution; user-provided accounts are passed alongside args in a single flat params object.
  • Batching: client.instructions.<name>.build(...) returns a BuiltInstruction; client.transaction([...]) composes them into one transaction.

Known follow-ups

  • round = ["round", round_id] PDA is intentionally omitted from the ore pdas! block — some ORE instructions derive it from a cross-account field (board.round_id), which needs per-instruction seed binding (not yet expressible). Codegen emits a warning and falls back to userProvided for these.
  • PDA name collisions across programs keep the first definition and warn.

Test plan

  • cargo test -p interpreter (golden: ore-close-instruction.expected.ts)
  • cargo test -p arete-idl
  • TS core: pnpm --filter @usearete/sdk test (client.test.ts, instructions.test.ts, seed-serializer.test.ts)
  • Adapter build: pnpm --filter @usearete/adapter-web3js build / @usearete/adapter-kit build
  • Manual: regenerate ore SDK via a4 sdk and confirm handlers match the golden fixture

@vercel

vercel Bot commented Jun 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
arete-docs Ready Ready Preview, Comment Jun 18, 2026 1:17am

Request Review

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