Skip to content

feat(sdk-coin-tao): build claimRootWithHotkey extrinsic from intent - #9448

Merged
abhijit0943 merged 1 commit into
masterfrom
ashutosh/SI-1171-claim-root-with-hotkey
Aug 11, 2026
Merged

feat(sdk-coin-tao): build claimRootWithHotkey extrinsic from intent#9448
abhijit0943 merged 1 commit into
masterfrom
ashutosh/SI-1171-claim-root-with-hotkey

Conversation

@bitgo-ai-agent-dev

Copy link
Copy Markdown
Contributor

What

  • abstract-substrate: add ClaimRootWithHotkey to MethodNames const, add ClaimRootWithHotkeyArgs interface ({ hotkey: string }) to iface.ts TxMethod.args union, add ClaimRootWithHotkeyTransactionSchema joi schema
  • sdk-coin-tao: new ClaimRootBuilder — builds SubtensorModule.claimRootWithHotkey(hotkey) extrinsic via defineMethod; implements hotkey() setter, buildTransaction(), fromImplementation(), validateTransaction(), validateDecodedTransaction()
  • sdk-coin-tao: new ClaimRootTransaction — overrides toJson() (adds hotkey field), loadInputsAndOutputs() (populates _outputs with hotkey address, resets arrays before repopulating), explainTransaction()
  • sdk-coin-tao: new ClaimRootTxData interface in iface.ts
  • sdk-coin-tao: TransactionBuilderFactory — register ClaimRootWithHotkey dispatch in getBuilder() and expose getClaimRootBuilder()
  • sdk-coin-tao: Tao.verifyTransaction override — short-circuits for StakingClaim type (case-insensitive) before the parent tries to access _to/_amount which don't exist on ClaimRootBuilder
  • sdk-coin-tao: new src/resources/testnetV2.ts — Bittensor testnet metadata (specVersion 443) that includes claim_root_with_hotkey; existing testnet.ts (specVersion 224) unchanged
  • sdk-coin-tao: wire TaoClaimRootIntent { hotkey, netuid: 0 } end-to-end in tao.ts
  • Unit tests: unsigned build, signed build, round-trip from(), factory dispatch, outputs content, loadInputsAndOutputs null-safety, explainTransaction, validation, error paths, verifyTransaction with both PascalCase and lowercase type

Why

  • SI-1171 requires sdk-coin-tao to accept TaoClaimRootIntent { hotkey, netuid: 0 } and produce a signed, broadcastable SubtensorModule.claimRootWithHotkey extrinsic. This is a P0 blocker for the TAO Root Reborn claim feature and directly blocks SI-1172 ([WP] Route CLAIM_REWARDS request type for tao/ttao)

Test plan

  • mocha — 93 passing, 2 pending, 1 pre-existing failure (requires BITGOJS_TEST_PASSWORD)
  • TypeScript build: sdk-coin-tao and abstract-substrate compile clean
  • loadInputsAndOutputs resets _outputs/_inputs before push — idempotent on repeated build() calls
  • verifyTransaction uses case-insensitive comparison — handles WalletPlatform lowercase 'stakingclaim' intentType
  • Integration test on testnet after feature is wired end-to-end (SI-1172)

Ticket: SI-1171

@linear-code

linear-code Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

SI-1171

@abhijit0943

Copy link
Copy Markdown
Contributor

Review

Recommend: request changes — one real correctness/security issue in verifyTransaction; rest of the builder/transaction implementation follows the existing MoveStakeBuilder pattern closely and has solid test coverage.

Critical

modules/sdk-coin-tao/src/tao.ts:319-326 — the new verifyTransaction override returns true for any stakingclaim-typed request without ever decoding txPrebuild.txHex. That skips all validation, not just the recipient/amount check the comment claims to be avoiding.

  • The stated reason ("parent tries to access _to/_amount which don't exist on ClaimRootBuilder") doesn't hold up — reading an undefined property in JS returns undefined, it doesn't throw.
  • The base SubstrateCoin.verifyTransaction already handles this safely: when txParams.recipients is undefined (true for claim/staking intents), it falls through to return true, but only after calling factory.from(txPrebuild.txHex) to decode the tx. MoveStakeBuilder/StakingBuilder/UnstakeBuilder all lack _to/_amount too and never needed a Tao-level override for this.
  • DOT (same abstract-substrate family) has a ClaimBuilder for claim rewards and does zero special-casing — same recipients === undefined fallthrough, but it always calls factory.from() first.
  • Net effect: a compromised/buggy WalletPlatform response tagged type: 'stakingclaim' carrying an arbitrary or malicious txHex (wrong hotkey, or not even a claim tx) would be approved for TSS signing with zero checks.

Suggested fix: drop the override — it should inherit the same safe fallthrough DOT and the other TAO builders already rely on.

Important

  • claimRootTransaction.ts:186loadInputsAndOutputs() calls super.loadInputsAndOutputs(), which SCALE-decodes the tx a second time for nothing (the base dispatcher has no StakingClaim case), then decodes again itself. Redundant work, not a bug.
  • utils.ts:8getMaterial() still points TESTNET at the old spec-224 testnetMaterial; the new testnetMaterialV2 (spec 443, has claim_root_with_hotkey) is only referenced by tests. Worth confirming this is intentionally deferred to SI-1172's end-to-end wiring rather than an oversight.

Minor

  • Test comment at claimRootBuilder.ts:535 ("tip=0 is falsy → fallback fires") is inaccurate — (0).toString() is "0", a truthy string, so the || '0' never actually fires for tip=0. No functional impact, both branches yield '0'.

@ashutoshkumar-6
ashutoshkumar-6 force-pushed the ashutosh/SI-1171-claim-root-with-hotkey branch 2 times, most recently from bd8ef78 to 5ec8c2b Compare August 11, 2026 07:37
Add SubtensorModule.claimRootWithHotkey(hotkey) Substrate extrinsic
support across abstract-substrate and sdk-coin-tao.

TICKET: SI-1171
Co-authored-by: Cursor <cursoragent@cursor.com>
@ashutoshkumar-6
ashutoshkumar-6 force-pushed the ashutosh/SI-1171-claim-root-with-hotkey branch from 5ec8c2b to 1b6fc41 Compare August 11, 2026 07:42

@abhijit0943 abhijit0943 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.

lgtm

@abhijit0943
abhijit0943 merged commit 42d9e7d into master Aug 11, 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