Skip to content

feat(subtensor): add MinTradeDelay post-start trading delay (#2844)#2887

Open
Elv92 wants to merge 1 commit into
RaoFoundation:mainfrom
Elv92:feat/min-trade-delay-2844
Open

feat(subtensor): add MinTradeDelay post-start trading delay (#2844)#2887
Elv92 wants to merge 1 commit into
RaoFoundation:mainfrom
Elv92:feat/min-trade-delay-2844

Conversation

@Elv92

@Elv92 Elv92 commented Jul 13, 2026

Copy link
Copy Markdown

PR: Add MinTradeDelay — a post-start trading delay to prevent subnet-start self-snipes

Closes / implements the mechanism requested in #2844.

Problem

do_start_call sets SubtokenEnabled = true in the same block as the subnet start
(subnets/subnet.rs). Because add_stake (and the swap/move/transfer family) validate against
SubtokenEnabled, a subnet owner can submit batch_all[start_call, add_stake] and buy alpha
atomically in the block trading opens, before anyone else can react — the SN99 case in #2844.

Change

Adds a sudo-configurable hyperparameter MinTradeDelay (blocks) and enforces a post-start
trading-open delay
: staking in/out is rejected with a new TradingNotOpenYet error until
current_block >= start_block + MinTradeDelay, where start_block = FirstEmissionBlockNumber - 1
(set atomically by do_start_call). This mirrors the existing StartCallDelay hyperparameter end
to end (storage / config const / event / getter-setter / sudo_set_min_trade_delay).

The check lives in Pallet::ensure_subtoken_enabled, which is the single gate for add_stake,
add_stake_limit, remove_stake, recycle, buy_alpha, and transfer_staked_alpha. The
swap_stake / move_stake / transfer_stake family was checking SubtokenEnabled directly
(validate_stake_transition), which would have let an owner pre-stake into root and bundle
batch_all[start_call, swap_stake(root -> new)] to snipe anyway — so those two checks are now
routed through ensure_subtoken_enabled too, closing that bypass.

Result: in the start block (with delay > 0) no alpha-acquiring path succeeds — the owner's
bundled buy reverts TradingNotOpenYet. Everyone, owner included, can only stake at the known,
public block start + MinTradeDelay.

Files

  • pallets/subtensor/src/lib.rsMinTradeDelay storage + the delay check in ensure_subtoken_enabled.
  • pallets/subtensor/src/macros/{config,events,errors}.rsInitialMinTradeDelay, MinTradeDelaySet, TradingNotOpenYet.
  • pallets/subtensor/src/coinbase/root.rsget/set_min_trade_delay.
  • pallets/subtensor/src/staking/stake_utils.rs — route validate_stake_transition through the gate.
  • pallets/admin-utils/src/lib.rssudo_set_min_trade_delay (call_index 97).
  • runtime/src/lib.rsInitialMinTradeDelay = prod_or_fast!(360, 0), wiring, spec_version 429→430.
  • runtime/src/proxy_filters/call_groups.rs — add the new sudo call to the proxy-filter allow-group.
  • 7 test mocks — provide InitialMinTradeDelay (compile requirement).
  • Tests in pallets/subtensor/src/tests/subnet.rs and pallets/admin-utils/src/tests/mod.rs.

Compatibility

  • Existing subnets: their FirstEmissionBlockNumber is in the past, so start + delay is in the
    past → not retroactively frozen.
  • Root / not-yet-started subnets (FirstEmissionBlockNumber = None): delay branch skipped → behave as today.
  • Emissions: FirstEmissionBlockNumber is unchanged and emission eligibility uses .is_some(), not a
    block compare — emission timing is unaffected.
  • Storage: ValueQuery + default ⇒ no migration.

Open questions for reviewers (policy, not mechanism)

  1. Default value. I defaulted to prod_or_fast!(360, 0) (~72 min on prod, 0 on fast-blocks) so the
    protection is on by default while remaining sudo-tunable. Happy to default 0 (mechanism only, opt-in
    via sudo) if the team prefers a no-behaviour-change merge, matching how StartCallDelay shipped.
  2. Sell-side symmetry. This gates the buy side (the self-snipe) and plain remove_stake. Some sell
    paths (unstake_all, remove_stake_limit) intentionally no-op / aren't gated today; I left that
    pre-existing behaviour alone. If "no staking in or out during the window" is desired verbatim, those
    can be routed through the gate too — flagging as a scope decision.

…ation#2844)

Prevent subnet-start self-snipes: a subnet owner can currently submit
batch_all[start_call, add_stake] and buy alpha atomically in the block
trading opens (the SN99 case, issue RaoFoundation#2844), because do_start_call enables
SubtokenEnabled in the same block.

Add a sudo-configurable MinTradeDelay (blocks). Staking in/out is rejected
with TradingNotOpenYet until current_block >= start_block + MinTradeDelay,
where start_block = FirstEmissionBlockNumber - 1. The check lives in
ensure_subtoken_enabled (the single gate for add_stake/remove_stake/recycle/
buy_alpha/transfer_staked_alpha); validate_stake_transition is also routed
through it so swap_stake/move_stake/transfer_stake cannot bypass the delay.

Mirrors the existing StartCallDelay hyperparameter (storage, config const,
event, getter/setter, sudo_set_min_trade_delay call_index 97). Runtime default
prod_or_fast!(360, 0); spec_version 429->430; ValueQuery default => no migration.
Existing/started subnets, root, and emission timing are unaffected. Adds tests.
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

A member of the Team first needs to authorize it.

@Elv92

Elv92 commented Jul 14, 2026

Copy link
Copy Markdown
Author

@IntiTechnologies — since this is a fork PR, the required ai-review (skeptic/auditor) checks can't auto-run; they need a manual workflow_dispatch with the PR number. Whenever you (or another maintainer) have a moment, could you kick those off so review can proceed? 🙏

Context in case it helps triage: this implements the staking-start delay from #2844. It's deliberately narrow and complementary to the May 8 owner-alpha-at-registration fix — that closed the registration free-alpha vector; this closes the distinct launch-timing vector (an owner bundling add_stake into the same block as start_call). It mirrors the existing StartCallDelay end to end and ships with tests.

@open-junius — if you have bandwidth to look at the code at some point, that'd be much appreciated. No rush either way, and happy to adjust to your conventions.

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