Skip to content

feat(chain-extensions): add claim-root-with-hotkey for contract root-basket claims - #3099

Open
Benup211 wants to merge 5 commits into
RaoFoundation:mainfrom
Benup211:feat/claim-root-with-hotkey-extension
Open

feat(chain-extensions): add claim-root-with-hotkey for contract root-basket claims#3099
Benup211 wants to merge 5 commits into
RaoFoundation:mainfrom
Benup211:feat/claim-root-with-hotkey-extension

Conversation

@Benup211

@Benup211 Benup211 commented Aug 20, 2026

Copy link
Copy Markdown

Description

Adds a new chain-extension function (ClaimRootWithHotkeyV1, id 39) so an pallet/ink! contract that holds root (netuid 0) stake as a coldkey can claim its per-validator basket entitlement through the 0x1000 chain extension.

  • The contract is the coldkey; do_root_claim(env.caller(), vec![hotkey]) is invoked with the contract address as the origin.
  • Realized TAO is staked back to root on the hotkey (compounding), and the realized amount (RootClaimOutcome::tao) is written back so the contract can update its own bookkeeping.
  • Basket work is bounded up front: the arm rejects claims whose basket row count exceeds MAX_ROOT_CLAIM_WORK (256) before charging any weight, mirroring the rows clause of the signed extrinsic's root_claim_fits_declared_budget admission gate. The full claim_root(MAX_ROOT_CLAIM_WORK) weight is then charged via env.charge_weight (a chain extension has no post-dispatch weight refund).

Files changed:

  • chain-extensions/src/types.rs — add ClaimRootWithHotkeyV1 = 39 to FunctionId
  • chain-extensions/src/lib.rs — dispatch arm (decode → bound → charge weight → claim → write output)
  • chain-extensions/src/tests.rsclaim_root_with_hotkey_noop_returns_zero (success path: full 256-unit charge, zero payout) and claim_root_with_hotkey_rejects_basket_above_envelope (257-row basket → RuntimeError, no weight charged)

Related Issue(s)

None.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Breaking Change

No breaking change. This is purely additive: a new chain-extension function id (39) and dispatch arm. Existing function ids 0–38 and their SCALE encodings are unchanged.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have run ./scripts/fix_rust.sh to ensure my code is formatted and linted correctly
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Screenshots (if applicable)

N/A

Additional Notes

  • Function id 39: ids 37/38 (MoveStakeLimitV1, CallerMoveStakeLimitV1) were taken by release-448, so this function landed on 39. The discriminant and roundtrip tests assert 16..=39.
  • Branch state: includes the release-449 merge; v449 changed no root-claim semantics (the claim engine, gate, and weights are identical), and the crate compiles with all tests passing post-merge.
  • Runtime-affecting: this adds a chain-extension function, so it needs a spec_version bump (or the no-spec-version-bump label) — left for the release train / maintainer to coordinate.
  • Verification performed (crate-scoped, not the full workspace gate):
    • cargo test -p subtensor-chain-extensions — 57 passed, 0 failed (incl. both claim tests)
    • cargo clippy -p subtensor-chain-extensions --all-targets — clean
    • cargo fmt -p subtensor-chain-extensions -- --check — clean
    • ./scripts/fix_rust.sh was not run (it auto-commits workspace-wide).
  • Design rationale: the upfront claim_root(MAX_ROOT_CLAIM_WORK) charge with a pre-charge row-count bound is deliberate — unlike the signed extrinsic (which declares the same 256-unit envelope and refunds post-dispatch down to root_claim_actual_weight), a chain extension has no post-dispatch refund, so the envelope must be charged in full and oversized baskets rejected before any weight is charged.

…basket claims

Exposes function 37 (ClaimRootWithHotkeyV1) so an ink! contract that holds
root stake as a coldkey can claim its per-validator basket entitlement
through the 0x1000 chain extension. The contract is the coldkey; realized
TAO is staked back to root on the hotkey and the realized amount is returned.
Basket work is bounded to MAX_ROOT_CLAIM_WORK and charged upfront (no
post-dispatch refund), mirroring the signed extrinsic's admission gate.
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

@Benup211 is attempting to deploy a commit to the RaoFoundation Team on Vercel.

A member of the Team first needs to authorize it.

@UnArbosSix UnArbosSix left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Successful contract claims can leave the root-staker coldkey index inconsistent. The new chain-extension arm calls do_root_claim(caller, vec![hotkey]) directly and returns the payout, but never calls maybe_add_coldkey_index(&caller). The normal claim_root_with_hotkey extrinsic explicitly does exactly that after do_root_claim, so this is a real semantic difference between the two entry points, not incidental cleanup.

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