Skip to content

feat(cdm): expose waitFor option on contract tx() calls#12

Open
shawntabrizi wants to merge 1 commit into
mainfrom
feat/tx-waitfor-option
Open

feat(cdm): expose waitFor option on contract tx() calls#12
shawntabrizi wants to merge 1 commit into
mainfrom
feat/tx-waitfor-option

Conversation

@shawntabrizi
Copy link
Copy Markdown
Member

Summary

Adds an optional waitFor: \"best-block\" | \"finalized\" field to TxOpts. When omitted, behavior is unchanged (waits for finalization). Setting to \"best-block\" resolves the Promise as soon as the tx is included in a block — typically 5-10× faster on chains with slow GRANDPA finality (local zombienet, dev networks).

Motivation

While building a Triangle game on top of @dotdm/cdm against a local PPN zombienet, every arena.method.tx(...) call took 12-18s to resolve, even though Asset Hub blocks tick every ~2s. The bottleneck was signAndSubmit always waiting for finalization.

For local dev where finality guarantees aren't needed, sub-second tx feedback materially improves the play-test-fix loop. Real-game gameplay code becomes:

await arena.startGame.tx(setId, seedNonce, { waitFor: \"best-block\" });
await arena.submitTurn.tx(action,           { waitFor: \"best-block\" });

…and the perceived latency drops from ~30s per click to ~2s.

Changes

  • types.ts: add waitFor?: \"best-block\" | \"finalized\" to TxOpts with docstring
  • wrap.ts: replace await tx.signAndSubmit(signer) with await submitAndWatch(tx, signer, { waitFor }). submitAndWatch from @polkadot-apps/tx already handles InkSDK's AsyncTransaction wrapper via its .waited Promise, so passing papiContract.send(...) directly flows through unchanged.
  • package.json: add @polkadot-apps/tx to deps (already in the catalog via @dotdm/contracts)
  • Changeset: minor bump

Backwards compatibility

waitFor defaults to \"finalized\", so any caller that doesn't pass it gets identical behavior. The TxResult shape ({ txHash, blockHash, ok, events }) is unchanged.

Related

  • Discussed alongside the sdk-ink `trace_call` resilience issue (separate PR/issue) — same surface area where cdm/sdk-ink doesn't expose enough of PAPI's flexibility through the wrap.

Test plan

  • pnpm install resolves
  • pnpm --filter \"@dotdm/cdm\" build clean
  • Verified locally against OAB game contract on PPN zombienet — waitFor: \"best-block\" returns in ~2s vs ~15s for default "finalized"
  • CI

🤖 Generated with Claude Code

Adds an optional `waitFor: "best-block" | "finalized"` field to TxOpts.
When omitted, behavior is unchanged (waits for finalization). Setting to
"best-block" resolves the Promise as soon as the tx is included in a
block, which is typically 5-10x faster on chains with slow GRANDPA
finality (local zombienet, dev networks).

Implementation: switch from PAPI's signAndSubmit (which has no waitFor
knob) to submitAndWatch from @polkadot-apps/tx. submitAndWatch already
handles InkSDK's AsyncTransaction wrapper transparently via its `.waited`
Promise, so the existing `tx` from `papiContract.send(...)` flows through
unchanged.

Motivated by a local dev loop where each .tx() call took 12-18s waiting
for finalization, masking the actual ~2s block time and making
play-test-fix iteration painful. With waitFor: "best-block" the same
tx returns in ~2s.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@cla-bot-2021
Copy link
Copy Markdown

cla-bot-2021 Bot commented May 8, 2026

User @claude, please sign the CLA here.

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