From f472452fd0360368bfd585157a35ef711fd62e82 Mon Sep 17 00:00:00 2001 From: unarbos Date: Mon, 13 Jul 2026 15:13:11 -0600 Subject: [PATCH 01/43] describe every chain error with its trigger and where to check Add bittensor/error_descriptions.py: a researched description for each of the 353 classified chain error names, grounded in the pallet raise sites. Surface it in the docs errors table and /catalog/errors.json, in the btcli failure diagnostic and `btcli explain `, and on ChainError for the SDK. The --names gate now enforces that classification and descriptions cover exactly the same names. Co-authored-by: Cursor --- docs/errors.mdx | 714 +++---- sdk/python/bittensor/cli/main.py | 2 + sdk/python/bittensor/cli/output.py | 11 +- sdk/python/bittensor/error_descriptions.py | 1845 +++++++++++++++++ sdk/python/bittensor/result.py | 13 +- sdk/python/codegen/check.py | 19 +- .../public/catalog/errors.json | 1765 ++++++++++++---- .../bittensor-website/scripts/generate.py | 17 +- 8 files changed, 3663 insertions(+), 723 deletions(-) create mode 100644 sdk/python/bittensor/error_descriptions.py diff --git a/docs/errors.mdx b/docs/errors.mdx index 99ce8dc505..612468dc37 100644 --- a/docs/errors.mdx +++ b/docs/errors.mdx @@ -83,360 +83,360 @@ Inspect the message for details ## Chain error classification -The exact chain error name (from the extrinsic receipt) maps to a code: - -| Chain error | Code | -| --- | --- | -| `AccountNotAllowedCommit` | `not_authorized` | -| `AccountRejectsLockedAlpha` | `invalid_argument` | -| `ActiveLockExists` | `already_exists` | -| `ActivityCutoffFactorMilliOutOfBounds` | `invalid_argument` | -| `ActivityCutoffTooLow` | `invalid_argument` | -| `AddStakeBurnRateLimitExceeded` | `rate_limited` | -| `AdminActionProhibitedDuringWeightsWindow` | `too_early` | -| `AllNetworksInImmunity` | `too_early` | -| `AlphaHighTooLow` | `invalid_argument` | -| `AlphaLowOutOfRange` | `invalid_argument` | -| `AlreadyApproved` | `already_exists` | -| `AlreadyDeposited` | `already_exists` | -| `AlreadyFinalized` | `already_exists` | -| `AlreadyFinalizing` | `already_exists` | -| `AlreadyNoted` | `already_exists` | -| `AlreadyStored` | `already_exists` | -| `AmountTooLow` | `invalid_argument` | -| `AnnouncedColdkeyHashDoesNotMatch` | `invalid_argument` | -| `AnnouncementDepositInvariantViolated` | `internal` | -| `ArithmeticOverflow` | `internal` | -| `AutoEpochAlreadyImminent` | `already_exists` | -| `BadEncKeyLen` | `invalid_argument` | -| `BalanceLow` | `insufficient_balance` | -| `BalanceWithdrawalError` | `insufficient_balance` | -| `BeneficiaryDoesNotOwnHotkey` | `not_authorized` | -| `BlockDurationTooLong` | `invalid_argument` | -| `BlockDurationTooShort` | `invalid_argument` | -| `BondsMovingAverageMaxReached` | `limit_exceeded` | -| `CallDisabled` | `disabled` | -| `CallFiltered` | `not_authorized` | -| `CallUnavailable` | `not_found` | -| `CanNotSetRootNetworkWeights` | `invalid_argument` | -| `CannotAddSelfAsDelegateDependency` | `invalid_argument` | -| `CannotAffordLockCost` | `insufficient_balance` | -| `CannotBurnOrRecycleOnRootSubnet` | `invalid_argument` | -| `CannotEndInPast` | `invalid_argument` | -| `CannotReleaseYet` | `too_early` | -| `CannotUseSystemAccount` | `not_authorized` | -| `CapNotRaised` | `too_early` | -| `CapRaised` | `limit_exceeded` | -| `CapTooLow` | `invalid_argument` | -| `ChainIdMismatch` | `invalid_argument` | -| `ChangePending` | `already_exists` | -| `ChildParentInconsistency` | `invalid_argument` | -| `CodeInUse` | `invalid_argument` | -| `CodeInfoNotFound` | `not_found` | -| `CodeNotFound` | `not_found` | -| `CodeRejected` | `invalid_argument` | -| `CodeTooLarge` | `limit_exceeded` | -| `ColdKeyAlreadyAssociated` | `already_exists` | -| `ColdkeySwapAlreadyDisputed` | `already_exists` | -| `ColdkeySwapAnnounced` | `already_exists` | -| `ColdkeySwapAnnouncementNotFound` | `not_found` | -| `ColdkeySwapClearTooEarly` | `too_early` | -| `ColdkeySwapDisputed` | `not_authorized` | -| `ColdkeySwapReannouncedTooEarly` | `too_early` | -| `ColdkeySwapTooEarly` | `too_early` | -| `CommitRevealDisabled` | `disabled` | -| `CommitRevealEnabled` | `disabled` | -| `CommittingWeightsTooFast` | `rate_limited` | -| `ContractNotFound` | `not_found` | -| `ContractReverted` | `internal` | -| `ContractTrapped` | `internal` | -| `ContributionPeriodEnded` | `expired` | -| `ContributionPeriodNotEnded` | `too_early` | -| `ContributionTooLow` | `invalid_argument` | -| `CreateOriginNotAllowed` | `not_authorized` | -| `CurrencyError` | `internal` | -| `DeadAccount` | `not_found` | -| `DecodingFailed` | `invalid_argument` | -| `DelegateDependencyAlreadyExists` | `already_exists` | -| `DelegateDependencyNotFound` | `not_found` | -| `DelegateTakeTooHigh` | `invalid_argument` | -| `DelegateTakeTooLow` | `invalid_argument` | -| `DelegateTxRateLimitExceeded` | `rate_limited` | -| `DeltaZero` | `invalid_argument` | -| `DepositCannotBeWithdrawn` | `invalid_argument` | -| `DepositTooLow` | `invalid_argument` | -| `Deprecated` | `disabled` | -| `DisabledTemporarily` | `disabled` | -| `DrandConnectionFailure` | `internal` | -| `Duplicate` | `already_exists` | -| `DuplicateChild` | `invalid_argument` | -| `DuplicateContract` | `already_exists` | -| `DuplicateOffenceReport` | `already_exists` | -| `DuplicateOrderInBatch` | `invalid_argument` | -| `DuplicateUids` | `invalid_argument` | -| `DynamicTempoBlockedByCommitReveal` | `disabled` | -| `Entered` | `already_exists` | -| `EpochTriggerAlreadyPending` | `already_exists` | -| `EvmKeyAssociateRateLimitExceeded` | `rate_limited` | -| `EvmKeyAssociationLimitExceeded` | `limit_exceeded` | -| `ExistentialDeposit` | `insufficient_balance` | -| `ExistingVestingSchedule` | `already_exists` | -| `Exited` | `already_exists` | -| `ExpectedBeneficiaryOrigin` | `not_authorized` | -| `Expendability` | `insufficient_balance` | -| `ExpiredWeightCommit` | `expired` | -| `FailedToExtractRuntimeVersion` | `invalid_argument` | -| `FailedToSchedule` | `internal` | -| `FaucetDisabled` | `disabled` | -| `FeeOverflow` | `internal` | -| `FeeRateTooHigh` | `invalid_argument` | -| `FirstEmissionBlockNumberAlreadySet` | `already_exists` | -| `GasLimitTooHigh` | `invalid_argument` | -| `GasLimitTooLow` | `invalid_argument` | -| `GasPriceTooLow` | `invalid_argument` | -| `HotKeyAccountNotExists` | `not_registered` | -| `HotKeyAlreadyDelegate` | `already_exists` | -| `HotKeyAlreadyRegisteredInSubNet` | `already_exists` | -| `HotKeyNotRegisteredInNetwork` | `not_registered` | -| `HotKeyNotRegisteredInSubNet` | `not_registered` | -| `HotKeySetTxRateLimitExceeded` | `rate_limited` | -| `HotKeySwapOnSubnetIntervalNotPassed` | `rate_limited` | -| `IncorrectCommitRevealVersion` | `invalid_argument` | -| `IncorrectPartialFillAmount` | `invalid_argument` | -| `IncorrectWeightVersionKey` | `invalid_argument` | -| `Indeterministic` | `invalid_argument` | -| `InputForwarded` | `invalid_argument` | -| `InputLengthsUnequal` | `invalid_argument` | -| `InsufficientBalance` | `insufficient_balance` | -| `InsufficientInputAmount` | `invalid_argument` | -| `InsufficientLiquidity` | `insufficient_liquidity` | -| `InsufficientStakeForLock` | `insufficient_balance` | -| `InvalidCallFlags` | `invalid_argument` | -| `InvalidChainId` | `invalid_argument` | -| `InvalidChild` | `invalid_argument` | -| `InvalidChildkeyTake` | `invalid_argument` | -| `InvalidCrowdloanId` | `not_found` | -| `InvalidDerivedAccount` | `invalid_argument` | -| `InvalidDerivedAccountId` | `invalid_argument` | -| `InvalidDifficulty` | `invalid_argument` | -| `InvalidEquivocationProof` | `invalid_argument` | -| `InvalidFinalizationConfig` | `invalid_argument` | -| `InvalidIdentity` | `invalid_argument` | -| `InvalidIpAddress` | `invalid_argument` | -| `InvalidIpType` | `invalid_argument` | -| `InvalidKeyOwnershipProof` | `invalid_argument` | -| `InvalidLeaseBeneficiary` | `invalid_argument` | -| `InvalidLiquidityValue` | `invalid_argument` | -| `InvalidNonce` | `invalid_argument` | -| `InvalidNumRootClaim` | `invalid_argument` | -| `InvalidOrigin` | `not_authorized` | -| `InvalidPort` | `invalid_argument` | -| `InvalidRecoveredPublicKey` | `invalid_argument` | -| `InvalidRevealCommitHashNotMatch` | `invalid_argument` | -| `InvalidRevealRound` | `expired` | -| `InvalidRootClaimThreshold` | `invalid_argument` | -| `InvalidRoundNumber` | `invalid_argument` | -| `InvalidSchedule` | `invalid_argument` | -| `InvalidSeal` | `invalid_argument` | -| `InvalidSignature` | `invalid_argument` | -| `InvalidSpecName` | `invalid_argument` | -| `InvalidSubnetNumber` | `invalid_argument` | -| `InvalidTickRange` | `invalid_argument` | -| `InvalidValue` | `invalid_argument` | -| `InvalidVotingPowerEmaAlpha` | `invalid_argument` | -| `InvalidWorkBlock` | `invalid_argument` | -| `IssuanceDeactivated` | `disabled` | -| `LeaseCannotEndInThePast` | `invalid_argument` | -| `LeaseDoesNotExist` | `not_found` | -| `LeaseHasNoEndBlock` | `invalid_argument` | -| `LeaseHasNotEnded` | `too_early` | -| `LeaseNetuidNotFound` | `not_found` | -| `LimitOrdersDisabled` | `disabled` | -| `LiquidAlphaDisabled` | `disabled` | -| `LiquidityRestrictions` | `insufficient_balance` | -| `LockHotkeyMismatch` | `invalid_argument` | -| `LockIdOverFlow` | `limit_exceeded` | -| `MaxAllowedUIdsLessThanCurrentUIds` | `invalid_argument` | -| `MaxAllowedUidsGreaterThanDefaultMaxAllowedUids` | `invalid_argument` | -| `MaxAllowedUidsLessThanMinAllowedUids` | `invalid_argument` | -| `MaxCallDepthReached` | `limit_exceeded` | -| `MaxContributionReached` | `limit_exceeded` | -| `MaxContributorsReached` | `limit_exceeded` | -| `MaxDelegateDependenciesReached` | `limit_exceeded` | -| `MaxValidatorsLargerThanMaxUIds` | `invalid_argument` | -| `MaxWeightExceeded` | `limit_exceeded` | -| `MaxWeightTooLow` | `invalid_argument` | -| `MaximumContributionTooLow` | `invalid_argument` | -| `MechanismDoesNotExist` | `subnet_not_exists` | -| `MigrationInProgress` | `too_early` | -| `MinAllowedUidsGreaterThanCurrentUids` | `invalid_argument` | -| `MinAllowedUidsGreaterThanMaxAllowedUids` | `invalid_argument` | -| `MinimumContributionTooHigh` | `invalid_argument` | -| `MinimumContributionTooLow` | `invalid_argument` | -| `MinimumThreshold` | `invalid_argument` | -| `MultiBlockMigrationsOngoing` | `too_early` | -| `Named` | `invalid_argument` | -| `NeedWaitingMoreBlocksToStarCall` | `too_early` | -| `NegativeSigmoidSteepness` | `invalid_argument` | -| `NetworkDissolveAlreadyQueued` | `already_exists` | -| `NetworkTxRateLimitExceeded` | `rate_limited` | -| `NeuronNoValidatorPermit` | `not_authorized` | -| `NewColdKeyIsHotkey` | `invalid_argument` | -| `NewHotKeyIsSameWithOld` | `invalid_argument` | -| `NewHotKeyNotCleanForRootSwap` | `invalid_argument` | -| `NoApprovalsNeeded` | `invalid_argument` | -| `NoChainExtension` | `disabled` | -| `NoContribution` | `not_found` | -| `NoDeposit` | `not_found` | -| `NoExistingLock` | `not_found` | -| `NoMigrationPerformed` | `invalid_argument` | -| `NoNeuronIdAvailable` | `limit_exceeded` | -| `NoPermission` | `not_authorized` | -| `NoSelfProxy` | `invalid_argument` | -| `NoTimepoint` | `invalid_argument` | -| `NoWeightsCommitFound` | `not_found` | -| `NonAssociatedColdKey` | `not_authorized` | -| `NonDefaultComposite` | `invalid_argument` | -| `NonZeroRefCount` | `invalid_argument` | -| `NoneValue` | `not_found` | -| `NotAllowed` | `not_authorized` | -| `NotAuthorized` | `not_authorized` | -| `NotConfigured` | `disabled` | -| `NotEnoughAlphaOutToRecycle` | `insufficient_liquidity` | -| `NotEnoughBalanceToPaySwapColdKey` | `insufficient_balance` | -| `NotEnoughBalanceToPaySwapHotKey` | `insufficient_balance` | -| `NotEnoughBalanceToStake` | `insufficient_balance` | -| `NotEnoughStake` | `insufficient_balance` | -| `NotEnoughStakeToSetChildkeys` | `insufficient_balance` | -| `NotEnoughStakeToSetWeights` | `insufficient_balance` | -| `NotEnoughStakeToWithdraw` | `insufficient_balance` | -| `NotFound` | `not_found` | -| `NotNoted` | `not_found` | -| `NotOwner` | `not_authorized` | -| `NotPermittedOnRootSubnet` | `invalid_argument` | -| `NotProxy` | `not_authorized` | -| `NotReadyToDissolve` | `too_early` | -| `NotRequested` | `not_found` | -| `NotRootSubnet` | `invalid_argument` | -| `NotSubnetOwner` | `not_authorized` | -| `NothingAuthorized` | `not_found` | -| `OrderAlreadyProcessed` | `already_exists` | -| `OrderCancelled` | `expired` | -| `OrderExpired` | `expired` | -| `OrderNetUidMismatch` | `invalid_argument` | -| `OutOfBounds` | `invalid_argument` | -| `OutOfGas` | `limit_exceeded` | -| `OutOfTransientStorage` | `limit_exceeded` | -| `OutputBufferTooSmall` | `invalid_argument` | -| `Overflow` | `internal` | -| `POWRegistrationDisabled` | `disabled` | -| `PalletHotkeyNotRegistered` | `not_registered` | -| `PartialFillsNotEnabled` | `disabled` | -| `PauseFailed` | `invalid_argument` | -| `PaymentOverflow` | `internal` | -| `PreLogExists` | `invalid_argument` | -| `PriceConditionNotMet` | `too_early` | -| `PriceLimitExceeded` | `insufficient_liquidity` | -| `ProportionOverflow` | `invalid_argument` | -| `PulseVerificationError` | `invalid_argument` | -| `RandomSubjectTooLong` | `limit_exceeded` | -| `ReentranceDenied` | `invalid_argument` | -| `Reentrancy` | `internal` | -| `RegistrationNotPermittedOnRootSubnet` | `invalid_argument` | -| `RegistrationPriceLimitExceeded` | `limit_exceeded` | -| `RelayerMissMatch` | `invalid_argument` | -| `RelayerRequiredForPartialFill` | `invalid_argument` | -| `Requested` | `invalid_argument` | -| `RequireSudo` | `not_authorized` | -| `RescheduleNoChange` | `invalid_argument` | -| `ReservesOutOfBalance` | `insufficient_liquidity` | -| `ReservesTooLow` | `insufficient_liquidity` | -| `ResumeFailed` | `invalid_argument` | -| `RevealPeriodTooLarge` | `invalid_argument` | -| `RevealPeriodTooSmall` | `invalid_argument` | -| `RevealTooEarly` | `too_early` | -| `RootNetUidNotAllowed` | `invalid_argument` | -| `RootNetworkDoesNotExist` | `subnet_not_exists` | -| `SameAutoStakeHotkeyAlreadySet` | `already_exists` | -| `SameNetuid` | `invalid_argument` | -| `SenderInSignatories` | `invalid_argument` | -| `ServingRateLimitExceeded` | `rate_limited` | -| `SettingWeightsTooFast` | `rate_limited` | -| `SignatoriesOutOfOrder` | `invalid_argument` | -| `SlippageTooHigh` | `insufficient_liquidity` | -| `SpaceLimitExceeded` | `rate_limited` | -| `SpecVersionNeedsToIncrease` | `invalid_argument` | -| `StakeTooLowForRoot` | `insufficient_balance` | -| `StakeUnavailable` | `insufficient_balance` | -| `StakingRateLimitExceeded` | `rate_limited` | -| `StartCallNotReady` | `too_early` | -| `StateChangeDenied` | `not_authorized` | -| `StorageDepositLimitExhausted` | `limit_exceeded` | -| `StorageDepositNotEnoughFunds` | `insufficient_balance` | -| `StorageOverflow` | `internal` | -| `SubNetRegistrationDisabled` | `disabled` | -| `SubnetBuybackRateLimitExceeded` | `rate_limited` | -| `SubnetDoesNotExist` | `subnet_not_exists` | -| `SubnetLimitReached` | `limit_exceeded` | -| `SubnetNotExists` | `subnet_not_exists` | -| `SubtokenDisabled` | `subtoken_disabled` | -| `SwapInputTooLarge` | `insufficient_liquidity` | -| `SwapReturnedZero` | `insufficient_liquidity` | -| `SymbolAlreadyInUse` | `already_exists` | -| `SymbolDoesNotExist` | `not_found` | -| `TargetBlockNumberInPast` | `invalid_argument` | -| `TempoOutOfBounds` | `invalid_argument` | -| `TerminatedInConstructor` | `internal` | -| `TerminatedWhileReentrant` | `invalid_argument` | -| `TooBig` | `limit_exceeded` | -| `TooFew` | `invalid_argument` | -| `TooFewSignatories` | `invalid_argument` | -| `TooMany` | `limit_exceeded` | -| `TooManyCalls` | `limit_exceeded` | -| `TooManyChildren` | `limit_exceeded` | -| `TooManyFieldsInCommitmentInfo` | `limit_exceeded` | -| `TooManyFreezes` | `limit_exceeded` | -| `TooManyHolds` | `limit_exceeded` | -| `TooManyPendingExtrinsics` | `limit_exceeded` | -| `TooManyRegistrationsThisBlock` | `rate_limited` | -| `TooManyRegistrationsThisInterval` | `rate_limited` | -| `TooManyReserves` | `limit_exceeded` | -| `TooManySignatories` | `limit_exceeded` | -| `TooManyTopics` | `limit_exceeded` | -| `TooManyUIDsPerMechanism` | `limit_exceeded` | -| `TooManyUnrevealedCommits` | `limit_exceeded` | -| `TooSoon` | `rate_limited` | -| `TransactionMustComeFromEOA` | `not_authorized` | -| `TransactorAccountShouldBeHotKey` | `not_authorized` | -| `TransferDisallowed` | `disabled` | -| `TransferFailed` | `insufficient_balance` | -| `TrimmingWouldExceedMaxImmunePercentage` | `limit_exceeded` | -| `TxChildkeyTakeRateLimitExceeded` | `rate_limited` | -| `TxRateLimitExceeded` | `rate_limited` | -| `UidMapCouldNotBeCleared` | `internal` | -| `UidVecContainInvalidOne` | `invalid_argument` | -| `UidsLengthExceedUidsInSubNet` | `limit_exceeded` | -| `UnableToRecoverPublicKey` | `invalid_argument` | -| `Unannounced` | `too_early` | -| `Unauthorized` | `not_authorized` | -| `Undefined` | `internal` | -| `Underflow` | `internal` | -| `UnexpectedTimepoint` | `invalid_argument` | -| `UnexpectedUnreserveLeftover` | `internal` | -| `UnlockAmountTooHigh` | `insufficient_balance` | -| `Unproxyable` | `not_authorized` | -| `Unreachable` | `internal` | -| `UnverifiedPulse` | `invalid_argument` | -| `ValueNotInBounds` | `invalid_argument` | -| `ValueTooLarge` | `limit_exceeded` | -| `VestingBalance` | `insufficient_balance` | -| `VotingPowerTrackingNotEnabled` | `disabled` | -| `WaitingForDissolvedSubnetCleanup` | `too_early` | -| `WeightExceedsAbsoluteMax` | `limit_exceeded` | -| `WeightVecLengthIsLow` | `invalid_argument` | -| `WeightVecNotEqualSize` | `invalid_argument` | -| `WithdrawFailed` | `insufficient_balance` | -| `WrongTimepoint` | `invalid_argument` | -| `XCMDecodeFailed` | `invalid_argument` | -| `ZeroBalanceAfterWithdrawn` | `insufficient_balance` | -| `ZeroShareInBatch` | `invalid_argument` | +The exact chain error name (from the extrinsic receipt) maps to a code; the description says what triggered it and where to check: + +| Chain error | Code | Description | +| --- | --- | --- | +| `AccountNotAllowedCommit` | `not_authorized` | Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet. | +| `AccountRejectsLockedAlpha` | `invalid_argument` | Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying. | +| `ActiveLockExists` | `already_exists` | The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first. | +| `ActivityCutoffFactorMilliOutOfBounds` | `invalid_argument` | The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting. | +| `ActivityCutoffTooLow` | `invalid_argument` | An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `. | +| `AddStakeBurnRateLimitExceeded` | `rate_limited` | The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes. | +| `AdminActionProhibitedDuringWeightsWindow` | `too_early` | An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires. | +| `AllNetworksInImmunity` | `too_early` | Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity. | +| `AlphaHighTooLow` | `invalid_argument` | The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid. | +| `AlphaLowOutOfRange` | `invalid_argument` | The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid. | +| `AlreadyApproved` | `already_exists` | The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list. | +| `AlreadyDeposited` | `already_exists` | The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason. | +| `AlreadyFinalized` | `already_exists` | The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`. | +| `AlreadyFinalizing` | `already_exists` | A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying. | +| `AlreadyNoted` | `already_exists` | The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again. | +| `AlreadyStored` | `already_exists` | The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again. | +| `AmountTooLow` | `invalid_argument` | A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount. | +| `AnnouncedColdkeyHashDoesNotMatch` | `invalid_argument` | The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to. | +| `AnnouncementDepositInvariantViolated` | `internal` | Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input. | +| `ArithmeticOverflow` | `internal` | Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts. | +| `AutoEpochAlreadyImminent` | `already_exists` | `trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire. | +| `BadEncKeyLen` | `invalid_argument` | The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing. | +| `BalanceLow` | `insufficient_balance` | The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price. | +| `BalanceWithdrawalError` | `insufficient_balance` | The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up. | +| `BeneficiaryDoesNotOwnHotkey` | `not_authorized` | When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns. | +| `BlockDurationTooLong` | `invalid_argument` | The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`. | +| `BlockDurationTooShort` | `invalid_argument` | The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`. | +| `BondsMovingAverageMaxReached` | `limit_exceeded` | A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root. | +| `CallDisabled` | `disabled` | The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version. | +| `CallFiltered` | `not_authorized` | The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect. | +| `CallUnavailable` | `not_found` | During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet. | +| `CanNotSetRootNetworkWeights` | `invalid_argument` | `set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism. | +| `CannotAddSelfAsDelegateDependency` | `invalid_argument` | A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash. | +| `CannotAffordLockCost` | `insufficient_balance` | The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet. | +| `CannotBurnOrRecycleOnRootSubnet` | `invalid_argument` | `recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn. | +| `CannotEndInPast` | `invalid_argument` | The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater. | +| `CannotReleaseYet` | `too_early` | `release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config. | +| `CannotUseSystemAccount` | `not_authorized` | The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`. | +| `CapNotRaised` | `too_early` | `finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing. | +| `CapRaised` | `limit_exceeded` | A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`. | +| `CapTooLow` | `invalid_argument` | On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry. | +| `ChainIdMismatch` | `invalid_argument` | The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed. | +| `ChangePending` | `already_exists` | A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first. | +| `ChildParentInconsistency` | `invalid_argument` | A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap. | +| `CodeInUse` | `invalid_argument` | `remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal. | +| `CodeInfoNotFound` | `not_found` | No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed. | +| `CodeNotFound` | `not_found` | No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed. | +| `CodeRejected` | `invalid_argument` | The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason. | +| `CodeTooLarge` | `limit_exceeded` | The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract. | +| `ColdKeyAlreadyAssociated` | `already_exists` | The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead. | +| `ColdkeySwapAlreadyDisputed` | `already_exists` | `dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed. | +| `ColdkeySwapAnnounced` | `already_exists` | The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement. | +| `ColdkeySwapAnnouncementNotFound` | `not_found` | `coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first. | +| `ColdkeySwapClearTooEarly` | `too_early` | The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later. | +| `ColdkeySwapDisputed` | `not_authorized` | All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact. | +| `ColdkeySwapReannouncedTooEarly` | `too_early` | `announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later. | +| `ColdkeySwapTooEarly` | `too_early` | `coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then. | +| `CommitRevealDisabled` | `disabled` | A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled. | +| `CommitRevealEnabled` | `disabled` | Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`. | +| `CommittingWeightsTooFast` | `rate_limited` | The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait. | +| `ContractNotFound` | `not_found` | No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated. | +| `ContractReverted` | `internal` | The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value. | +| `ContractTrapped` | `internal` | The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations. | +| `ContributionPeriodEnded` | `expired` | A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized. | +| `ContributionPeriodNotEnded` | `too_early` | The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number. | +| `ContributionTooLow` | `invalid_argument` | The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount. | +| `CreateOriginNotAllowed` | `not_authorized` | A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list. | +| `CurrencyError` | `internal` | A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason. | +| `DeadAccount` | `not_found` | The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs. | +| `DecodingFailed` | `invalid_argument` | Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API. | +| `DelegateDependencyAlreadyExists` | `already_exists` | The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it. | +| `DelegateDependencyNotFound` | `not_found` | `unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info. | +| `DelegateTakeTooHigh` | `invalid_argument` | The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it. | +| `DelegateTakeTooLow` | `invalid_argument` | The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item. | +| `DelegateTxRateLimitExceeded` | `rate_limited` | The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later. | +| `DeltaZero` | `invalid_argument` | The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount. | +| `DepositCannotBeWithdrawn` | `invalid_argument` | The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry. | +| `DepositTooLow` | `invalid_argument` | The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit. | +| `Deprecated` | `disabled` | The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`). | +| `DisabledTemporarily` | `disabled` | The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled. | +| `DrandConnectionFailure` | `internal` | Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints. | +| `Duplicate` | `already_exists` | This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple. | +| `DuplicateChild` | `invalid_argument` | The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid. | +| `DuplicateContract` | `already_exists` | Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address. | +| `DuplicateOffenceReport` | `already_exists` | The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again. | +| `DuplicateOrderInBatch` | `invalid_argument` | Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`. | +| `DuplicateUids` | `invalid_argument` | The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector. | +| `DynamicTempoBlockedByCommitReveal` | `disabled` | `trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs. | +| `Entered` | `already_exists` | Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages. | +| `EpochTriggerAlreadyPending` | `already_exists` | `trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again. | +| `EvmKeyAssociateRateLimitExceeded` | `rate_limited` | `associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later. | +| `EvmKeyAssociationLimitExceeded` | `limit_exceeded` | The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address. | +| `ExistentialDeposit` | `insufficient_balance` | The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant. | +| `ExistingVestingSchedule` | `already_exists` | A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule. | +| `Exited` | `already_exists` | Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting. | +| `ExpectedBeneficiaryOrigin` | `not_authorized` | A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey. | +| `Expendability` | `insufficient_balance` | The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable. | +| `ExpiredWeightCommit` | `expired` | The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time. | +| `FailedToExtractRuntimeVersion` | `invalid_argument` | The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly. | +| `FailedToSchedule` | `internal` | The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated. | +| `FaucetDisabled` | `disabled` | The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead. | +| `FeeOverflow` | `internal` | Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction. | +| `FeeRateTooHigh` | `invalid_argument` | `set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting. | +| `FirstEmissionBlockNumberAlreadySet` | `already_exists` | `start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed. | +| `GasLimitTooHigh` | `invalid_argument` | The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. | +| `GasLimitTooLow` | `invalid_argument` | The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. | +| `GasPriceTooLow` | `invalid_argument` | The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. | +| `HotKeyAccountNotExists` | `not_registered` | The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first. | +| `HotKeyAlreadyDelegate` | `already_exists` | `become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed. | +| `HotKeyAlreadyRegisteredInSubNet` | `already_exists` | A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid. | +| `HotKeyNotRegisteredInNetwork` | `not_registered` | The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first. | +| `HotKeyNotRegisteredInSubNet` | `not_registered` | The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed. | +| `HotKeySetTxRateLimitExceeded` | `rate_limited` | The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks. | +| `HotKeySwapOnSubnetIntervalNotPassed` | `rate_limited` | A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval. | +| `IncorrectCommitRevealVersion` | `invalid_argument` | The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version. | +| `IncorrectPartialFillAmount` | `invalid_argument` | The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`. | +| `IncorrectWeightVersionKey` | `invalid_argument` | The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key. | +| `Indeterministic` | `invalid_argument` | Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically. | +| `InputForwarded` | `invalid_argument` | The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards. | +| `InputLengthsUnequal` | `invalid_argument` | A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length. | +| `InsufficientBalance` | `insufficient_balance` | The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved. | +| `InsufficientInputAmount` | `invalid_argument` | Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output. | +| `InsufficientLiquidity` | `insufficient_liquidity` | The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount. | +| `InsufficientStakeForLock` | `insufficient_balance` | The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first. | +| `InvalidCallFlags` | `invalid_argument` | The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values. | +| `InvalidChainId` | `invalid_argument` | The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction. | +| `InvalidChild` | `invalid_argument` | The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved. | +| `InvalidChildkeyTake` | `invalid_argument` | The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds. | +| `InvalidCrowdloanId` | `not_found` | No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued. | +| `InvalidDerivedAccount` | `invalid_argument` | Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation. | +| `InvalidDerivedAccountId` | `invalid_argument` | Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one). | +| `InvalidDifficulty` | `invalid_argument` | The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block. | +| `InvalidEquivocationProof` | `invalid_argument` | The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set. | +| `InvalidFinalizationConfig` | `invalid_argument` | Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry. | +| `InvalidIdentity` | `invalid_argument` | The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity. | +| `InvalidIpAddress` | `invalid_argument` | The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed. | +| `InvalidIpType` | `invalid_argument` | The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted. | +| `InvalidKeyOwnershipProof` | `invalid_argument` | The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report. | +| `InvalidLeaseBeneficiary` | `invalid_argument` | The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey. | +| `InvalidLiquidityValue` | `invalid_argument` | Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`. | +| `InvalidNonce` | `invalid_argument` | The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`. | +| `InvalidNumRootClaim` | `invalid_argument` | The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number. | +| `InvalidOrigin` | `not_authorized` | The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`. | +| `InvalidPort` | `invalid_argument` | The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port. | +| `InvalidRecoveredPublicKey` | `invalid_argument` | The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format). | +| `InvalidRevealCommitHashNotMatch` | `invalid_argument` | The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid. | +| `InvalidRevealRound` | `expired` | A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number. | +| `InvalidRootClaimThreshold` | `invalid_argument` | The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid. | +| `InvalidRoundNumber` | `invalid_argument` | A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`. | +| `InvalidSchedule` | `invalid_argument` | The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments. | +| `InvalidSeal` | `invalid_argument` | The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit. | +| `InvalidSignature` | `invalid_argument` | Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed. | +| `InvalidSpecName` | `invalid_argument` | The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one. | +| `InvalidSubnetNumber` | `invalid_argument` | A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit. | +| `InvalidTickRange` | `invalid_argument` | Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones. | +| `InvalidValue` | `invalid_argument` | A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`). | +| `InvalidVotingPowerEmaAlpha` | `invalid_argument` | The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid. | +| `InvalidWorkBlock` | `invalid_argument` | The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block. | +| `IssuanceDeactivated` | `disabled` | Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again. | +| `LeaseCannotEndInThePast` | `invalid_argument` | The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease. | +| `LeaseDoesNotExist` | `not_found` | The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated. | +| `LeaseHasNoEndBlock` | `invalid_argument` | The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id. | +| `LeaseHasNotEnded` | `too_early` | The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes. | +| `LeaseNetuidNotFound` | `not_found` | After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete. | +| `LimitOrdersDisabled` | `disabled` | Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet. | +| `LiquidAlphaDisabled` | `disabled` | Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first. | +| `LiquidityRestrictions` | `insufficient_balance` | The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal. | +| `LockHotkeyMismatch` | `invalid_argument` | The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first. | +| `LockIdOverFlow` | `limit_exceeded` | The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem. | +| `MaxAllowedUIdsLessThanCurrentUIds` | `invalid_argument` | `sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid. | +| `MaxAllowedUidsGreaterThanDefaultMaxAllowedUids` | `invalid_argument` | `sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value. | +| `MaxAllowedUidsLessThanMinAllowedUids` | `invalid_argument` | `sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid. | +| `MaxCallDepthReached` | `limit_exceeded` | A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth. | +| `MaxContributionReached` | `limit_exceeded` | The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`. | +| `MaxContributorsReached` | `limit_exceeded` | The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant. | +| `MaxDelegateDependenciesReached` | `limit_exceeded` | `lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first. | +| `MaxValidatorsLargerThanMaxUIds` | `invalid_argument` | `sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid. | +| `MaxWeightExceeded` | `limit_exceeded` | After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting. | +| `MaxWeightTooLow` | `invalid_argument` | The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`. | +| `MaximumContributionTooLow` | `invalid_argument` | The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry. | +| `MechanismDoesNotExist` | `subnet_not_exists` | The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet. | +| `MigrationInProgress` | `too_early` | A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it. | +| `MinAllowedUidsGreaterThanCurrentUids` | `invalid_argument` | `sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid. | +| `MinAllowedUidsGreaterThanMaxAllowedUids` | `invalid_argument` | `sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid. | +| `MinimumContributionTooHigh` | `invalid_argument` | The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`. | +| `MinimumContributionTooLow` | `invalid_argument` | The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value. | +| `MinimumThreshold` | `invalid_argument` | The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case. | +| `MultiBlockMigrationsOngoing` | `too_early` | Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade. | +| `Named` | `invalid_argument` | An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map. | +| `NeedWaitingMoreBlocksToStarCall` | `too_early` | The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens. | +| `NegativeSigmoidSteepness` | `invalid_argument` | A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root. | +| `NetworkDissolveAlreadyQueued` | `already_exists` | The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request. | +| `NetworkTxRateLimitExceeded` | `rate_limited` | The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks. | +| `NeuronNoValidatorPermit` | `not_authorized` | The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator. | +| `NewColdKeyIsHotkey` | `invalid_argument` | The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey. | +| `NewHotKeyIsSameWithOld` | `invalid_argument` | swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey. | +| `NewHotKeyNotCleanForRootSwap` | `invalid_argument` | The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey. | +| `NoApprovalsNeeded` | `invalid_argument` | The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it. | +| `NoChainExtension` | `disabled` | The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against. | +| `NoContribution` | `not_found` | The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question. | +| `NoDeposit` | `not_found` | No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block. | +| `NoExistingLock` | `not_found` | move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey. | +| `NoMigrationPerformed` | `invalid_argument` | A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument. | +| `NoNeuronIdAvailable` | `limit_exceeded` | Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire. | +| `NoPermission` | `not_authorized` | The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments. | +| `NoSelfProxy` | `invalid_argument` | An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account. | +| `NoTimepoint` | `invalid_argument` | No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`. | +| `NoWeightsCommitFound` | `not_found` | A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window. | +| `NonAssociatedColdKey` | `not_authorized` | The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it. | +| `NonDefaultComposite` | `invalid_argument` | The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way. | +| `NonZeroRefCount` | `invalid_argument` | The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first. | +| `NoneValue` | `not_found` | Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization. | +| `NotAllowed` | `not_authorized` | Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value. | +| `NotAuthorized` | `not_authorized` | The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`. | +| `NotConfigured` | `disabled` | The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants. | +| `NotEnoughAlphaOutToRecycle` | `insufficient_liquidity` | A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount. | +| `NotEnoughBalanceToPaySwapColdKey` | `insufficient_balance` | The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap. | +| `NotEnoughBalanceToPaySwapHotKey` | `insufficient_balance` | The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying. | +| `NotEnoughBalanceToStake` | `insufficient_balance` | The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid). | +| `NotEnoughStake` | `insufficient_balance` | The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs. | +| `NotEnoughStakeToSetChildkeys` | `insufficient_balance` | Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value. | +| `NotEnoughStakeToSetWeights` | `insufficient_balance` | Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`. | +| `NotEnoughStakeToWithdraw` | `insufficient_balance` | An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage). | +| `NotFound` | `not_found` | The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state. | +| `NotNoted` | `not_found` | The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored. | +| `NotOwner` | `not_authorized` | Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash. | +| `NotPermittedOnRootSubnet` | `invalid_argument` | An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0. | +| `NotProxy` | `not_authorized` | The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call. | +| `NotReadyToDissolve` | `too_early` | `dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record. | +| `NotRequested` | `not_found` | The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`. | +| `NotRootSubnet` | `invalid_argument` | A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0. | +| `NotSubnetOwner` | `not_authorized` | The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`). | +| `NothingAuthorized` | `not_found` | No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code. | +| `OrderAlreadyProcessed` | `already_exists` | The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`. | +| `OrderCancelled` | `expired` | The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order. | +| `OrderExpired` | `expired` | The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value. | +| `OrderNetUidMismatch` | `invalid_argument` | An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out. | +| `OutOfBounds` | `invalid_argument` | A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug. | +| `OutOfGas` | `limit_exceeded` | The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight. | +| `OutOfTransientStorage` | `limit_exceeded` | A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit. | +| `OutputBufferTooSmall` | `invalid_argument` | The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug. | +| `Overflow` | `internal` | A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values. | +| `POWRegistrationDisabled` | `disabled` | `sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled. | +| `PalletHotkeyNotRegistered` | `not_registered` | Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs. | +| `PartialFillsNotEnabled` | `disabled` | A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing. | +| `PauseFailed` | `invalid_argument` | A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause. | +| `PaymentOverflow` | `internal` | Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction. | +| `PreLogExists` | `invalid_argument` | An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it. | +| `PriceConditionNotMet` | `too_early` | The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field. | +| `PriceLimitExceeded` | `insufficient_liquidity` | The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting. | +| `ProportionOverflow` | `invalid_argument` | The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX. | +| `PulseVerificationError` | `invalid_argument` | BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key). | +| `RandomSubjectTooLong` | `limit_exceeded` | The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section. | +| `ReentranceDenied` | `invalid_argument` | A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag. | +| `Reentrancy` | `internal` | EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call. | +| `RegistrationNotPermittedOnRootSubnet` | `invalid_argument` | A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership. | +| `RegistrationPriceLimitExceeded` | `limit_exceeded` | `burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay. | +| `RelayerMissMatch` | `invalid_argument` | The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload. | +| `RelayerRequiredForPartialFill` | `invalid_argument` | A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount. | +| `Requested` | `invalid_argument` | The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed. | +| `RequireSudo` | `not_authorized` | The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item. | +| `RescheduleNoChange` | `invalid_argument` | The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block. | +| `ReservesOutOfBalance` | `insufficient_liquidity` | Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry. | +| `ReservesTooLow` | `insufficient_liquidity` | The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size. | +| `ResumeFailed` | `invalid_argument` | A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume. | +| `RevealPeriodTooLarge` | `invalid_argument` | `set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | +| `RevealPeriodTooSmall` | `invalid_argument` | `set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | +| `RevealTooEarly` | `too_early` | A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch. | +| `RootNetUidNotAllowed` | `invalid_argument` | The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet. | +| `RootNetworkDoesNotExist` | `subnet_not_exists` | Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`. | +| `SameAutoStakeHotkeyAlreadySet` | `already_exists` | The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted. | +| `SameNetuid` | `invalid_argument` | A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ. | +| `SenderInSignatories` | `invalid_argument` | The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting. | +| `ServingRateLimitExceeded` | `rate_limited` | `serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait. | +| `SettingWeightsTooFast` | `rate_limited` | The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks. | +| `SignatoriesOutOfOrder` | `invalid_argument` | The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting. | +| `SlippageTooHigh` | `insufficient_liquidity` | A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution. | +| `SpaceLimitExceeded` | `rate_limited` | The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage. | +| `SpecVersionNeedsToIncrease` | `invalid_argument` | The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain. | +| `StakeTooLowForRoot` | `insufficient_balance` | `root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`). | +| `StakeUnavailable` | `insufficient_balance` | An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked. | +| `StakingRateLimitExceeded` | `rate_limited` | Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block. | +| `StartCallNotReady` | `too_early` | `start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder. | +| `StateChangeDenied` | `not_authorized` | The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context. | +| `StorageDepositLimitExhausted` | `limit_exceeded` | The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`. | +| `StorageDepositNotEnoughFunds` | `insufficient_balance` | The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit. | +| `StorageOverflow` | `internal` | Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit. | +| `SubNetRegistrationDisabled` | `disabled` | Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid. | +| `SubnetBuybackRateLimitExceeded` | `rate_limited` | A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback. | +| `SubnetDoesNotExist` | `subnet_not_exists` | The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters. | +| `SubnetLimitReached` | `limit_exceeded` | `register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable. | +| `SubnetNotExists` | `subnet_not_exists` | The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved. | +| `SubtokenDisabled` | `subtoken_disabled` | The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved. | +| `SwapInputTooLarge` | `insufficient_liquidity` | The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed. | +| `SwapReturnedZero` | `insufficient_liquidity` | The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit. | +| `SymbolAlreadyInUse` | `already_exists` | The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken. | +| `SymbolDoesNotExist` | `not_found` | The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry. | +| `TargetBlockNumberInPast` | `invalid_argument` | The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block. | +| `TempoOutOfBounds` | `invalid_argument` | `set_tempo` was given a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range. Check the tempo argument against those chain constants and pick a value inside the bounds. | +| `TerminatedInConstructor` | `internal` | The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls. | +| `TerminatedWhileReentrant` | `invalid_argument` | `seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. | +| `TooBig` | `limit_exceeded` | The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it. | +| `TooFew` | `invalid_argument` | The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. | +| `TooFewSignatories` | `invalid_argument` | The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. | +| `TooMany` | `limit_exceeded` | A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`. | +| `TooManyCalls` | `limit_exceeded` | The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions. | +| `TooManyChildren` | `limit_exceeded` | `set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries. | +| `TooManyFieldsInCommitmentInfo` | `limit_exceeded` | The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit. | +| `TooManyFreezes` | `limit_exceeded` | The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first. | +| `TooManyHolds` | `limit_exceeded` | The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another. | +| `TooManyPendingExtrinsics` | `limit_exceeded` | `store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire. | +| `TooManyRegistrationsThisBlock` | `rate_limited` | Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block. | +| `TooManyRegistrationsThisInterval` | `rate_limited` | Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start. | +| `TooManyReserves` | `limit_exceeded` | The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another. | +| `TooManySignatories` | `limit_exceeded` | The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant. | +| `TooManyTopics` | `limit_exceeded` | The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit. | +| `TooManyUIDsPerMechanism` | `limit_exceeded` | Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit. | +| `TooManyUnrevealedCommits` | `limit_exceeded` | `commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again. | +| `TooSoon` | `rate_limited` | A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change. | +| `TransactionMustComeFromEOA` | `not_authorized` | Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead. | +| `TransactorAccountShouldBeHotKey` | `not_authorized` | The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin. | +| `TransferDisallowed` | `disabled` | A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first. | +| `TransferFailed` | `insufficient_balance` | A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit. | +| `TrimmingWouldExceedMaxImmunePercentage` | `limit_exceeded` | Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target. | +| `TxChildkeyTakeRateLimitExceeded` | `rate_limited` | `set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder. | +| `TxRateLimitExceeded` | `rate_limited` | An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass. | +| `UidMapCouldNotBeCleared` | `internal` | During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it. | +| `UidVecContainInvalidOne` | `invalid_argument` | The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`). | +| `UidsLengthExceedUidsInSubNet` | `limit_exceeded` | The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector. | +| `UnableToRecoverPublicKey` | `invalid_argument` | While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key. | +| `Unannounced` | `too_early` | The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`. | +| `Unauthorized` | `not_authorized` | In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`. | +| `Undefined` | `internal` | Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs. | +| `Underflow` | `internal` | A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`. | +| `UnexpectedTimepoint` | `invalid_argument` | A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry. | +| `UnexpectedUnreserveLeftover` | `internal` | While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`. | +| `UnlockAmountTooHigh` | `insufficient_balance` | An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount. | +| `Unproxyable` | `not_authorized` | The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call. | +| `Unreachable` | `internal` | `announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring. | +| `UnverifiedPulse` | `invalid_argument` | Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`. | +| `ValueNotInBounds` | `invalid_argument` | An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds. | +| `ValueTooLarge` | `limit_exceeded` | A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant. | +| `VestingBalance` | `insufficient_balance` | The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs. | +| `VotingPowerTrackingNotEnabled` | `disabled` | Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic. | +| `WaitingForDissolvedSubnetCleanup` | `too_early` | The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes. | +| `WeightExceedsAbsoluteMax` | `limit_exceeded` | `set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant. | +| `WeightVecLengthIsLow` | `invalid_argument` | The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid. | +| `WeightVecNotEqualSize` | `invalid_argument` | The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID. | +| `WithdrawFailed` | `insufficient_balance` | Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance. | +| `WrongTimepoint` | `invalid_argument` | The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint. | +| `XCMDecodeFailed` | `invalid_argument` | The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports. | +| `ZeroBalanceAfterWithdrawn` | `insufficient_balance` | Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn. | +| `ZeroShareInBatch` | `invalid_argument` | An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch. | diff --git a/sdk/python/bittensor/cli/main.py b/sdk/python/bittensor/cli/main.py index a5bf86f889..911d3890be 100644 --- a/sdk/python/bittensor/cli/main.py +++ b/sdk/python/bittensor/cli/main.py @@ -22,6 +22,7 @@ from .. import __version__, wallets from .._generated.errors import ERRORS from ..config import get as config_default +from ..error_descriptions import DESCRIPTIONS from ..intents import list_tools from ..result import EXPLANATIONS, REMEDIATION, ErrorCode, classify_error from ..settings import DEFAULT_NETWORK @@ -326,6 +327,7 @@ def _chain_error_matches(query: str) -> list[dict[str, str]]: "name": info.name, "code": code.value, "docs": info.docs, + "description": DESCRIPTIONS.get(info.name, ""), "help": REMEDIATION[code], } ) diff --git a/sdk/python/bittensor/cli/output.py b/sdk/python/bittensor/cli/output.py index d614b0e4fa..a00530d5d3 100644 --- a/sdk/python/bittensor/cli/output.py +++ b/sdk/python/bittensor/cli/output.py @@ -1496,6 +1496,8 @@ def _print_failure(self, result: ExtrinsicResult) -> None: return if error.name: self._sub_diag("note", f"the chain rejected the call with `{error.name}`") + if error.description: + self._sub_diag("note", error.description) self._sub_diag("help", error.remediation) if result.explorer_url: self._sub_diag("see", result.explorer_url) @@ -1554,8 +1556,10 @@ def error_catalog(self, title: str, records: list[dict[str, str]]) -> None: self._out.print(f"[dim]{len(records)} {suffix}[/dim]") def explain_chain(self, matches: list[dict[str, str]]) -> None: - """Explain exact chain error names: the on-chain docs plus the semantic - code each classifies to. One block per pallet when a name collides.""" + """Explain exact chain error names: the researched description (trigger + plus where to check) with the on-chain docs as fallback, and the + semantic code each classifies to. One block per pallet when a name + collides.""" if self.json_mode: self._json(matches[0] if len(matches) == 1 else matches) return @@ -1568,7 +1572,8 @@ def explain_chain(self, matches: list[dict[str, str]]) -> None: header.append(f"{match['pallet']}.{match['name']}") self._out.print(header) self._out.print() - self._out.print(_prose(_diagnostic(match["docs"] or match["name"]))) + body = match.get("description") or match["docs"] or match["name"] + self._out.print(_prose(_diagnostic(body))) self._out.print() self._sub_diag("help", match["help"], console=self._out) for code in dict.fromkeys(match["code"] for match in matches): diff --git a/sdk/python/bittensor/error_descriptions.py b/sdk/python/bittensor/error_descriptions.py new file mode 100644 index 0000000000..b1219e8f72 --- /dev/null +++ b/sdk/python/bittensor/error_descriptions.py @@ -0,0 +1,1845 @@ +"""Per-chain-error descriptions: what the error means and where to check. + +Every name classified in :mod:`bittensor.error_map` has a description here that +tells an agent what condition triggered the error and which state, argument, or +query to inspect. ``python -m codegen.check --names`` enforces that this table +and ``NAME_TO_CODE`` cover exactly the same names, so a newly classified error +must be described before it can ship. + +Grouped by the pallet that (first) declares the error, mirroring the layout of +``error_map.py``. Names shared across pallets carry one description covering +all meanings. +""" + +from __future__ import annotations + +DESCRIPTIONS: dict[str, str] = { + # ── AdminUtils ────────────────────────────────────────────────────────── + "BondsMovingAverageMaxReached": ( + "A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the " + "cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or " + "submit the call as root." + ), + "MaxAllowedUIdsLessThanCurrentUIds": ( + "`sudo_set_max_allowed_uids` was given a value below the number of neurons already " + "registered on the subnet. Compare the `max_allowed_uids` argument against " + "`SubnetworkN` for that netuid." + ), + "MaxAllowedUidsGreaterThanDefaultMaxAllowedUids": ( + "`sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare " + "the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value." + ), + "MaxAllowedUidsLessThanMinAllowedUids": ( + "`sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. " + "Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid." + ), + "MaxValidatorsLargerThanMaxUIds": ( + "`sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID " + "capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for " + "that netuid." + ), + "MinAllowedUidsGreaterThanCurrentUids": ( + "`sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons " + "currently registered on the subnet. Compare the `min_allowed_uids` argument against " + "`SubnetworkN` for that netuid." + ), + "MinAllowedUidsGreaterThanMaxAllowedUids": ( + "`sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum " + "UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for " + "that netuid." + ), + "NegativeSigmoidSteepness": ( + "A non-root caller (subnet owner) passed a negative value to " + "`sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the " + "root origin. Use a non-negative `steepness` or submit the call as root." + ), + "NotPermittedOnRootSubnet": ( + "An admin-utils call that only applies to regular subnets (burn half-life, burn " + "increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at " + "the root network. Check that the `netuid` argument is not the root netuid 0." + ), + "POWRegistrationDisabled": ( + "`sudo_set_network_pow_registration_allowed` unconditionally fails because " + "proof-of-work registration is deprecated and its toggle can no longer be changed. " + "Nothing to check; the call is permanently disabled." + ), + "SubnetDoesNotExist": ( + "The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` " + "argument against `NetworksAdded` (the set of existing subnets) before setting " + "hyperparameters." + ), + "ValueNotInBounds": ( + "An admin-utils argument fell outside its allowed range: `min_burn` must be below " + "`MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` " + "and the min burn, and `max_epochs_per_block` at least 1. Check the argument against " + "those bounds." + ), + # ── Balances ──────────────────────────────────────────────────────────── + "DeadAccount": ( + "The beneficiary account does not exist and this operation is not allowed to create it. " + "Check `System.Account` for the destination: it must already hold at least the " + "existential deposit before the operation runs." + ), + "DeltaZero": ( + "The issuance adjustment was called with a delta of zero, which is meaningless. Check " + "the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive " + "amount." + ), + "ExistentialDeposit": ( + "The amount is too small to create the destination account: its resulting balance would " + "sit below the existential deposit. Compare the transfer value plus the destination's " + "current free balance against the `ExistentialDeposit` constant." + ), + "ExistingVestingSchedule": ( + "A vesting schedule already exists for the target account and this call cannot add " + "another. Check the account's `Vesting` storage entry before attempting to set a new " + "vested transfer or schedule." + ), + "Expendability": ( + "The transfer or payment would drop the sender below the existential deposit and kill " + "the account while keep-alive semantics are required. Compare the sender's free balance " + "minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` " + "if reaping is acceptable." + ), + "InsufficientBalance": ( + "The caller's spendable balance is below what the operation needs, whether a plain " + "transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare " + "the account's free balance in `System.Account` (net of holds, freezes, and fees) " + "against the amount being moved." + ), + "IssuanceDeactivated": ( + "Total issuance cannot be adjusted because issuance has already been deactivated. Check " + "the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` " + "again." + ), + "LiquidityRestrictions": ( + "The withdrawal is blocked by locks or freezes on the account even though the raw " + "balance looks sufficient. Check the account's `Locks` and `Freezes` entries and " + "compare the frozen amount against what would remain after the withdrawal." + ), + "TooManyFreezes": ( + "The account already has the maximum number of balance freezes, so a new freeze cannot " + "be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an " + "existing freeze must be thawed first." + ), + "TooManyHolds": ( + "The account already carries the maximum number of balance holds, one per hold reason " + "variant. Check the account's `Holds` entry; an existing hold must be released before a " + "new reason can place another." + ), + "TooManyReserves": ( + "The account already has the maximum number of named reserves. Check the account's " + "`Reserves` entry against the `MaxReserves` constant; a named reserve must be " + "unreserved before adding another." + ), + "VestingBalance": ( + "The account's balance is locked under a vesting schedule, leaving too little usable " + "balance to send the requested value. Check the account's `Vesting` schedules and its " + "lock in `Locks`, and compare the unvested (still locked) amount against what the " + "transfer needs." + ), + # ── Commitments ───────────────────────────────────────────────────────── + "AccountNotAllowedCommit": ( + "Raised by `set_commitment` when the runtime commit check fails: the subnet must exist " + "and the signing hotkey must be registered on it. Verify the `netuid` and that the " + "hotkey has a UID on that subnet." + ), + "SpaceLimitExceeded": ( + "The commitment would push the account's byte quota for the current epoch over the cap; " + "each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid " + "and account against `MaxSpace`, or wait for the next epoch to reset usage." + ), + "TooManyFieldsInCommitmentInfo": ( + "The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than " + "the pallet's `MaxFields` config allows. Count the fields in the `info` argument and " + "trim to the `MaxFields` limit." + ), + "UnexpectedUnreserveLeftover": ( + "While lowering a commitment deposit, `Currency::unreserve` failed to return the full " + "difference, leaving a leftover, which signals an internal inconsistency. Check the " + "account's reserved balance against the deposit recorded in `CommitmentOf`." + ), + # ── Contracts ─────────────────────────────────────────────────────────── + "CannotAddSelfAsDelegateDependency": ( + "A contract called `lock_delegate_dependency` with its own code hash, which is not " + "permitted. Check the code hash argument passed to the delegate dependency API against " + "the contract's own code hash." + ), + "CodeInUse": ( + "`remove_code` was refused because at least one contract instance still references the " + "code hash. Check the code's reference count and terminate or `set_code` the contracts " + "using it before removal." + ), + "CodeInfoNotFound": ( + "No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit " + "metadata cannot be read. Verify the code hash argument and that the code was uploaded " + "and not since removed." + ), + "CodeNotFound": ( + "No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` " + "argument used in instantiation, `set_code`, or a delegate call, and that the code was " + "uploaded via `upload_code` and not removed." + ), + "CodeRejected": ( + "The uploaded WASM failed validation, most often because it imports a host API the node " + "does not support, e.g. newer ink! against an older node. Rerun the node with " + "`-lruntime::contracts=debug` to see the detailed rejection reason." + ), + "CodeTooLarge": ( + "The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum " + "code length in the pallet's schedule. Compare the WASM binary size against the " + "schedule's code length limit and shrink the contract." + ), + "ContractNotFound": ( + "No contract instance exists at the destination address; the account has no " + "`ContractInfoOf` entry. Verify the `dest` address and that the contract was " + "instantiated and has not been terminated." + ), + "ContractReverted": ( + "The contract ran to completion but returned with the REVERT flag set, rolling back its " + "state changes; only extrinsics surface this as an error. Dry-run the call via RPC and " + "decode the returned output data for the contract's error value." + ), + "ContractTrapped": ( + "The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or " + "memory violation, instead of returning normally. Dry-run the call with debug messages " + "enabled and check the input data against the contract's expectations." + ), + "DecodingFailed": ( + "Input bytes passed to a contract API host function could not be SCALE-decoded into the " + "expected type. Check the encoding of the call's input data or the argument bytes the " + "contract passes to the runtime API." + ), + "DelegateDependencyAlreadyExists": ( + "The contract called `lock_delegate_dependency` for a code hash it has already locked. " + "Check the contract's recorded delegate dependencies before adding, and unlock the old " + "entry first if replacing it." + ), + "DelegateDependencyNotFound": ( + "`unlock_delegate_dependency` was called for a code hash that is not among the " + "contract's locked delegate dependencies. Check the code hash argument against the " + "dependencies recorded in the contract's info." + ), + "DuplicateContract": ( + "Instantiation would create a contract at an address already occupied by an existing " + "contract. Check the derived contract address and vary the `salt` argument to obtain a " + "fresh address." + ), + "Indeterministic": ( + "Code flagged as non-deterministic (e.g. using floating point) was used where " + "determinism is enforced, such as on-chain instantiation or calls. Check the " + "determinism mode the code was uploaded with and rebuild the contract " + "deterministically." + ), + "InputForwarded": ( + "The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT " + "flag and then tried to read or forward it again. Check the call flags used; use " + "CLONE_INPUT when the input is still needed afterwards." + ), + "InvalidCallFlags": ( + "The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or " + "disallowed combination; delegate calls accept only a restricted flag set. Check the " + "flags argument against the supported `CallFlags` bit values." + ), + "InvalidSchedule": ( + "The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` " + "for a basic operation, making gas conversion impossible. This is a runtime " + "configuration issue; inspect the `Schedule` constant rather than call arguments." + ), + "MaxCallDepthReached": ( + "A nested contract call would exceed the maximum call stack depth defined in the pallet " + "schedule. Inspect the cross-contract call chain for deep or unbounded recursion and " + "flatten it or raise the configured depth." + ), + "MaxDelegateDependenciesReached": ( + "`lock_delegate_dependency` failed because the contract already holds the maximum " + "number of delegate dependencies allowed by the runtime. Check the " + "`MaxDelegateDependencies` config value and unlock unused dependencies first." + ), + "MigrationInProgress": ( + "A multi-block storage migration of the contracts pallet is still running, so other " + "extrinsics of the pallet are rejected until it completes. Check the migration status " + "in storage and retry once done, or submit `migrate` calls to advance it." + ), + "NoChainExtension": ( + "The contract invoked `call_chain_extension` but this runtime registers no chain " + "extension; such code is normally rejected at upload. Check that the target chain " + "provides the chain extension the contract was built against." + ), + "NoMigrationPerformed": ( + "A `migrate` call ran but no migration step executed, either because no migration is " + "pending or the supplied `weight_limit` is too small for one step. Check the " + "in-progress migration status and increase the weight limit argument." + ), + "OutOfBounds": ( + "A pointer and length pair passed to a contract API host function references memory " + "outside the contract's sandbox. Check the buffer pointers and lengths the contract " + "passes to seal functions; this usually indicates a low-level contract bug." + ), + "OutOfGas": ( + "The contract exhausted the gas limit supplied for this execution before completing. " + "Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC " + "to estimate the required weight." + ), + "OutOfTransientStorage": ( + "A write would exceed the per-execution byte limit for transient storage. Check how " + "much data the contract places in transient storage during the call against the " + "runtime's transient storage limit." + ), + "OutputBufferTooSmall": ( + "The output buffer the contract supplied to an API call is smaller than the data the " + "runtime needs to write back. Check the output length pointer the contract passes and " + "enlarge the buffer; usually a contract-side bug." + ), + "RandomSubjectTooLong": ( + "The subject buffer given to the deprecated `seal_random` API exceeds the schedule's " + "`subject_len` limit. Shorten the randomness subject the contract passes or check the " + "schedule's limits section." + ), + "ReentranceDenied": ( + "A call tried to re-enter a contract already on the call stack without reentrancy being " + "allowed, or contract code called back into the contracts pallet through the runtime. " + "Check the callee address against the current call stack and the ALLOW_REENTRY call " + "flag." + ), + "StateChangeDenied": ( + "The contract invoked a state-modifying host function, such as a storage write, " + "transfer, or value-bearing call, while executing in read-only mode. Check whether the " + "enclosing call was made with the read-only flag or from a static context." + ), + "StorageDepositLimitExhausted": ( + "The execution created more storage than the caller's `storage_deposit_limit` allows to " + "be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a " + "dry-run reports the required `storage_deposit`." + ), + "StorageDepositNotEnoughFunds": ( + "The origin's free balance cannot cover the storage deposit limit specified or required " + "for this call. Check the caller's withdrawable balance against the " + "`storage_deposit_limit` argument and the dry-run's reported deposit." + ), + "TerminatedInConstructor": ( + "The contract called `seal_terminate` inside its constructor, self-destructing during " + "instantiation, which is forbidden. Inspect the constructor logic; termination is only " + "allowed in regular message calls." + ), + "TerminatedWhileReentrant": ( + "`seal_terminate` was called on a contract that appears more than once on the call " + "stack, so termination was refused. Check the call chain for reentrant calls into the " + "contract being terminated." + ), + "TooManyTopics": ( + "The number of topics passed to `seal_deposit_event` exceeds the schedule's " + "`event_topics` limit. Reduce the number of indexed topics in the contract's event " + "definition or compare against the schedule limit." + ), + "TransferFailed": ( + "A balance transfer performed during the contract call failed, most likely because the " + "sender lacks enough free balance. Check the transferring account's free balance " + "against the `value` being sent, accounting for the existential deposit." + ), + "ValueTooLarge": ( + "A value written to contract storage or emitted as event data exceeds the " + "`MaxValueSize` limit. Compare the size of the stored value or event payload against " + "the runtime's maximum value size constant." + ), + "XCMDecodeFailed": ( + "The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a " + "versioned XCM message. Check the XCM encoding and version the contract produces " + "against what the runtime supports." + ), + # ── Crowdloan ─────────────────────────────────────────────────────────── + "AlreadyFinalized": ( + "The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, " + "dissolve, and the update calls are all rejected. Check the `finalized` field of the " + "`Crowdloans` entry for the given `crowdloan_id`." + ), + "AlreadyFinalizing": ( + "A `finalize` call was made while another finalization is still in progress, i.e. the " + "dispatched call from a previous finalize has not cleared. Check that the " + "`CurrentCrowdloanId` storage value is empty before retrying." + ), + "BlockDurationTooLong": ( + "The requested `end` block is more than `MaximumBlockDuration` blocks after the current " + "block. Compare `end` minus the current block number against the `MaximumBlockDuration` " + "pallet constant when calling `create` or `update_end`." + ), + "BlockDurationTooShort": ( + "The requested `end` block is fewer than `MinimumBlockDuration` blocks after the " + "current block. Compare `end` minus the current block number against the " + "`MinimumBlockDuration` pallet constant when calling `create` or `update_end`." + ), + "CallUnavailable": ( + "During `finalize` the crowdloan's stored call could not be fetched from preimage " + "storage, so nothing was dispatched. Check that the preimage referenced by the `call` " + "field of the `Crowdloans` entry still exists in the preimage pallet." + ), + "CannotEndInPast": ( + "The `end` block passed to `create` or `update_end` is not after the current block. " + "Compare the `end` argument against the current block number; it must be strictly " + "greater." + ), + "CapNotRaised": ( + "`finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare " + "the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or " + "lower the cap with `update_cap` before finalizing." + ), + "CapRaised": ( + "A contribution was attempted on a crowdloan whose `raised` amount has already reached " + "its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` " + "fields of the `Crowdloans` entry for the `crowdloan_id`." + ), + "CapTooLow": ( + "On `create` the `cap` is not strictly greater than the initial `deposit`, or on " + "`update_cap` the new cap is below the amount already raised. Compare the cap argument " + "against the `deposit` or the `raised` field of the `Crowdloans` entry." + ), + "ContributionPeriodEnded": ( + "A contribution was made at or after the crowdloan's `end` block. Compare the `end` " + "field of the `Crowdloans` entry with the current block number; the creator can extend " + "it with `update_end` while the crowdloan is not finalized." + ), + "ContributionPeriodNotEnded": ( + "The operation requires the crowdloan's contribution period to be over, but the current " + "block is still before the crowdloan's `end` block. Compare the `end` field of the " + "`Crowdloans` entry for the `crowdloan_id` with the current block number." + ), + "ContributionTooLow": ( + "The `amount` passed to `contribute` is below the crowdloan's configured minimum " + "contribution. Check the `min_contribution` field of the `Crowdloans` entry for the " + "`crowdloan_id` and contribute at least that amount." + ), + "DepositCannotBeWithdrawn": ( + "The creator called `withdraw` but holds nothing above the initial deposit, which stays " + "locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry " + "with the `deposit` field of the `Crowdloans` entry." + ), + "DepositTooLow": ( + "The `deposit` argument to `create` is below the pallet's required minimum. Check the " + "`MinimumDeposit` pallet constant and create the crowdloan with at least that initial " + "deposit." + ), + "InvalidCrowdloanId": ( + "No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it " + "was never created or has been dissolved. Check `Crowdloans` for the id and " + "`NextCrowdloanId` for the range of ids ever issued." + ), + "InvalidFinalizationConfig": ( + "Exactly one of `call` or `target_address` must be set, but both or neither were " + "provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` " + "time. Check those two fields on the `create` arguments or the `Crowdloans` entry." + ), + "InvalidOrigin": ( + "The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, " + "`dissolve`, and the update calls. Compare the signing account with the `creator` field " + "of the `Crowdloans` entry for the `crowdloan_id`." + ), + "MaxContributionReached": ( + "The contributor's cumulative contribution already equals the crowdloan's " + "per-contributor cap, so further contributions are rejected. Compare their " + "`Contributions` entry with the `MaxContributions` value for the `crowdloan_id`." + ), + "MaxContributorsReached": ( + "The crowdloan already has the maximum number of distinct contributors, so accounts " + "without an existing contribution are rejected. Compare the `contributors_count` field " + "of the `Crowdloans` entry with the `MaxContributors` pallet constant." + ), + "MaximumContributionTooLow": ( + "The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's " + "`min_contribution` or below the creator's existing contribution. Check both against " + "the `Crowdloans` entry and the creator's `Contributions` entry." + ), + "MinimumContributionTooHigh": ( + "The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's " + "configured per-contributor maximum. Compare it with the `MaxContributions` entry for " + "the `crowdloan_id`." + ), + "MinimumContributionTooLow": ( + "The minimum contribution given to `create` or `update_min_contribution` is below the " + "chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise " + "the `min_contribution` argument to at least that value." + ), + "NoContribution": ( + "The account has no contribution recorded for this crowdloan, so `withdraw` has nothing " + "to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` " + "double map under the `crowdloan_id` for the account in question." + ), + "NotReadyToDissolve": ( + "`dissolve` was called while outside contributions remain: the crowdloan's `raised` " + "amount still exceeds the creator's own contribution. Call `refund` until only the " + "creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` " + "record." + ), + "Underflow": ( + "A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding " + "`cap` when computing remaining room, or a contributor count decrement, indicating " + "inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the " + "`crowdloan_id`." + ), + # ── Drand ─────────────────────────────────────────────────────────────── + "DrandConnectionFailure": ( + "Declared for failures reaching the drand HTTP API, but pulse fetching happens in the " + "offchain worker, which logs errors instead of raising this. Check the node's offchain " + "worker logs and outbound connectivity to the drand endpoints." + ), + "InvalidRoundNumber": ( + "A submitted drand pulse has an unacceptable round: the first pulse ever stored must " + "have a round greater than zero, and each later pulse must be exactly `LastStoredRound` " + "plus one. Compare the pulse round against `LastStoredRound`." + ), + "NoneValue": ( + "Template leftover in the drand pallet meaning a storage value was read before ever " + "being set; no current code path raises it. If seen, inspect the drand pallet's storage " + "items for missing initialization." + ), + "PulseVerificationError": ( + "BLS signature verification of a submitted drand pulse against the stored beacon " + "configuration failed. Check the pulse's signature and round against the `BeaconConfig` " + "storage (drand quicknet public key)." + ), + "StorageOverflow": ( + "Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; " + "no current code path raises it. If seen, inspect the drand pallet's stored counters " + "for values near the u32 limit." + ), + "UnverifiedPulse": ( + "Declared for drand pulses that fail validity checks, but current code raises " + "`PulseVerificationError` for verification failures and silently skips unverified " + "pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`." + ), + # ── EVM ───────────────────────────────────────────────────────────────── + "BalanceLow": ( + "The sender's mapped account cannot cover the transaction's value plus maximum gas fee, " + "detected during validation or when withdrawing the fee. Check the account balance " + "against `value` plus `gas_limit` times the effective gas price." + ), + "CreateOriginNotAllowed": ( + "A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address " + "not permitted to deploy contracts. Check whether the deploying address is in the " + "chain's allowed-deployers list." + ), + "FeeOverflow": ( + "Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or " + "converting the EVM fee into Substrate balance decimals. Check for absurdly large " + "`gas_limit` or fee-per-gas values in the transaction." + ), + "GasLimitTooHigh": ( + "The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. " + "Compare the `gas_limit` argument against the chain's block gas limit and lower it." + ), + "GasLimitTooLow": ( + "The transaction's `gas_limit` is below the intrinsic gas required, or too small to " + "cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing " + "against an `eth_estimateGas` result." + ), + "GasPriceTooLow": ( + "The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the " + "block base fee, the priority fee exceeds the max fee, or the fee inputs are " + "inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the " + "chain's base fee." + ), + "InvalidChainId": ( + "The EIP-155 chain id encoded in the signed transaction does not match this chain's " + "configured chain id. Compare the transaction's chain id with the value returned by " + "`eth_chainId` and re-sign the transaction." + ), + "InvalidNonce": ( + "The transaction nonce does not match the sender's current account nonce, being either " + "too low (already used) or too high. Compare the transaction's `nonce` with the " + "sender's on-chain nonce from `eth_getTransactionCount`." + ), + "NotAllowed": ( + "Contract deployment was blocked because the source address is not in the " + "`WhitelistedCreators` list while the whitelist check is enabled. Check the deployer " + "address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value." + ), + "PaymentOverflow": ( + "Arithmetic overflowed while computing the total payment or refund for an EVM " + "transaction, such as refunding remaining gas at the effective gas price. Check for " + "extreme gas price or gas limit values in the transaction." + ), + "Reentrancy": ( + "EVM execution re-entered the pallet while another EVM execution was already in " + "progress on the same thread, e.g. a precompile or runtime call dispatching back into " + "the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM " + "call." + ), + "TransactionMustComeFromEOA": ( + "Rejected per EIP-3607: the sender address has contract code deployed, and transactions " + "must originate from externally owned accounts. Check `eth_getCode` for the `source` " + "address and sign with a plain EOA key instead." + ), + "Undefined": ( + "Catch-all EVM validation error for cases without a dedicated variant, such as a " + "malformed EIP-7702 authorization list or an unknown validation failure. Inspect the " + "raw transaction for unsupported fields and check the node logs." + ), + "WithdrawFailed": ( + "Withdrawing the transaction fee from the sender's mapped account failed even though " + "the balance check passed, e.g. due to locks, holds, or existential deposit " + "constraints. Check the account's locks and its free versus withdrawable balance." + ), + # ── Ethereum ──────────────────────────────────────────────────────────── + "InvalidSignature": ( + "Signature verification failed: the sender of an Ethereum or EVM transaction could not " + "be recovered from its signature, or a limit order's Sr25519 signature does not match " + "the order payload and signer. Check the signing key, chain id, and the exact payload " + "bytes that were signed." + ), + "PreLogExists": ( + "An `ethereum.transact` extrinsic was submitted in a block that already carries a " + "pre-log digest, meaning an Ethereum transaction is being injected by other means. " + "Check the block's digest for a pre-runtime Ethereum log; transact is not allowed " + "alongside it." + ), + # ── Grandpa ───────────────────────────────────────────────────────────── + "ChangePending": ( + "A GRANDPA authority-set change has already been signalled and is still pending, so a " + "new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage " + "and wait for the pending change to be applied first." + ), + "DuplicateOffenceReport": ( + "The equivocation proof is valid but this offence has already been reported and " + "recorded. Check whether an equivocation report for the same offender, session, and " + "round was previously submitted before reporting again." + ), + "InvalidEquivocationProof": ( + "The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the " + "two votes may be identical, from different rounds or set ids, or badly signed. Verify " + "the proof contains two distinct votes by the same authority in the same round and " + "authority set." + ), + "InvalidKeyOwnershipProof": ( + "The key ownership proof does not establish that the offending GRANDPA key belonged to " + "the claimed validator at that session. Regenerate the proof via the " + "`generate_key_ownership_proof` runtime API for the exact set id and authority id in " + "the report." + ), + "PauseFailed": ( + "A GRANDPA pause was signalled while the authority set is not live, i.e. it is already " + "paused or a pause is already pending. Check the Grandpa `State` storage before " + "signalling a pause." + ), + "ResumeFailed": ( + "A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live " + "or already pending a resume. Check the Grandpa `State` storage before signalling a " + "resume." + ), + "TooSoon": ( + "A forced GRANDPA authority change was signalled too soon after the previous one. Check " + "the Grandpa `NextForced` storage and wait until the current block passes it before " + "signalling another forced change." + ), + # ── LimitOrders ───────────────────────────────────────────────────────── + "ArithmeticOverflow": ( + "Converting a TAO amount to alpha during batched order execution overflowed the " + "fixed-point range, typically when the pool price is tiny relative to the batch's total " + "buy TAO. Check the subnet's current alpha price against the batch's aggregate buy " + "amounts." + ), + "ChainIdMismatch": ( + "The order payload's `chain_id` field differs from this chain's configured EVM chain " + "id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's " + "`chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed." + ), + "DuplicateOrderInBatch": ( + "Two entries in one `execute_batched_orders` call hash to the same order id, meaning " + "the identical signed payload was included twice, which hard-fails the batch. " + "Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`." + ), + "IncorrectPartialFillAmount": ( + "The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or " + "a full execution was submitted against an order already partially filled. Compare " + "`partial_fill` with `order.amount` minus the filled amount recorded in `Orders`." + ), + "LimitOrdersDisabled": ( + "Order execution was attempted while the pallet's global switch is off. Check the " + "`LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to " + "enable the pallet." + ), + "OrderAlreadyProcessed": ( + "The order id already has a terminal status: execution found it fulfilled, or " + "`cancel_order` found any existing status for it. Check the `Orders` storage map under " + "the blake2-256 hash of the SCALE-encoded `VersionedOrder`." + ), + "OrderCancelled": ( + "The order was previously cancelled via `cancel_order` and can never be executed. Check " + "the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the " + "signer must sign and submit a fresh order." + ), + "OrderExpired": ( + "The current chain time is past the order's `expiry` field, which is a unix timestamp " + "in milliseconds, so the order can no longer execute. Compare the `expiry` in the " + "signed order payload with the chain's current `Timestamp` value." + ), + "OrderNetUidMismatch": ( + "An order inside an `execute_batched_orders` call has a `netuid` field different from " + "the batch's `netuid` parameter, which hard-fails the entire batch. Check each order " + "payload's `netuid` against the batch argument and split mismatched orders out." + ), + "PalletHotkeyNotRegistered": ( + "Root tried to enable the pallet via `set_pallet_status` before its hotkey was " + "registered to the pallet's intermediary account. Check that the `PalletHotkey` " + "constant is registered for the pallet account, which genesis or the " + "`on_runtime_upgrade` migration performs." + ), + "PartialFillsNotEnabled": ( + "A `partial_fill` amount was supplied for an order whose signed payload has " + "`partial_fills_enabled` set to false. Check that field in the order payload; partial " + "execution requires the signer to have opted in when signing." + ), + "PriceConditionNotMet": ( + "The subnet's current alpha price does not satisfy the order's trigger: buys and " + "stop-losses require price at or below `limit_price`, take-profits at or above it. " + "Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the " + "`limit_price` field." + ), + "RelayerMissMatch": ( + "The order's `relayer` allowlist is set but the account that submitted the execution " + "transaction is not in it. Compare the extrinsic's signing account against the " + "`relayer` list in the signed order payload." + ), + "RelayerRequiredForPartialFill": ( + "A `partial_fill` was requested for an order whose `relayer` field is empty; partial " + "fills are only permitted on orders that restrict who may execute them. Check the order " + "payload and either set a relayer list or execute the full amount." + ), + "RootNetUidNotAllowed": ( + "The order or batch targets the root subnet, netuid 0, which the limit orders pallet " + "does not serve. Check the `netuid` field of the order payload or the `netuid` " + "parameter of the batch call and target a non-root subnet." + ), + "SwapReturnedZero": ( + "The netted pool swap in `execute_batched_orders` produced zero output for a non-zero " + "input, meaning the pool lacks liquidity or the derived price limit clamped the swap " + "entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived " + "price limit." + ), + "ZeroShareInBatch": ( + "An order's pro-rata share of the batch output floored to zero, so the whole batch was " + "rejected rather than consuming that order's input for no payout. Check the order's " + "`amount` relative to the batch totals and retry it in a differently composed batch." + ), + # ── MevShield ─────────────────────────────────────────────────────────── + "BadEncKeyLen": ( + "The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation " + "key length (1184 bytes). Check the byte length of the `enc_key` argument before " + "announcing." + ), + "TooManyPendingExtrinsics": ( + "`store_encrypted` was rejected because the shield pallet's queue of encrypted " + "extrinsics is already at capacity. Compare the `PendingExtrinsics` count against " + "`MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire." + ), + "Unreachable": ( + "`announce_next_key` could not identify the current block author via the `FindAuthors` " + "lookup, which should be impossible in a normally authored block. Check the block's " + "author digest and the shield pallet's authorship wiring." + ), + "WeightExceedsAbsoluteMax": ( + "`set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the " + "shield pallet's hard cap of half the total block weight. Compare the `value` argument " + "against the `MAX_ON_INITIALIZE_WEIGHT` constant." + ), + # ── Multisig ──────────────────────────────────────────────────────────── + "AlreadyApproved": ( + "The sender has already approved this multisig call, so a repeat approval is redundant. " + "Check the `Multisigs` entry for the call hash: the sender's account already appears in " + "its `approvals` list." + ), + "AlreadyStored": ( + "The call data supplied for storage is already stored on-chain for this multisig " + "operation. Check whether the call bytes were previously stored for this call hash " + "before submitting them again." + ), + "MaxWeightTooLow": ( + "The `max_weight` argument supplied with the final multisig approval is lower than the " + "actual weight of the call being dispatched. Compute the call's real dispatch weight " + "and pass a `max_weight` at least that large to `as_multi`." + ), + "MinimumThreshold": ( + "The multisig `threshold` argument was below 2, which these calls do not accept. Pass a " + "threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case." + ), + "NoApprovalsNeeded": ( + "The multisig call does not need any more approvals; it is only waiting for final " + "execution with the full call data. Instead of another `approve_as_multi`, submit " + "`as_multi` with the complete call to dispatch it." + ), + "NoTimepoint": ( + "No timepoint was supplied but this multisig operation is already underway, so the " + "approval cannot be matched to it. Read the operation's `when` field from the " + "`Multisigs` entry for the call hash and pass that height and index as " + "`maybe_timepoint`." + ), + "NotFound": ( + "The referenced item does not exist in storage: no multisig operation for that call " + "hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or " + "no matching proxy registration in `Proxies`. Verify the identifier against current " + "chain state." + ), + "NotOwner": ( + "Only the account that opened the multisig operation (its depositor) may cancel it or " + "adjust its deposit. Compare the sender against the `depositor` field stored in the " + "`Multisigs` entry for this call hash." + ), + "SenderInSignatories": ( + "The multisig sender was included in the `other_signatories` list, but that list must " + "contain only the remaining signatories. Remove the sender's own account from " + "`other_signatories` before resubmitting." + ), + "SignatoriesOutOfOrder": ( + "The `other_signatories` list is not sorted in strictly ascending account order, which " + "the multisig pallet requires for a canonical account derivation. Sort the list and " + "remove duplicates before resubmitting." + ), + "TooFewSignatories": ( + "The multisig signatory list is too short: `other_signatories` must contain at least " + "one account besides the sender. Check the length of `other_signatories` against the " + "threshold you are using." + ), + "TooManySignatories": ( + "The multisig signatory list exceeds the maximum allowed. Compare the length of " + "`other_signatories` plus the sender against the pallet's `MaxSignatories` constant." + ), + "UnexpectedTimepoint": ( + "A timepoint was supplied but no multisig operation is underway for this call hash; the " + "first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` " + "on the opening call, or verify the call hash matches an existing `Multisigs` entry." + ), + "WrongTimepoint": ( + "The timepoint supplied does not match the one recorded when this multisig operation " + "was opened. Read the correct `when` height and index from the `Multisigs` entry for " + "the call hash and resubmit with that exact timepoint." + ), + # ── Preimage ──────────────────────────────────────────────────────────── + "AlreadyNoted": ( + "The preimage for this hash has already been noted on-chain, so `note_preimage` has " + "nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before " + "submitting the bytes again." + ), + "NotAuthorized": ( + "The caller is not permitted to manage this preimage; unnoting or unrequesting requires " + "the pallet's manager origin or the account that originally deposited it. Check which " + "origin noted or requested the preimage and use that origin or the configured " + "`ManagerOrigin`." + ), + "NotNoted": ( + "The preimage cannot be unnoted because no preimage was ever noted for this hash. Check " + "`RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, " + "is stored." + ), + "NotRequested": ( + "The preimage request cannot be removed because there are no outstanding requests for " + "this hash. Check the request status for the hash in `RequestStatusFor` before calling " + "`unrequest_preimage`." + ), + "Requested": ( + "The preimage cannot be unnoted while there are still outstanding requests for it. " + "Check the request count in the hash's request status; all requests must be cleared " + "before the preimage can be removed." + ), + "TooBig": ( + "The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check " + "the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting " + "it." + ), + "TooFew": ( + "The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. " + "Pass at least one hash to `ensure_updated`." + ), + "TooMany": ( + "A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were " + "passed to `ensure_updated`, or the account has hit its proxy or announcement cap. " + "Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and " + "`MaxPending`." + ), + # ── Proxy ─────────────────────────────────────────────────────────────── + "AnnouncementDepositInvariantViolated": ( + "Internal invariant failure in `announce`: recomputing the announcement deposit " + "returned nothing after the pending announcements were updated. Inspect the caller's " + "`Announcements` entry and the announcement deposit constants; this indicates a pallet " + "bug rather than bad input." + ), + "Duplicate": ( + "This delegate is already registered as a proxy for the delegator with the same proxy " + "type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with " + "the same (delegate, proxy type, delay) tuple." + ), + "InvalidDerivedAccountId": ( + "Deriving the pure proxy account id from the provided entropy failed to decode into a " + "valid account. Check the spawner, `proxy_type`, and `index` arguments used with " + "`create_pure` (or the equivalent lookup when destroying one)." + ), + "NoPermission": ( + "The proxy pallet refused the action: the proxied call could escalate privileges, or " + "the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). " + "Check the proxy type's call filter and the original `create_pure` arguments." + ), + "NoSelfProxy": ( + "An account attempted to register itself as its own proxy, which is not allowed. Check " + "the `delegate` argument to `add_proxy` and ensure it differs from the calling " + "(delegator) account." + ), + "NotProxy": ( + "The sender is not registered as a proxy for the account it tried to act for. Check the " + "`Proxies` entry of the `real` account and confirm the sender appears there with a " + "proxy type and delay compatible with the call." + ), + "Unannounced": ( + "The proxied call was executed before its announcement matured, or no matching " + "announcement exists at all. Check the proxy's `Announcements` entry for the call hash " + "and the `delay` on the proxy registration; enough blocks must elapse between " + "`announce` and `proxy_announced`." + ), + "Unproxyable": ( + "The attempted call is not permitted by the registered proxy type's call filter. Check " + "which `proxy_type` the sender holds in the real account's `Proxies` entry and whether " + "that type's `InstanceFilter` allows this specific call." + ), + # ── SafeMode ──────────────────────────────────────────────────────────── + "AlreadyDeposited": ( + "The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on " + "hold, so another cannot be placed. Check the account's `Deposits` entries and its " + "balance held under the `EnterOrExtend` hold reason." + ), + "CannotReleaseYet": ( + "`release_deposit` was called too early: the current block must exceed the deposit's " + "block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the " + "entry in `Deposits` against the `ReleaseDelay` config." + ), + "CurrencyError": ( + "A balance hold, release, or burn inside pallet-safe-mode failed while managing an " + "enter/extend deposit. Check the account's free balance and existing holds under the " + "safe-mode `EnterOrExtend` hold reason." + ), + "Entered": ( + "Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again " + "and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at " + "which safe-mode disengages." + ), + "Exited": ( + "Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have " + "nothing to act on. Check that `EnteredUntil` contains a value before extending or " + "exiting." + ), + "NoDeposit": ( + "No safe-mode deposit exists for the given account and block combination, so nothing " + "can be released or slashed. Check the `Deposits` storage map for an entry under that " + "account and deposit block." + ), + "NotConfigured": ( + "The permissionless safe-mode operation is disabled because its config option is " + "`None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or " + "`ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only " + "force variants." + ), + # ── Scheduler ─────────────────────────────────────────────────────────── + "FailedToSchedule": ( + "The scheduler could not place the call into the agenda, typically because the target " + "block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the " + "target block against `MaxScheduledPerBlock` and pick a different block if it is " + "saturated." + ), + "Named": ( + "An unnamed scheduler function was used on a task that was scheduled with a name. Use " + "the named variants (`cancel_named`, `schedule_named`) with the task's id, which you " + "can find via the `Lookup` storage map." + ), + "RescheduleNoChange": ( + "The reschedule was rejected because the new dispatch time equals the task's currently " + "scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely " + "different `when` block." + ), + "TargetBlockNumberInPast": ( + "The scheduler was given a dispatch block that is not in the future. Compare the `when` " + "argument against the current block number and choose a strictly later block." + ), + # ── SubtensorModule ───────────────────────────────────────────────────── + "AccountRejectsLockedAlpha": ( + "Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the " + "accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. " + "Check the destination coldkey's `AccountFlags` storage and have the recipient opt in " + "to receiving locked alpha before retrying." + ), + "ActiveLockExists": ( + "The destination coldkey already holds a lock with nonzero locked mass on that subnet, " + "so a new or transferred lock cannot be created there. Inspect the `Lock` storage for " + "the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or " + "remove it first." + ), + "ActivityCutoffFactorMilliOutOfBounds": ( + "The `factor_milli` argument to set the activity-cutoff factor was outside the allowed " + "1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those " + "bounds before resubmitting." + ), + "ActivityCutoffTooLow": ( + "An admin tried to set the subnet's activity cutoff below the chain-wide minimum. " + "Compare the requested value against the `MinActivityCutoff` storage item and current " + "`activity_cutoff` in `btcli sudo get --netuid `." + ), + "AddStakeBurnRateLimitExceeded": ( + "The add-stake-and-burn operation was submitted again before its per-key rate-limit " + "window elapsed. Wait some blocks and retry; no active raise site exists in current " + "code, so this mainly appears on older runtimes." + ), + "AdminActionProhibitedDuringWeightsWindow": ( + "An owner or admin hyperparameter change was attempted inside the protected freeze " + "window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks " + "remaining until the next epoch (subnet tempo), then retry after the epoch fires." + ), + "AllNetworksInImmunity": ( + "Creating a new subnet required pruning an existing one, but every candidate subnet is " + "still inside its network immunity period so none can be dissolved. Check " + "`NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a " + "subnet leaves immunity." + ), + "AlphaHighTooLow": ( + "The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly " + "0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` " + "call; current values are in the `AlphaValues` storage per netuid." + ), + "AlphaLowOutOfRange": ( + "The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum " + "(1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not " + "exceeding alpha_high; current settings are in the `AlphaValues` storage for the " + "netuid." + ), + "AmountTooLow": ( + "A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the " + "minimum stake threshold after fees and slippage. Compare the amount against the " + "`DefaultMinStake` storage item and the subnet's alpha price before retrying with a " + "larger amount." + ), + "AnnouncedColdkeyHashDoesNotMatch": ( + "The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash " + "committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the " + "`ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are " + "swapping to." + ), + "AutoEpochAlreadyImminent": ( + "`trigger_epoch` was called when the next automatic epoch is closer than the " + "`AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's " + "tempo and blocks until the next epoch, and simply wait for it to fire." + ), + "BalanceWithdrawalError": ( + "The requested TAO could not be withdrawn from the coldkey's free balance, typically " + "due to insufficient funds, the existential deposit, or frozen/reserved balance. Check " + "the coldkey's balance with `btcli wallet balance` and reduce the amount or top up." + ), + "BeneficiaryDoesNotOwnHotkey": ( + "When ending a subnet lease, the hotkey passed for the ownership handover is not owned " + "by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass " + "a hotkey the beneficiary coldkey actually owns." + ), + "CallDisabled": ( + "The extrinsic has been switched off in the current runtime and cannot be dispatched. " + "There is no active raise site in current code; if seen, check release notes for " + "whether the call was re-enabled in a newer runtime version." + ), + "CanNotSetRootNetworkWeights": ( + "`set_weights` was called with netuid 0, the root network, where normal weight setting " + "is not allowed. Use a non-root `netuid` argument; root weights are handled by a " + "separate mechanism." + ), + "CannotAffordLockCost": ( + "The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. " + "Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey " + "balance from `btcli wallet balance` before registering a subnet." + ), + "CannotBurnOrRecycleOnRootSubnet": ( + "`recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet " + "cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose " + "alpha you want to recycle or burn." + ), + "CannotUseSystemAccount": ( + "The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment " + "is a reserved subnet system account. Use a regular user-generated hotkey instead; " + "system accounts are derived per-subnet and rejected by `is_subnet_account_id`." + ), + "ChildParentInconsistency": ( + "A `set_children` or parent-delegation call would make the same hotkey appear as both a " + "child and a parent, or referenced a child missing from the proposed mapping. Inspect " + "the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the " + "overlap." + ), + "ColdKeyAlreadyAssociated": ( + "The destination coldkey of a coldkey swap already has staking hotkeys associated with " + "it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for " + "the new coldkey and swap to a fresh, unused coldkey instead." + ), + "ColdkeySwapAlreadyDisputed": ( + "`dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is " + "already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no " + "further dispute action is needed." + ), + "ColdkeySwapAnnounced": ( + "The coldkey has a pending swap announcement, so all but a small allow-list of " + "extrinsics are blocked until the swap completes or is cleared. Check the " + "`ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with " + "`coldkey_swap` or clear the announcement." + ), + "ColdkeySwapAnnouncementNotFound": ( + "`coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was " + "called for a coldkey with no pending announcement. Check the " + "`ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first." + ), + "ColdkeySwapClearTooEarly": ( + "The swap announcement cannot be cleared until the reannouncement delay after the " + "announcement's execution block has passed. Compare the current block with the `when` " + "stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry " + "later." + ), + "ColdkeySwapDisputed": ( + "All extrinsics from this coldkey are blocked because its pending coldkey swap is under " + "dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be " + "resolved by root before the account can transact." + ), + "ColdkeySwapReannouncedTooEarly": ( + "`announce_coldkey_swap` was called again before the reannouncement delay after the " + "previous announcement's execution block elapsed. Compare the current block with the " + "stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later." + ), + "ColdkeySwapTooEarly": ( + "`coldkey_swap` was executed before the announcement delay had elapsed since " + "`announce_coldkey_swap`. Check the execution block stored in " + "`ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and " + "wait until then." + ), + "CommitRevealDisabled": ( + "A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. " + "Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo " + "get`); use plain `set_weights` instead when it is disabled." + ), + "CommitRevealEnabled": ( + "Plain `set_weights` was called on a subnet where commit-reveal is enabled, which " + "requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` " + "hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`." + ), + "CommittingWeightsTooFast": ( + "The neuron committed weights again before the per-UID rate limit elapsed since its " + "last commit on that subnet. Compare blocks since the last commit against the " + "`weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait." + ), + "DelegateTakeTooHigh": ( + "The `take` argument exceeds the maximum delegate take allowed by the chain (18% by " + "default). Compare the requested value against the `MaxDelegateTake` storage item and " + "lower it." + ), + "DelegateTakeTooLow": ( + "The `take` argument was below the `MinDelegateTake` minimum, or " + "`increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the " + "current take. Check the hotkey's current take in the `Delegates` storage and the " + "`MinDelegateTake` storage item." + ), + "DelegateTxRateLimitExceeded": ( + "The delegate changed its take again before the per-hotkey take-change rate limit " + "elapsed. Compare blocks since the hotkey's last take transaction against the " + "`TxDelegateTakeRateLimit` storage item and retry later." + ), + "Deprecated": ( + "The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the " + "swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the " + "replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` " + "plus `coldkey_swap`)." + ), + "DisabledTemporarily": ( + "The operation has been temporarily switched off in the runtime, usually as a hotfix " + "measure. There is no active raise site in current code; if encountered, check the " + "runtime version and release notes for when the feature is re-enabled." + ), + "DuplicateChild": ( + "The children list passed to `set_children` contains the same child hotkey more than " + "once. Deduplicate the `children` argument; current relations are visible in the " + "`ChildKeys` storage for the parent hotkey and netuid." + ), + "DuplicateUids": ( + "The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more " + "than once. Deduplicate the uids/values pairs before submitting; each target neuron may " + "appear only once per weight vector." + ), + "DynamicTempoBlockedByCommitReveal": ( + "`trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an " + "out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop " + "committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable " + "it before manually triggering epochs." + ), + "EpochTriggerAlreadyPending": ( + "`trigger_epoch` was called while a previously triggered epoch is still queued for this " + "subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending " + "epoch to fire before triggering again." + ), + "EvmKeyAssociateRateLimitExceeded": ( + "`associate_evm_key` was called again before the per-UID rate limit since the last " + "association elapsed. Compare blocks since the association recorded in the " + "`AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant " + "and retry later." + ), + "EvmKeyAssociationLimitExceeded": ( + "The EVM address is already associated with the maximum number of UIDs allowed on this " + "subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) " + "pair and free a slot or use a different EVM address." + ), + "ExpectedBeneficiaryOrigin": ( + "A lease operation such as terminating a subnet lease was signed by an account other " + "than the lease's beneficiary coldkey. Check the beneficiary recorded in the " + "`SubnetLeases` storage for the lease id and sign with that coldkey." + ), + "ExpiredWeightCommit": ( + "The hash supplied to `reveal_weights` matches a commit whose reveal window has already " + "passed, so it can no longer be revealed. Check the `commit_reveal_period` " + "hyperparameter and reveal within the allowed epochs after committing; re-commit and " + "reveal on time." + ), + "FaucetDisabled": ( + "The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, " + "i.e. any real network. The faucet only works on local test chains compiled with that " + "feature; use a funded wallet or testnet TAO instead." + ), + "FirstEmissionBlockNumberAlreadySet": ( + "`start_call` was issued for a subnet whose emissions have already been started. Check " + "the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the " + "subnet is already emitting and no action is needed." + ), + "HotKeyAccountNotExists": ( + "The hotkey has no on-chain account, meaning it was never created through registration, " + "so staking or delegation operations cannot reference it. Check the `Owner` storage for " + "the hotkey or `btcli wallet overview`; register the hotkey on a subnet first." + ), + "HotKeyAlreadyDelegate": ( + "`become_delegate` was called for a hotkey that is already a delegate. Check the " + "`Delegates` storage for the hotkey; if it has a take entry it is already delegating " + "and no action is needed." + ), + "HotKeyAlreadyRegisteredInSubNet": ( + "A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet " + "(or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the " + "(netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid." + ), + "HotKeyNotRegisteredInNetwork": ( + "The hotkey is not registered on the relevant subnet, raised by " + "`serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring " + "registration on any subnet. Verify registration with `btcli subnets show --netuid ` " + "and register via `btcli subnets register` first." + ), + "HotKeyNotRegisteredInSubNet": ( + "The hotkey holds no UID on the given netuid, so weight setting, commits, or UID " + "lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli " + "subnets show --netuid `; confirm the netuid argument and register the hotkey if " + "needed." + ), + "HotKeySetTxRateLimitExceeded": ( + "The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since " + "its last such transaction. Check the coldkey's last transaction block against the " + "`TxRateLimit` storage value and wait the remaining blocks." + ), + "HotKeySwapOnSubnetIntervalNotPassed": ( + "A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks " + "passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` " + "for the coldkey with the current block and retry after the interval." + ), + "IncorrectCommitRevealVersion": ( + "The `commit_reveal_version` argument does not match the chain's current commit-reveal " + "weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or " + "configure the client to commit with that version." + ), + "IncorrectWeightVersionKey": ( + "The `version_key` supplied with set_weights is older than the subnet's required " + "weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli " + "subnets hyperparameters`) and update the validator software or the key." + ), + "InputLengthsUnequal": ( + "A batch weights call passed vectors of different lengths, e.g. netuids vs commit " + "hashes, or uids vs values, salts and version_keys in batch reveal. Check that every " + "parallel vector argument in the batch extrinsic has the same length." + ), + "InsufficientLiquidity": ( + "The pool cannot absorb the operation: the swap simulation failed, reserves are smaller " + "than the payout, or the amount exceeds the pool's supported input. Check the subnet " + "pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount." + ), + "InsufficientStakeForLock": ( + "The requested lock amount exceeds the coldkey's total alpha stake on that subnet " + "(existing locked mass included). Compare the amount against the coldkey's stake on the " + "netuid, e.g. via `btcli stake list`, and lock less or add stake first." + ), + "InvalidChild": ( + "The children or parents list includes the pivot hotkey itself (a self-loop), including " + "during a hotkey swap when the new hotkey is already a child or parent of the old one. " + "Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved." + ), + "InvalidChildkeyTake": ( + "The childkey take is outside the allowed range for the subnet: below the effective " + "minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and " + "pick a `take` value within those bounds." + ), + "InvalidDifficulty": ( + "The submitted proof-of-work hash does not meet the required difficulty (the faucet " + "uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the " + "`Difficulty` storage for the netuid and regenerate work against the current block." + ), + "InvalidIdentity": ( + "The submitted coldkey or subnet identity failed validation, typically a field " + "exceeding its allowed byte length or malformed data. Check each identity field's " + "length against the limits enforced by the chain before calling set_identity or " + "set_subnet_identity." + ), + "InvalidIpAddress": ( + "The `ip` argument to serve_axon or serve_prometheus is not a valid address for the " + "declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP " + "encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed." + ), + "InvalidIpType": ( + "The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the " + "value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted." + ), + "InvalidLeaseBeneficiary": ( + "The account registering a leased network is not the creator of the crowdloan currently " + "being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage " + "and submit the call from that coldkey." + ), + "InvalidNumRootClaim": ( + "The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number " + "of root claims. Check the `new_value` argument against the chain's " + "`MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number." + ), + "InvalidPort": ( + "The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check " + "the miner or client axon configuration and serve on a non-zero port." + ), + "InvalidRecoveredPublicKey": ( + "The EVM key association signature recovered to a public key whose keccak hash does not " + "equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key " + "over the hotkey plus block hash message (EIP-191 format)." + ), + "InvalidRevealCommitHashNotMatch": ( + "The revealed uids, values, salt and version_key hash to a value that matches none of " + "the hotkey's pending non-expired commits. Check that the reveal parameters and salt " + "exactly match what was committed, and inspect `WeightCommits` for the hotkey and " + "netuid." + ), + "InvalidRevealRound": ( + "A timelocked weights commit specified a `reveal_round` older than the latest stored " + "DRAND round, so it could be decrypted immediately. Query the drand pallet's " + "`LastStoredRound` and commit with a future round number." + ), + "InvalidRootClaimThreshold": ( + "The value passed to set the root claim threshold exceeds the chain's maximum allowed " + "threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` " + "constant and the current `RootClaimableThreshold` for the netuid." + ), + "InvalidSeal": ( + "The seal hash recomputed from the supplied `block_number`, `nonce` and key does not " + "equal the submitted `work`. Verify the PoW solver built the seal for the same key and " + "block it submits, and that the work bytes were not corrupted in transit." + ), + "InvalidSubnetNumber": ( + "A root-claim call passed an empty subnet set or more subnets than the per-call maximum " + "(claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is " + "non-empty and within the `MAX_SUBNET_CLAIMS` limit." + ), + "InvalidValue": ( + "A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, " + "emission splits summing away from 65535, max UIDs or take bounds. Check the specific " + "argument against the min/max storage items the extrinsic validates (e.g. " + "`MinAllowedUids`, `MaxMechanismCount`)." + ), + "InvalidVotingPowerEmaAlpha": ( + "The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. " + "Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most " + "10^18, and the current value is in `VotingPowerEmaAlpha` per netuid." + ), + "InvalidWorkBlock": ( + "The `block_number` in the proof-of-work submission is in the future or more than 3 " + "blocks old, so the work is stale. Compare the submitted block number with the current " + "chain height and regenerate the PoW against a fresh block." + ), + "LeaseCannotEndInThePast": ( + "The `end_block` supplied when registering a leased network is not after the current " + "block. Check the current chain height and pass an `end_block` in the future, or omit " + "it for a perpetual lease." + ), + "LeaseDoesNotExist": ( + "The `lease_id` argument does not correspond to any stored lease. Query the " + "`SubnetLeases` storage map to confirm the lease id and whether it was already " + "terminated." + ), + "LeaseHasNoEndBlock": ( + "The lease being terminated is perpetual (its `end_block` is None), so it can never be " + "ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given " + "lease id." + ), + "LeaseHasNotEnded": ( + "The lease termination was attempted before the lease's `end_block` was reached. " + "Compare the current block height with the `end_block` stored in `SubnetLeases` for the " + "lease id and retry after it passes." + ), + "LeaseNetuidNotFound": ( + "After registering the leased network, no subnet owned by the lease's derived coldkey " + "could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the " + "lease coldkey; this usually indicates the registration did not complete." + ), + "LiquidAlphaDisabled": ( + "Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the " + "subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and " + "have the subnet owner enable liquid alpha first." + ), + "LockHotkeyMismatch": ( + "The coldkey already has a conviction lock on this subnet bound to a different hotkey, " + "and locks for one coldkey per subnet must target a single hotkey. Check the existing " + "lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first." + ), + "LockIdOverFlow": ( + "The global network-registration lock id counter reached its u32 maximum while queueing " + "a subnet registration, so no new lock could be created. Check the " + "`NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a " + "balance problem." + ), + "MaxWeightExceeded": ( + "After normalization, one of the submitted weights exceeds the subnet's maximum weight " + "limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli " + "subnets hyperparameters`) and flatten the weight vector before setting." + ), + "MechanismDoesNotExist": ( + "The target subnet or its sub-mechanism does not exist: the netuid is unknown, the " + "mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was " + "requested. Check the netuid with `btcli subnets list` and the mechanism count for that " + "subnet." + ), + "NeedWaitingMoreBlocksToStarCall": ( + "The subnet owner called start_call before enough blocks had passed since the subnet " + "was registered. Compare the current block with `NetworkRegisteredAt` for the netuid " + "plus the start-call delay and retry once the window opens." + ), + "NetworkDissolveAlreadyQueued": ( + "The subnet is already in the dissolve cleanup queue, so it cannot be queued for " + "dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid " + "before submitting another dissolve request." + ), + "NetworkTxRateLimitExceeded": ( + "The coldkey attempted register_network again before the network registration rate " + "limit elapsed since its previous registration. Check the coldkey's last " + "register-network block against the `NetworkRateLimit` storage value and wait the " + "remaining blocks." + ), + "NeuronNoValidatorPermit": ( + "The hotkey tried to set weights on other neurons without holding a validator permit on " + "that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or " + "`btcli subnets metagraph`) and whether its stake ranks it as a validator." + ), + "NewColdKeyIsHotkey": ( + "The proposed new coldkey in a coldkey swap is already an existing hotkey account, " + "which is not allowed. Check the `Owner` storage for the candidate key to confirm it is " + "not registered as a hotkey, and pick a fresh coldkey." + ), + "NewHotKeyIsSameWithOld": ( + "swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is " + "nothing to swap. Check the extrinsic arguments and supply a different destination " + "hotkey." + ), + "NewHotKeyNotCleanForRootSwap": ( + "The destination hotkey has pending root claimable dividends, non-zero root stake, or " + "root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` " + "and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey." + ), + "NoExistingLock": ( + "move_lock was called but no conviction lock exists for the signing coldkey on that " + "subnet. Check the lock storage for the coldkey and netuid, and create a lock before " + "attempting to move it to another hotkey." + ), + "NoNeuronIdAvailable": ( + "Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet " + "is full and every neuron is immune from pruning. Check `SubnetworkN` versus " + "`MaxAllowedUids` for the netuid and retry after immunity periods expire." + ), + "NoWeightsCommitFound": ( + "A weights reveal was submitted but no pending (non-expired) commit exists for the " + "hotkey and netuid, possibly because it already expired. Query the `WeightCommits` " + "storage map for the hotkey and check the commit hasn't passed the reveal window." + ), + "NonAssociatedColdKey": ( + "The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, " + "serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. " + "via `btcli wallet overview`, and sign with the coldkey that registered it." + ), + "NotEnoughAlphaOutToRecycle": ( + "A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. " + "Compare the amount against the `SubnetAlphaOut` storage value for the netuid and " + "reduce the recycle amount." + ), + "NotEnoughBalanceToPaySwapColdKey": ( + "The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled " + "when the swap executes. Check the balance with `btcli wallet balance` against the swap " + "cost and top up before scheduling the swap." + ), + "NotEnoughBalanceToPaySwapHotKey": ( + "The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost " + "applies when swapping on a single netuid). Check `btcli wallet balance` against the " + "key swap cost and fund the coldkey before retrying." + ), + "NotEnoughBalanceToStake": ( + "The coldkey's free balance is less than the TAO required, either the stake amount in " + "add_stake or the burn cost of a registration. Check `btcli wallet balance` against the " + "amount or the current registration burn (`Burn` storage for the netuid)." + ), + "NotEnoughStake": ( + "The caller's hotkey holds less stake than the action requires; a generic " + "insufficient-stake failure on staking-related calls. Check the hotkey's stake on the " + "relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs." + ), + "NotEnoughStakeToSetChildkeys": ( + "Raised by `set_children` when the parent hotkey's total stake is below " + "`StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total " + "stake (`btcli stake list`) against the `StakeThreshold` storage value." + ), + "NotEnoughStakeToSetWeights": ( + "Setting or committing weights failed because the hotkey's stake weight on the subnet " + "is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is " + "exempt. Check the hotkey's stake on that netuid against `StakeThreshold`." + ), + "NotEnoughStakeToWithdraw": ( + "An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey " + "pair holds on that subnet. Compare the requested amount against the pair's current " + "stake on the netuid (`btcli stake list` or the `Alpha` storage)." + ), + "NotRootSubnet": ( + "A call that only operates on the root network, such as setting root network weights, " + "was given a non-root netuid. Check the netuid argument; root operations must target " + "netuid 0." + ), + "NotSubnetOwner": ( + "The signing coldkey is not the recorded owner of the subnet it tried to administer " + "(e.g. setting subnet identity or owner-only hyperparameters). Compare the caller " + "against `SubnetOwner` for that netuid (`btcli subnets show`)." + ), + "Overflow": ( + "A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when " + "registering a leased network, or adding to a crowdloan's `raised` amount or " + "contributor count. Internal guard; inspect the amounts involved as this should not " + "occur with realistic values." + ), + "ProportionOverflow": ( + "The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the " + "per-child proportion values so their total fits in a u64; each proportion is a " + "fraction of u64::MAX." + ), + "RegistrationNotPermittedOnRootSubnet": ( + "A neuron registration or child-hotkey operation (`register`, `burned_register`, " + "`set_children`) was called with the root netuid, where these calls are invalid. Check " + "the netuid argument; use a regular subnet, or `root_register` for root membership." + ), + "RegistrationPriceLimitExceeded": ( + "`burned_register` with a price limit failed because the subnet's current registration " + "burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` " + "storage or `btcli subnets list` and raise the limit or wait for the cost to decay." + ), + "RevealPeriodTooLarge": ( + "`set_reveal_period` was given a commit-reveal period above the compiled-in maximum " + "number of epochs. Lower the `reveal_period` argument; the current setting is readable " + "from `RevealPeriodEpochs` for the netuid." + ), + "RevealPeriodTooSmall": ( + "`set_reveal_period` was given a commit-reveal period below the compiled-in minimum " + "number of epochs. Raise the `reveal_period` argument; the current setting is readable " + "from `RevealPeriodEpochs` for the netuid." + ), + "RevealTooEarly": ( + "A weight reveal was submitted before the commit's reveal window: the current epoch " + "must equal the commit epoch plus the reveal period. Check the commit in " + "`WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch." + ), + "RootNetworkDoesNotExist": ( + "Root registration or root stake claiming found no root network in chain state, which " + "only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists " + "in `NetworksAdded`." + ), + "SameAutoStakeHotkeyAlreadySet": ( + "The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is " + "already configured. Read `AutoStakeDestination` for the coldkey and netuid before " + "calling; only a different hotkey is accepted." + ), + "SameNetuid": ( + "A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so " + "`origin_netuid` equals `destination_netuid` with nothing to transition. Check the call " + "arguments; at least the subnet or one of the keys must differ." + ), + "ServingRateLimitExceeded": ( + "`serve_axon` or `serve_prometheus` was called again before enough blocks passed since " + "the neuron's last serving update. Check the axon's last update block in `Axons` " + "against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait." + ), + "SettingWeightsTooFast": ( + "The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its " + "last weight update on that subnet. Check the weights_rate_limit hyperparameter and the " + "neuron's `LastUpdate` entry, then wait the remaining blocks." + ), + "SlippageTooHigh": ( + "A stake, unstake, or move with a price limit would execute at a worse rate than the " + "limit allows and `allow_partial` was false. Compare the `limit_price` argument with " + "the subnet's current alpha price (`btcli subnets price`) or permit partial execution." + ), + "StakeTooLowForRoot": ( + "`root_register` when the root network is full and the hotkey's stake on netuid 0 does " + "not exceed the lowest-staked current root member. Compare your hotkey's root stake " + "against existing root validators (`btcli root list`)." + ), + "StakeUnavailable": ( + "An unstake would dip into stake that is still locked: the requested alpha exceeds the " + "coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and " + "netuid; only total stake minus the decaying locked mass can be unstaked." + ), + "StakingRateLimitExceeded": ( + "Staking operations (add_stake, remove_stake, and similar) were submitted faster than " + "the per-block staking rate limit allows for the hotkey-coldkey pair. Space the " + "transactions out and retry in a later block." + ), + "StartCallNotReady": ( + "`start_call` was made before `StartCallDelay` blocks elapsed since the subnet was " + "registered. Compare the current block against `NetworkRegisteredAt` for the netuid " + "plus `StartCallDelay`, and wait for the remainder." + ), + "SubNetRegistrationDisabled": ( + "Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` " + "flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` " + "is in the future). Check the network_registration_allowed hyperparameter for the " + "netuid." + ), + "SubnetBuybackRateLimitExceeded": ( + "A subnet buyback operation (staking TAO and immediately burning the acquired alpha, " + "e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the " + "window to pass before retrying the buyback." + ), + "SubnetLimitReached": ( + "`register_network` failed because the subnet count is at the network limit and no " + "existing subnet is eligible to be pruned. Check the number of registered subnets " + "(`btcli subnets list`) against the subnet limit and retry once a subnet becomes " + "prunable." + ), + "SubnetNotExists": ( + "The netuid passed to the call does not correspond to a registered subnet. Verify the " + "netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also " + "have been dissolved." + ), + "SubtokenDisabled": ( + "The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it " + "are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after " + "registration. Check `SubtokenEnabled` for the netuid involved." + ), + "SymbolAlreadyInUse": ( + "The token symbol requested for the subnet is already assigned to another subnet. Scan " + "`TokenSymbol` across netuids and pick a symbol that is not taken." + ), + "SymbolDoesNotExist": ( + "The requested token symbol is not in the chain's predefined symbol table, so it cannot " + "be assigned to a subnet. Check the symbol argument against the chain's built-in " + "`SYMBOLS` list and choose a valid entry." + ), + "TempoOutOfBounds": ( + "`set_tempo` was given a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range. Check " + "the tempo argument against those chain constants and pick a value inside the bounds." + ), + "TooManyChildren": ( + "`set_children` was called with more than 5 child hotkeys for a parent on the subnet. " + "Trim the children list to at most 5 entries." + ), + "TooManyRegistrationsThisBlock": ( + "Registrations in the current block already reached the subnet's per-block cap " + "(`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration " + "enforces the same cap on netuid 0. Retry in the next block." + ), + "TooManyRegistrationsThisInterval": ( + "Registrations in the current interval reached the cap of three times " + "`TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` " + "against that hyperparameter and wait for the next interval to start." + ), + "TooManyUIDsPerMechanism": ( + "Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed " + "the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's " + "mechanism count so their product stays within the limit." + ), + "TooManyUnrevealedCommits": ( + "`commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 " + "unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and " + "reveal or let old commits expire before committing again." + ), + "TransactorAccountShouldBeHotKey": ( + "The extrinsic must be signed by the hotkey itself, but a different account (typically " + "the coldkey) was the origin. Check which key signs the transaction; calls like axon " + "serving expect the hotkey as origin." + ), + "TransferDisallowed": ( + "A stake transfer or cross-subnet move was attempted while the origin or destination " + "subnet has stake transfers switched off. Check the `TransferToggle` storage for both " + "netuids involved; the subnet owner must enable transfers first." + ), + "TrimmingWouldExceedMaxImmunePercentage": ( + "Trimming the subnet's UIDs cannot proceed because immune neurons would make up at " + "least the maximum immune share (80%) of the reduced slot count. Check neurons still in " + "`ImmunityPeriod` and retry after their immunity lapses or with a higher max UID " + "target." + ), + "TxChildkeyTakeRateLimitExceeded": ( + "`set_childkey_take` was called again for the hotkey on this subnet before its " + "rate-limit window elapsed. Check the block of the last childkey-take change against " + "`TxChildkeyTakeRateLimit` and wait out the remainder." + ), + "TxRateLimitExceeded": ( + "An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, " + "setting the owner hotkey) was repeated within its rate-limit window for that key and " + "subnet. Check when the same transaction type last succeeded and wait for the limit to " + "pass." + ), + "UidMapCouldNotBeCleared": ( + "During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries " + "(the storage clear returned a cursor). Internal state inconsistency rather than a " + "caller error; inspect the `Uids` storage for the netuid and report it." + ), + "UidVecContainInvalidOne": ( + "The weight submission includes a UID that is not registered on the subnet, i.e. at " + "least one entry is not below `SubnetworkN`. Check the `uids` argument against the " + "subnet's neuron count in the metagraph (`btcli subnets metagraph`)." + ), + "UidsLengthExceedUidsInSubNet": ( + "The weight submission contains more UID entries than there are neurons registered on " + "the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the " + "netuid and trim the vector." + ), + "UnableToRecoverPublicKey": ( + "While associating an EVM key, the secp256k1 public key recovered from the supplied " + "signature could not be parsed. Check that the signature was produced by signing the " + "expected EIP-191 message (hotkey plus block hash) with the EVM private key." + ), + "UnlockAmountTooHigh": ( + "An unlock requested more alpha than remains locked for the coldkey on that subnet. " + "Check the lock's remaining decaying locked mass in the `Lock` storage entry and " + "request at most that amount." + ), + "VotingPowerTrackingNotEnabled": ( + "Disabling voting power tracking was requested on a subnet where tracking is not " + "currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid " + "before calling the disable extrinsic." + ), + "WaitingForDissolvedSubnetCleanup": ( + "The operation is blocked while a dissolved subnet's storage is still being torn down " + "in the background. Check the `DissolveCleanupQueue` and retry after the on-idle " + "cleanup for that netuid completes." + ), + "WeightVecLengthIsLow": ( + "The weight submission has fewer entries than the subnet's minimum (setting only a " + "self-weight is the one exception). Compare the vector length against the " + "`MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid." + ), + "WeightVecNotEqualSize": ( + "The `uids` and `values` vectors passed to a weight-setting call have different " + "lengths, so they cannot be paired. Check the call arguments; both vectors must have " + "exactly one value per UID." + ), + "ZeroBalanceAfterWithdrawn": ( + "Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) " + "would leave the account at zero, below what keeps it alive. Check the coldkey's free " + "balance and leave at least the existential deposit after the amount withdrawn." + ), + # ── Sudo ──────────────────────────────────────────────────────────────── + "RequireSudo": ( + "The call requires the sudo key but was signed by a different account. Compare the " + "sender against the account stored in the Sudo pallet's `Key` storage item." + ), + # ── Swap ──────────────────────────────────────────────────────────────── + "FeeRateTooHigh": ( + "`set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config " + "constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` " + "before submitting." + ), + "InsufficientInputAmount": ( + "Declared for swap inputs too small to execute, but no current code path raises it " + "since the user-liquidity code was removed. If seen on an older runtime, check that the " + "swap input amount is nonzero and large enough to produce output." + ), + "InvalidLiquidityValue": ( + "Legacy error from the removed V3 user-liquidity code, raised when an added or removed " + "liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current " + "runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`." + ), + "InvalidTickRange": ( + "Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not " + "below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current " + "runtimes; check the tick range arguments on older ones." + ), + "PriceLimitExceeded": ( + "The `limit_price` given to a swap is not beyond the current pool price in the trade's " + "direction, so the swap would immediately breach it. Compare the limit price argument " + "against the subnet's current alpha price before submitting." + ), + "ReservesOutOfBalance": ( + "Swap balancer initialization failed because the subnet's TAO and alpha reserves " + "produce an invalid ratio, for example both reserves are zero when an initial price is " + "supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry." + ), + "ReservesTooLow": ( + "The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step " + "produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves " + "against `MinimumReserve` and reduce the trade size." + ), + "SwapInputTooLarge": ( + "The swap's net input after fees exceeds 1000 times the input-side reserve, the " + "pallet's hard per-trade cap. Compare the input amount against the subnet's input-side " + "reserve (TAO or alpha) and split the trade if needed." + ), + # ── System ────────────────────────────────────────────────────────────── + "CallFiltered": ( + "The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) " + "rejected this call before dispatch. Check whether the specific call is permitted for " + "the origin you used, including any proxy or safe-mode filtering in effect." + ), + "FailedToExtractRuntimeVersion": ( + "The new runtime code passed to `set_code` did not yield a readable version: calling " + "`Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a " + "valid, complete runtime wasm and not truncated or compressed incorrectly." + ), + "InvalidSpecName": ( + "The new runtime's `spec_name` does not match the current runtime, so `set_code` " + "refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure " + "the spec name is identical to the chain's current one." + ), + "MultiBlockMigrationsOngoing": ( + "Runtime code replacement is blocked while a multi-block migration is still executing. " + "Wait for the ongoing migrations to complete (check the multi-block migrations cursor) " + "before retrying `set_code` or the authorized upgrade." + ), + "NonDefaultComposite": ( + "The account cannot be killed because its composite account data is not in the default " + "state. Check the account's `System.Account` entry; all balance and data fields must be " + "default before the account can be removed this way." + ), + "NonZeroRefCount": ( + "The account cannot be purged because other pallets still reference it. Check the " + "`consumers`, `providers`, and `sufficients` counters in the account's `System.Account` " + "record; all references must be released first." + ), + "NothingAuthorized": ( + "No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to " + "apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be " + "recorded before applying the new code." + ), + "SpecVersionNeedsToIncrease": ( + "The new runtime's `spec_version` is not greater than the current one, so the upgrade " + "is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above " + "the version currently on chain." + ), + "Unauthorized": ( + "In System, the code passed to `apply_authorized_upgrade` does not hash to the value in " + "`AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone " + "may cancel it. Check the code hash against the authorization, or the sender against " + "the order's `signer`." + ), + # ── Utility ───────────────────────────────────────────────────────────── + "InvalidDerivedAccount": ( + "Deriving the sub-account for `as_derivative` failed to decode into a valid account id " + "from the (caller, index) entropy. Check the `index` argument and the caller account " + "used for derivation." + ), + "TooManyCalls": ( + "The batch submitted to the utility pallet contains more calls than the batched-calls " + "limit allows. Check the length of the `calls` vector and split the work across " + "multiple smaller `batch`, `batch_all`, or `force_batch` submissions." + ), +} diff --git a/sdk/python/bittensor/result.py b/sdk/python/bittensor/result.py index 3b4aa1cec8..f1c5d27945 100644 --- a/sdk/python/bittensor/result.py +++ b/sdk/python/bittensor/result.py @@ -12,6 +12,7 @@ from typing import Any, Optional from ._generated.errors import ERRORS +from .error_descriptions import DESCRIPTIONS as _DESCRIPTIONS from .error_map import NAME_TO_CODE as _NAME_TO_CODE from .error_map import ErrorCode @@ -311,13 +312,23 @@ def remediation(self) -> str: return help_text return REMEDIATION[self.code] + @property + def description(self) -> Optional[str]: + """What triggered this exact chain error and where to check, from the + per-name table in :mod:`bittensor.error_descriptions`. ``None`` when the + failure carried no module error name (e.g. a pool rejection).""" + return _DESCRIPTIONS.get(self.name) if self.name else None + def to_dict(self) -> dict[str, Any]: - return { + payload = { "message": self.message, "name": self.name, "code": self.code.value, "remediation": self.remediation, } + if self.description: + payload["description"] = self.description + return payload def chain_error_from_substrate_request(error: Exception) -> ChainError: diff --git a/sdk/python/codegen/check.py b/sdk/python/codegen/check.py index 56959078c7..e7d3d2a108 100644 --- a/sdk/python/codegen/check.py +++ b/sdk/python/codegen/check.py @@ -329,12 +329,15 @@ def check_coverage() -> int: def check_names() -> int: from bittensor._generated.errors import ERRORS + from bittensor.error_descriptions import DESCRIPTIONS from bittensor.error_map import NAME_TO_CODE, ErrorCode from bittensor.result import classify_error catalog = {info.name for info in ERRORS.values()} stale = sorted(name for name in NAME_TO_CODE if name not in catalog) unclassified = sorted(name for name in catalog if classify_error("", name) is ErrorCode.UNKNOWN) + undescribed = sorted(name for name in NAME_TO_CODE if name not in DESCRIPTIONS) + orphan_descriptions = sorted(name for name in DESCRIPTIONS if name not in NAME_TO_CODE) if stale: print(f"STALE: error names classified by the SDK but absent from chain: {stale}") if unclassified: @@ -342,11 +345,21 @@ def check_names() -> int: "UNCLASSIFIED: chain error names with no semantic code " f"(add them to bittensor/error_map.py): {unclassified}" ) - if stale or unclassified: + if undescribed: + print( + "UNDESCRIBED: classified error names with no description " + f"(add them to bittensor/error_descriptions.py): {undescribed}" + ) + if orphan_descriptions: + print( + "ORPHANED: described error names no longer classified " + f"(remove them from bittensor/error_descriptions.py): {orphan_descriptions}" + ) + if stale or unclassified or undescribed or orphan_descriptions: return 1 print( - f"names ok: all {len(catalog)} chain error names classify to a semantic code " - "and no mapped name is stale" + f"names ok: all {len(catalog)} chain error names classify to a semantic code, " + "every classified name is described, and no mapped name is stale" ) return 0 diff --git a/website/apps/bittensor-website/public/catalog/errors.json b/website/apps/bittensor-website/public/catalog/errors.json index 97b5a40560..f657e64cab 100644 --- a/website/apps/bittensor-website/public/catalog/errors.json +++ b/website/apps/bittensor-website/public/catalog/errors.json @@ -20,358 +20,1417 @@ "unknown": "inspect the message for details" }, "chain_errors": { - "AccountNotAllowedCommit": "not_authorized", - "AccountRejectsLockedAlpha": "invalid_argument", - "ActiveLockExists": "already_exists", - "ActivityCutoffFactorMilliOutOfBounds": "invalid_argument", - "ActivityCutoffTooLow": "invalid_argument", - "AddStakeBurnRateLimitExceeded": "rate_limited", - "AdminActionProhibitedDuringWeightsWindow": "too_early", - "AllNetworksInImmunity": "too_early", - "AlphaHighTooLow": "invalid_argument", - "AlphaLowOutOfRange": "invalid_argument", - "AlreadyApproved": "already_exists", - "AlreadyDeposited": "already_exists", - "AlreadyFinalized": "already_exists", - "AlreadyFinalizing": "already_exists", - "AlreadyNoted": "already_exists", - "AlreadyStored": "already_exists", - "AmountTooLow": "invalid_argument", - "AnnouncedColdkeyHashDoesNotMatch": "invalid_argument", - "AnnouncementDepositInvariantViolated": "internal", - "ArithmeticOverflow": "internal", - "AutoEpochAlreadyImminent": "already_exists", - "BadEncKeyLen": "invalid_argument", - "BalanceLow": "insufficient_balance", - "BalanceWithdrawalError": "insufficient_balance", - "BeneficiaryDoesNotOwnHotkey": "not_authorized", - "BlockDurationTooLong": "invalid_argument", - "BlockDurationTooShort": "invalid_argument", - "BondsMovingAverageMaxReached": "limit_exceeded", - "CallDisabled": "disabled", - "CallFiltered": "not_authorized", - "CallUnavailable": "not_found", - "CanNotSetRootNetworkWeights": "invalid_argument", - "CannotAddSelfAsDelegateDependency": "invalid_argument", - "CannotAffordLockCost": "insufficient_balance", - "CannotBurnOrRecycleOnRootSubnet": "invalid_argument", - "CannotEndInPast": "invalid_argument", - "CannotReleaseYet": "too_early", - "CannotUseSystemAccount": "not_authorized", - "CapNotRaised": "too_early", - "CapRaised": "limit_exceeded", - "CapTooLow": "invalid_argument", - "ChainIdMismatch": "invalid_argument", - "ChangePending": "already_exists", - "ChildParentInconsistency": "invalid_argument", - "CodeInUse": "invalid_argument", - "CodeInfoNotFound": "not_found", - "CodeNotFound": "not_found", - "CodeRejected": "invalid_argument", - "CodeTooLarge": "limit_exceeded", - "ColdKeyAlreadyAssociated": "already_exists", - "ColdkeySwapAlreadyDisputed": "already_exists", - "ColdkeySwapAnnounced": "already_exists", - "ColdkeySwapAnnouncementNotFound": "not_found", - "ColdkeySwapClearTooEarly": "too_early", - "ColdkeySwapDisputed": "not_authorized", - "ColdkeySwapReannouncedTooEarly": "too_early", - "ColdkeySwapTooEarly": "too_early", - "CommitRevealDisabled": "disabled", - "CommitRevealEnabled": "disabled", - "CommittingWeightsTooFast": "rate_limited", - "ContractNotFound": "not_found", - "ContractReverted": "internal", - "ContractTrapped": "internal", - "ContributionPeriodEnded": "expired", - "ContributionPeriodNotEnded": "too_early", - "ContributionTooLow": "invalid_argument", - "CreateOriginNotAllowed": "not_authorized", - "CurrencyError": "internal", - "DeadAccount": "not_found", - "DecodingFailed": "invalid_argument", - "DelegateDependencyAlreadyExists": "already_exists", - "DelegateDependencyNotFound": "not_found", - "DelegateTakeTooHigh": "invalid_argument", - "DelegateTakeTooLow": "invalid_argument", - "DelegateTxRateLimitExceeded": "rate_limited", - "DeltaZero": "invalid_argument", - "DepositCannotBeWithdrawn": "invalid_argument", - "DepositTooLow": "invalid_argument", - "Deprecated": "disabled", - "DisabledTemporarily": "disabled", - "DrandConnectionFailure": "internal", - "Duplicate": "already_exists", - "DuplicateChild": "invalid_argument", - "DuplicateContract": "already_exists", - "DuplicateOffenceReport": "already_exists", - "DuplicateOrderInBatch": "invalid_argument", - "DuplicateUids": "invalid_argument", - "DynamicTempoBlockedByCommitReveal": "disabled", - "Entered": "already_exists", - "EpochTriggerAlreadyPending": "already_exists", - "EvmKeyAssociateRateLimitExceeded": "rate_limited", - "EvmKeyAssociationLimitExceeded": "limit_exceeded", - "ExistentialDeposit": "insufficient_balance", - "ExistingVestingSchedule": "already_exists", - "Exited": "already_exists", - "ExpectedBeneficiaryOrigin": "not_authorized", - "Expendability": "insufficient_balance", - "ExpiredWeightCommit": "expired", - "FailedToExtractRuntimeVersion": "invalid_argument", - "FailedToSchedule": "internal", - "FaucetDisabled": "disabled", - "FeeOverflow": "internal", - "FeeRateTooHigh": "invalid_argument", - "FirstEmissionBlockNumberAlreadySet": "already_exists", - "GasLimitTooHigh": "invalid_argument", - "GasLimitTooLow": "invalid_argument", - "GasPriceTooLow": "invalid_argument", - "HotKeyAccountNotExists": "not_registered", - "HotKeyAlreadyDelegate": "already_exists", - "HotKeyAlreadyRegisteredInSubNet": "already_exists", - "HotKeyNotRegisteredInNetwork": "not_registered", - "HotKeyNotRegisteredInSubNet": "not_registered", - "HotKeySetTxRateLimitExceeded": "rate_limited", - "HotKeySwapOnSubnetIntervalNotPassed": "rate_limited", - "IncorrectCommitRevealVersion": "invalid_argument", - "IncorrectPartialFillAmount": "invalid_argument", - "IncorrectWeightVersionKey": "invalid_argument", - "Indeterministic": "invalid_argument", - "InputForwarded": "invalid_argument", - "InputLengthsUnequal": "invalid_argument", - "InsufficientBalance": "insufficient_balance", - "InsufficientInputAmount": "invalid_argument", - "InsufficientLiquidity": "insufficient_liquidity", - "InsufficientStakeForLock": "insufficient_balance", - "InvalidCallFlags": "invalid_argument", - "InvalidChainId": "invalid_argument", - "InvalidChild": "invalid_argument", - "InvalidChildkeyTake": "invalid_argument", - "InvalidCrowdloanId": "not_found", - "InvalidDerivedAccount": "invalid_argument", - "InvalidDerivedAccountId": "invalid_argument", - "InvalidDifficulty": "invalid_argument", - "InvalidEquivocationProof": "invalid_argument", - "InvalidFinalizationConfig": "invalid_argument", - "InvalidIdentity": "invalid_argument", - "InvalidIpAddress": "invalid_argument", - "InvalidIpType": "invalid_argument", - "InvalidKeyOwnershipProof": "invalid_argument", - "InvalidLeaseBeneficiary": "invalid_argument", - "InvalidLiquidityValue": "invalid_argument", - "InvalidNonce": "invalid_argument", - "InvalidNumRootClaim": "invalid_argument", - "InvalidOrigin": "not_authorized", - "InvalidPort": "invalid_argument", - "InvalidRecoveredPublicKey": "invalid_argument", - "InvalidRevealCommitHashNotMatch": "invalid_argument", - "InvalidRevealRound": "expired", - "InvalidRootClaimThreshold": "invalid_argument", - "InvalidRoundNumber": "invalid_argument", - "InvalidSchedule": "invalid_argument", - "InvalidSeal": "invalid_argument", - "InvalidSignature": "invalid_argument", - "InvalidSpecName": "invalid_argument", - "InvalidSubnetNumber": "invalid_argument", - "InvalidTickRange": "invalid_argument", - "InvalidValue": "invalid_argument", - "InvalidVotingPowerEmaAlpha": "invalid_argument", - "InvalidWorkBlock": "invalid_argument", - "IssuanceDeactivated": "disabled", - "LeaseCannotEndInThePast": "invalid_argument", - "LeaseDoesNotExist": "not_found", - "LeaseHasNoEndBlock": "invalid_argument", - "LeaseHasNotEnded": "too_early", - "LeaseNetuidNotFound": "not_found", - "LimitOrdersDisabled": "disabled", - "LiquidAlphaDisabled": "disabled", - "LiquidityRestrictions": "insufficient_balance", - "LockHotkeyMismatch": "invalid_argument", - "LockIdOverFlow": "limit_exceeded", - "MaxAllowedUIdsLessThanCurrentUIds": "invalid_argument", - "MaxAllowedUidsGreaterThanDefaultMaxAllowedUids": "invalid_argument", - "MaxAllowedUidsLessThanMinAllowedUids": "invalid_argument", - "MaxCallDepthReached": "limit_exceeded", - "MaxContributionReached": "limit_exceeded", - "MaxContributorsReached": "limit_exceeded", - "MaxDelegateDependenciesReached": "limit_exceeded", - "MaxValidatorsLargerThanMaxUIds": "invalid_argument", - "MaxWeightExceeded": "limit_exceeded", - "MaxWeightTooLow": "invalid_argument", - "MaximumContributionTooLow": "invalid_argument", - "MechanismDoesNotExist": "subnet_not_exists", - "MigrationInProgress": "too_early", - "MinAllowedUidsGreaterThanCurrentUids": "invalid_argument", - "MinAllowedUidsGreaterThanMaxAllowedUids": "invalid_argument", - "MinimumContributionTooHigh": "invalid_argument", - "MinimumContributionTooLow": "invalid_argument", - "MinimumThreshold": "invalid_argument", - "MultiBlockMigrationsOngoing": "too_early", - "Named": "invalid_argument", - "NeedWaitingMoreBlocksToStarCall": "too_early", - "NegativeSigmoidSteepness": "invalid_argument", - "NetworkDissolveAlreadyQueued": "already_exists", - "NetworkTxRateLimitExceeded": "rate_limited", - "NeuronNoValidatorPermit": "not_authorized", - "NewColdKeyIsHotkey": "invalid_argument", - "NewHotKeyIsSameWithOld": "invalid_argument", - "NewHotKeyNotCleanForRootSwap": "invalid_argument", - "NoApprovalsNeeded": "invalid_argument", - "NoChainExtension": "disabled", - "NoContribution": "not_found", - "NoDeposit": "not_found", - "NoExistingLock": "not_found", - "NoMigrationPerformed": "invalid_argument", - "NoNeuronIdAvailable": "limit_exceeded", - "NoPermission": "not_authorized", - "NoSelfProxy": "invalid_argument", - "NoTimepoint": "invalid_argument", - "NoWeightsCommitFound": "not_found", - "NonAssociatedColdKey": "not_authorized", - "NonDefaultComposite": "invalid_argument", - "NonZeroRefCount": "invalid_argument", - "NoneValue": "not_found", - "NotAllowed": "not_authorized", - "NotAuthorized": "not_authorized", - "NotConfigured": "disabled", - "NotEnoughAlphaOutToRecycle": "insufficient_liquidity", - "NotEnoughBalanceToPaySwapColdKey": "insufficient_balance", - "NotEnoughBalanceToPaySwapHotKey": "insufficient_balance", - "NotEnoughBalanceToStake": "insufficient_balance", - "NotEnoughStake": "insufficient_balance", - "NotEnoughStakeToSetChildkeys": "insufficient_balance", - "NotEnoughStakeToSetWeights": "insufficient_balance", - "NotEnoughStakeToWithdraw": "insufficient_balance", - "NotFound": "not_found", - "NotNoted": "not_found", - "NotOwner": "not_authorized", - "NotPermittedOnRootSubnet": "invalid_argument", - "NotProxy": "not_authorized", - "NotReadyToDissolve": "too_early", - "NotRequested": "not_found", - "NotRootSubnet": "invalid_argument", - "NotSubnetOwner": "not_authorized", - "NothingAuthorized": "not_found", - "OrderAlreadyProcessed": "already_exists", - "OrderCancelled": "expired", - "OrderExpired": "expired", - "OrderNetUidMismatch": "invalid_argument", - "OutOfBounds": "invalid_argument", - "OutOfGas": "limit_exceeded", - "OutOfTransientStorage": "limit_exceeded", - "OutputBufferTooSmall": "invalid_argument", - "Overflow": "internal", - "POWRegistrationDisabled": "disabled", - "PalletHotkeyNotRegistered": "not_registered", - "PartialFillsNotEnabled": "disabled", - "PauseFailed": "invalid_argument", - "PaymentOverflow": "internal", - "PreLogExists": "invalid_argument", - "PriceConditionNotMet": "too_early", - "PriceLimitExceeded": "insufficient_liquidity", - "ProportionOverflow": "invalid_argument", - "PulseVerificationError": "invalid_argument", - "RandomSubjectTooLong": "limit_exceeded", - "ReentranceDenied": "invalid_argument", - "Reentrancy": "internal", - "RegistrationNotPermittedOnRootSubnet": "invalid_argument", - "RegistrationPriceLimitExceeded": "limit_exceeded", - "RelayerMissMatch": "invalid_argument", - "RelayerRequiredForPartialFill": "invalid_argument", - "Requested": "invalid_argument", - "RequireSudo": "not_authorized", - "RescheduleNoChange": "invalid_argument", - "ReservesOutOfBalance": "insufficient_liquidity", - "ReservesTooLow": "insufficient_liquidity", - "ResumeFailed": "invalid_argument", - "RevealPeriodTooLarge": "invalid_argument", - "RevealPeriodTooSmall": "invalid_argument", - "RevealTooEarly": "too_early", - "RootNetUidNotAllowed": "invalid_argument", - "RootNetworkDoesNotExist": "subnet_not_exists", - "SameAutoStakeHotkeyAlreadySet": "already_exists", - "SameNetuid": "invalid_argument", - "SenderInSignatories": "invalid_argument", - "ServingRateLimitExceeded": "rate_limited", - "SettingWeightsTooFast": "rate_limited", - "SignatoriesOutOfOrder": "invalid_argument", - "SlippageTooHigh": "insufficient_liquidity", - "SpaceLimitExceeded": "rate_limited", - "SpecVersionNeedsToIncrease": "invalid_argument", - "StakeTooLowForRoot": "insufficient_balance", - "StakeUnavailable": "insufficient_balance", - "StakingRateLimitExceeded": "rate_limited", - "StartCallNotReady": "too_early", - "StateChangeDenied": "not_authorized", - "StorageDepositLimitExhausted": "limit_exceeded", - "StorageDepositNotEnoughFunds": "insufficient_balance", - "StorageOverflow": "internal", - "SubNetRegistrationDisabled": "disabled", - "SubnetBuybackRateLimitExceeded": "rate_limited", - "SubnetDoesNotExist": "subnet_not_exists", - "SubnetLimitReached": "limit_exceeded", - "SubnetNotExists": "subnet_not_exists", - "SubtokenDisabled": "subtoken_disabled", - "SwapInputTooLarge": "insufficient_liquidity", - "SwapReturnedZero": "insufficient_liquidity", - "SymbolAlreadyInUse": "already_exists", - "SymbolDoesNotExist": "not_found", - "TargetBlockNumberInPast": "invalid_argument", - "TempoOutOfBounds": "invalid_argument", - "TerminatedInConstructor": "internal", - "TerminatedWhileReentrant": "invalid_argument", - "TooBig": "limit_exceeded", - "TooFew": "invalid_argument", - "TooFewSignatories": "invalid_argument", - "TooMany": "limit_exceeded", - "TooManyCalls": "limit_exceeded", - "TooManyChildren": "limit_exceeded", - "TooManyFieldsInCommitmentInfo": "limit_exceeded", - "TooManyFreezes": "limit_exceeded", - "TooManyHolds": "limit_exceeded", - "TooManyPendingExtrinsics": "limit_exceeded", - "TooManyRegistrationsThisBlock": "rate_limited", - "TooManyRegistrationsThisInterval": "rate_limited", - "TooManyReserves": "limit_exceeded", - "TooManySignatories": "limit_exceeded", - "TooManyTopics": "limit_exceeded", - "TooManyUIDsPerMechanism": "limit_exceeded", - "TooManyUnrevealedCommits": "limit_exceeded", - "TooSoon": "rate_limited", - "TransactionMustComeFromEOA": "not_authorized", - "TransactorAccountShouldBeHotKey": "not_authorized", - "TransferDisallowed": "disabled", - "TransferFailed": "insufficient_balance", - "TrimmingWouldExceedMaxImmunePercentage": "limit_exceeded", - "TxChildkeyTakeRateLimitExceeded": "rate_limited", - "TxRateLimitExceeded": "rate_limited", - "UidMapCouldNotBeCleared": "internal", - "UidVecContainInvalidOne": "invalid_argument", - "UidsLengthExceedUidsInSubNet": "limit_exceeded", - "UnableToRecoverPublicKey": "invalid_argument", - "Unannounced": "too_early", - "Unauthorized": "not_authorized", - "Undefined": "internal", - "Underflow": "internal", - "UnexpectedTimepoint": "invalid_argument", - "UnexpectedUnreserveLeftover": "internal", - "UnlockAmountTooHigh": "insufficient_balance", - "Unproxyable": "not_authorized", - "Unreachable": "internal", - "UnverifiedPulse": "invalid_argument", - "ValueNotInBounds": "invalid_argument", - "ValueTooLarge": "limit_exceeded", - "VestingBalance": "insufficient_balance", - "VotingPowerTrackingNotEnabled": "disabled", - "WaitingForDissolvedSubnetCleanup": "too_early", - "WeightExceedsAbsoluteMax": "limit_exceeded", - "WeightVecLengthIsLow": "invalid_argument", - "WeightVecNotEqualSize": "invalid_argument", - "WithdrawFailed": "insufficient_balance", - "WrongTimepoint": "invalid_argument", - "XCMDecodeFailed": "invalid_argument", - "ZeroBalanceAfterWithdrawn": "insufficient_balance", - "ZeroShareInBatch": "invalid_argument" + "AccountNotAllowedCommit": { + "code": "not_authorized", + "description": "Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet." + }, + "AccountRejectsLockedAlpha": { + "code": "invalid_argument", + "description": "Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying." + }, + "ActiveLockExists": { + "code": "already_exists", + "description": "The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first." + }, + "ActivityCutoffFactorMilliOutOfBounds": { + "code": "invalid_argument", + "description": "The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting." + }, + "ActivityCutoffTooLow": { + "code": "invalid_argument", + "description": "An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `." + }, + "AddStakeBurnRateLimitExceeded": { + "code": "rate_limited", + "description": "The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes." + }, + "AdminActionProhibitedDuringWeightsWindow": { + "code": "too_early", + "description": "An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires." + }, + "AllNetworksInImmunity": { + "code": "too_early", + "description": "Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity." + }, + "AlphaHighTooLow": { + "code": "invalid_argument", + "description": "The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid." + }, + "AlphaLowOutOfRange": { + "code": "invalid_argument", + "description": "The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid." + }, + "AlreadyApproved": { + "code": "already_exists", + "description": "The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list." + }, + "AlreadyDeposited": { + "code": "already_exists", + "description": "The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason." + }, + "AlreadyFinalized": { + "code": "already_exists", + "description": "The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`." + }, + "AlreadyFinalizing": { + "code": "already_exists", + "description": "A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying." + }, + "AlreadyNoted": { + "code": "already_exists", + "description": "The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again." + }, + "AlreadyStored": { + "code": "already_exists", + "description": "The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again." + }, + "AmountTooLow": { + "code": "invalid_argument", + "description": "A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount." + }, + "AnnouncedColdkeyHashDoesNotMatch": { + "code": "invalid_argument", + "description": "The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to." + }, + "AnnouncementDepositInvariantViolated": { + "code": "internal", + "description": "Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input." + }, + "ArithmeticOverflow": { + "code": "internal", + "description": "Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts." + }, + "AutoEpochAlreadyImminent": { + "code": "already_exists", + "description": "`trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire." + }, + "BadEncKeyLen": { + "code": "invalid_argument", + "description": "The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing." + }, + "BalanceLow": { + "code": "insufficient_balance", + "description": "The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price." + }, + "BalanceWithdrawalError": { + "code": "insufficient_balance", + "description": "The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up." + }, + "BeneficiaryDoesNotOwnHotkey": { + "code": "not_authorized", + "description": "When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns." + }, + "BlockDurationTooLong": { + "code": "invalid_argument", + "description": "The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`." + }, + "BlockDurationTooShort": { + "code": "invalid_argument", + "description": "The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`." + }, + "BondsMovingAverageMaxReached": { + "code": "limit_exceeded", + "description": "A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root." + }, + "CallDisabled": { + "code": "disabled", + "description": "The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version." + }, + "CallFiltered": { + "code": "not_authorized", + "description": "The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect." + }, + "CallUnavailable": { + "code": "not_found", + "description": "During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet." + }, + "CanNotSetRootNetworkWeights": { + "code": "invalid_argument", + "description": "`set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism." + }, + "CannotAddSelfAsDelegateDependency": { + "code": "invalid_argument", + "description": "A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash." + }, + "CannotAffordLockCost": { + "code": "insufficient_balance", + "description": "The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet." + }, + "CannotBurnOrRecycleOnRootSubnet": { + "code": "invalid_argument", + "description": "`recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn." + }, + "CannotEndInPast": { + "code": "invalid_argument", + "description": "The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater." + }, + "CannotReleaseYet": { + "code": "too_early", + "description": "`release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config." + }, + "CannotUseSystemAccount": { + "code": "not_authorized", + "description": "The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`." + }, + "CapNotRaised": { + "code": "too_early", + "description": "`finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing." + }, + "CapRaised": { + "code": "limit_exceeded", + "description": "A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`." + }, + "CapTooLow": { + "code": "invalid_argument", + "description": "On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry." + }, + "ChainIdMismatch": { + "code": "invalid_argument", + "description": "The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed." + }, + "ChangePending": { + "code": "already_exists", + "description": "A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first." + }, + "ChildParentInconsistency": { + "code": "invalid_argument", + "description": "A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap." + }, + "CodeInUse": { + "code": "invalid_argument", + "description": "`remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal." + }, + "CodeInfoNotFound": { + "code": "not_found", + "description": "No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed." + }, + "CodeNotFound": { + "code": "not_found", + "description": "No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed." + }, + "CodeRejected": { + "code": "invalid_argument", + "description": "The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason." + }, + "CodeTooLarge": { + "code": "limit_exceeded", + "description": "The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract." + }, + "ColdKeyAlreadyAssociated": { + "code": "already_exists", + "description": "The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead." + }, + "ColdkeySwapAlreadyDisputed": { + "code": "already_exists", + "description": "`dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed." + }, + "ColdkeySwapAnnounced": { + "code": "already_exists", + "description": "The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement." + }, + "ColdkeySwapAnnouncementNotFound": { + "code": "not_found", + "description": "`coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first." + }, + "ColdkeySwapClearTooEarly": { + "code": "too_early", + "description": "The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later." + }, + "ColdkeySwapDisputed": { + "code": "not_authorized", + "description": "All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact." + }, + "ColdkeySwapReannouncedTooEarly": { + "code": "too_early", + "description": "`announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later." + }, + "ColdkeySwapTooEarly": { + "code": "too_early", + "description": "`coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then." + }, + "CommitRevealDisabled": { + "code": "disabled", + "description": "A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled." + }, + "CommitRevealEnabled": { + "code": "disabled", + "description": "Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`." + }, + "CommittingWeightsTooFast": { + "code": "rate_limited", + "description": "The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait." + }, + "ContractNotFound": { + "code": "not_found", + "description": "No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated." + }, + "ContractReverted": { + "code": "internal", + "description": "The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value." + }, + "ContractTrapped": { + "code": "internal", + "description": "The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations." + }, + "ContributionPeriodEnded": { + "code": "expired", + "description": "A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized." + }, + "ContributionPeriodNotEnded": { + "code": "too_early", + "description": "The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number." + }, + "ContributionTooLow": { + "code": "invalid_argument", + "description": "The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount." + }, + "CreateOriginNotAllowed": { + "code": "not_authorized", + "description": "A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list." + }, + "CurrencyError": { + "code": "internal", + "description": "A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason." + }, + "DeadAccount": { + "code": "not_found", + "description": "The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs." + }, + "DecodingFailed": { + "code": "invalid_argument", + "description": "Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API." + }, + "DelegateDependencyAlreadyExists": { + "code": "already_exists", + "description": "The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it." + }, + "DelegateDependencyNotFound": { + "code": "not_found", + "description": "`unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info." + }, + "DelegateTakeTooHigh": { + "code": "invalid_argument", + "description": "The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it." + }, + "DelegateTakeTooLow": { + "code": "invalid_argument", + "description": "The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item." + }, + "DelegateTxRateLimitExceeded": { + "code": "rate_limited", + "description": "The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later." + }, + "DeltaZero": { + "code": "invalid_argument", + "description": "The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount." + }, + "DepositCannotBeWithdrawn": { + "code": "invalid_argument", + "description": "The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry." + }, + "DepositTooLow": { + "code": "invalid_argument", + "description": "The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit." + }, + "Deprecated": { + "code": "disabled", + "description": "The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`)." + }, + "DisabledTemporarily": { + "code": "disabled", + "description": "The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled." + }, + "DrandConnectionFailure": { + "code": "internal", + "description": "Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints." + }, + "Duplicate": { + "code": "already_exists", + "description": "This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple." + }, + "DuplicateChild": { + "code": "invalid_argument", + "description": "The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid." + }, + "DuplicateContract": { + "code": "already_exists", + "description": "Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address." + }, + "DuplicateOffenceReport": { + "code": "already_exists", + "description": "The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again." + }, + "DuplicateOrderInBatch": { + "code": "invalid_argument", + "description": "Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`." + }, + "DuplicateUids": { + "code": "invalid_argument", + "description": "The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector." + }, + "DynamicTempoBlockedByCommitReveal": { + "code": "disabled", + "description": "`trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs." + }, + "Entered": { + "code": "already_exists", + "description": "Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages." + }, + "EpochTriggerAlreadyPending": { + "code": "already_exists", + "description": "`trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again." + }, + "EvmKeyAssociateRateLimitExceeded": { + "code": "rate_limited", + "description": "`associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later." + }, + "EvmKeyAssociationLimitExceeded": { + "code": "limit_exceeded", + "description": "The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address." + }, + "ExistentialDeposit": { + "code": "insufficient_balance", + "description": "The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant." + }, + "ExistingVestingSchedule": { + "code": "already_exists", + "description": "A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule." + }, + "Exited": { + "code": "already_exists", + "description": "Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting." + }, + "ExpectedBeneficiaryOrigin": { + "code": "not_authorized", + "description": "A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey." + }, + "Expendability": { + "code": "insufficient_balance", + "description": "The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable." + }, + "ExpiredWeightCommit": { + "code": "expired", + "description": "The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time." + }, + "FailedToExtractRuntimeVersion": { + "code": "invalid_argument", + "description": "The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly." + }, + "FailedToSchedule": { + "code": "internal", + "description": "The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated." + }, + "FaucetDisabled": { + "code": "disabled", + "description": "The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead." + }, + "FeeOverflow": { + "code": "internal", + "description": "Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction." + }, + "FeeRateTooHigh": { + "code": "invalid_argument", + "description": "`set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting." + }, + "FirstEmissionBlockNumberAlreadySet": { + "code": "already_exists", + "description": "`start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed." + }, + "GasLimitTooHigh": { + "code": "invalid_argument", + "description": "The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it." + }, + "GasLimitTooLow": { + "code": "invalid_argument", + "description": "The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result." + }, + "GasPriceTooLow": { + "code": "invalid_argument", + "description": "The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee." + }, + "HotKeyAccountNotExists": { + "code": "not_registered", + "description": "The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first." + }, + "HotKeyAlreadyDelegate": { + "code": "already_exists", + "description": "`become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed." + }, + "HotKeyAlreadyRegisteredInSubNet": { + "code": "already_exists", + "description": "A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid." + }, + "HotKeyNotRegisteredInNetwork": { + "code": "not_registered", + "description": "The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first." + }, + "HotKeyNotRegisteredInSubNet": { + "code": "not_registered", + "description": "The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed." + }, + "HotKeySetTxRateLimitExceeded": { + "code": "rate_limited", + "description": "The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks." + }, + "HotKeySwapOnSubnetIntervalNotPassed": { + "code": "rate_limited", + "description": "A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval." + }, + "IncorrectCommitRevealVersion": { + "code": "invalid_argument", + "description": "The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version." + }, + "IncorrectPartialFillAmount": { + "code": "invalid_argument", + "description": "The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`." + }, + "IncorrectWeightVersionKey": { + "code": "invalid_argument", + "description": "The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key." + }, + "Indeterministic": { + "code": "invalid_argument", + "description": "Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically." + }, + "InputForwarded": { + "code": "invalid_argument", + "description": "The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards." + }, + "InputLengthsUnequal": { + "code": "invalid_argument", + "description": "A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length." + }, + "InsufficientBalance": { + "code": "insufficient_balance", + "description": "The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved." + }, + "InsufficientInputAmount": { + "code": "invalid_argument", + "description": "Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output." + }, + "InsufficientLiquidity": { + "code": "insufficient_liquidity", + "description": "The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount." + }, + "InsufficientStakeForLock": { + "code": "insufficient_balance", + "description": "The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first." + }, + "InvalidCallFlags": { + "code": "invalid_argument", + "description": "The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values." + }, + "InvalidChainId": { + "code": "invalid_argument", + "description": "The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction." + }, + "InvalidChild": { + "code": "invalid_argument", + "description": "The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved." + }, + "InvalidChildkeyTake": { + "code": "invalid_argument", + "description": "The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds." + }, + "InvalidCrowdloanId": { + "code": "not_found", + "description": "No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued." + }, + "InvalidDerivedAccount": { + "code": "invalid_argument", + "description": "Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation." + }, + "InvalidDerivedAccountId": { + "code": "invalid_argument", + "description": "Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one)." + }, + "InvalidDifficulty": { + "code": "invalid_argument", + "description": "The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block." + }, + "InvalidEquivocationProof": { + "code": "invalid_argument", + "description": "The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set." + }, + "InvalidFinalizationConfig": { + "code": "invalid_argument", + "description": "Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry." + }, + "InvalidIdentity": { + "code": "invalid_argument", + "description": "The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity." + }, + "InvalidIpAddress": { + "code": "invalid_argument", + "description": "The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed." + }, + "InvalidIpType": { + "code": "invalid_argument", + "description": "The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted." + }, + "InvalidKeyOwnershipProof": { + "code": "invalid_argument", + "description": "The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report." + }, + "InvalidLeaseBeneficiary": { + "code": "invalid_argument", + "description": "The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey." + }, + "InvalidLiquidityValue": { + "code": "invalid_argument", + "description": "Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`." + }, + "InvalidNonce": { + "code": "invalid_argument", + "description": "The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`." + }, + "InvalidNumRootClaim": { + "code": "invalid_argument", + "description": "The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number." + }, + "InvalidOrigin": { + "code": "not_authorized", + "description": "The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`." + }, + "InvalidPort": { + "code": "invalid_argument", + "description": "The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port." + }, + "InvalidRecoveredPublicKey": { + "code": "invalid_argument", + "description": "The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format)." + }, + "InvalidRevealCommitHashNotMatch": { + "code": "invalid_argument", + "description": "The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid." + }, + "InvalidRevealRound": { + "code": "expired", + "description": "A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number." + }, + "InvalidRootClaimThreshold": { + "code": "invalid_argument", + "description": "The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid." + }, + "InvalidRoundNumber": { + "code": "invalid_argument", + "description": "A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`." + }, + "InvalidSchedule": { + "code": "invalid_argument", + "description": "The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments." + }, + "InvalidSeal": { + "code": "invalid_argument", + "description": "The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit." + }, + "InvalidSignature": { + "code": "invalid_argument", + "description": "Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed." + }, + "InvalidSpecName": { + "code": "invalid_argument", + "description": "The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one." + }, + "InvalidSubnetNumber": { + "code": "invalid_argument", + "description": "A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit." + }, + "InvalidTickRange": { + "code": "invalid_argument", + "description": "Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones." + }, + "InvalidValue": { + "code": "invalid_argument", + "description": "A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`)." + }, + "InvalidVotingPowerEmaAlpha": { + "code": "invalid_argument", + "description": "The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid." + }, + "InvalidWorkBlock": { + "code": "invalid_argument", + "description": "The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block." + }, + "IssuanceDeactivated": { + "code": "disabled", + "description": "Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again." + }, + "LeaseCannotEndInThePast": { + "code": "invalid_argument", + "description": "The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease." + }, + "LeaseDoesNotExist": { + "code": "not_found", + "description": "The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated." + }, + "LeaseHasNoEndBlock": { + "code": "invalid_argument", + "description": "The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id." + }, + "LeaseHasNotEnded": { + "code": "too_early", + "description": "The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes." + }, + "LeaseNetuidNotFound": { + "code": "not_found", + "description": "After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete." + }, + "LimitOrdersDisabled": { + "code": "disabled", + "description": "Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet." + }, + "LiquidAlphaDisabled": { + "code": "disabled", + "description": "Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first." + }, + "LiquidityRestrictions": { + "code": "insufficient_balance", + "description": "The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal." + }, + "LockHotkeyMismatch": { + "code": "invalid_argument", + "description": "The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first." + }, + "LockIdOverFlow": { + "code": "limit_exceeded", + "description": "The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem." + }, + "MaxAllowedUIdsLessThanCurrentUIds": { + "code": "invalid_argument", + "description": "`sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid." + }, + "MaxAllowedUidsGreaterThanDefaultMaxAllowedUids": { + "code": "invalid_argument", + "description": "`sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value." + }, + "MaxAllowedUidsLessThanMinAllowedUids": { + "code": "invalid_argument", + "description": "`sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid." + }, + "MaxCallDepthReached": { + "code": "limit_exceeded", + "description": "A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth." + }, + "MaxContributionReached": { + "code": "limit_exceeded", + "description": "The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`." + }, + "MaxContributorsReached": { + "code": "limit_exceeded", + "description": "The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant." + }, + "MaxDelegateDependenciesReached": { + "code": "limit_exceeded", + "description": "`lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first." + }, + "MaxValidatorsLargerThanMaxUIds": { + "code": "invalid_argument", + "description": "`sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid." + }, + "MaxWeightExceeded": { + "code": "limit_exceeded", + "description": "After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting." + }, + "MaxWeightTooLow": { + "code": "invalid_argument", + "description": "The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`." + }, + "MaximumContributionTooLow": { + "code": "invalid_argument", + "description": "The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry." + }, + "MechanismDoesNotExist": { + "code": "subnet_not_exists", + "description": "The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet." + }, + "MigrationInProgress": { + "code": "too_early", + "description": "A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it." + }, + "MinAllowedUidsGreaterThanCurrentUids": { + "code": "invalid_argument", + "description": "`sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid." + }, + "MinAllowedUidsGreaterThanMaxAllowedUids": { + "code": "invalid_argument", + "description": "`sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid." + }, + "MinimumContributionTooHigh": { + "code": "invalid_argument", + "description": "The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`." + }, + "MinimumContributionTooLow": { + "code": "invalid_argument", + "description": "The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value." + }, + "MinimumThreshold": { + "code": "invalid_argument", + "description": "The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case." + }, + "MultiBlockMigrationsOngoing": { + "code": "too_early", + "description": "Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade." + }, + "Named": { + "code": "invalid_argument", + "description": "An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map." + }, + "NeedWaitingMoreBlocksToStarCall": { + "code": "too_early", + "description": "The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens." + }, + "NegativeSigmoidSteepness": { + "code": "invalid_argument", + "description": "A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root." + }, + "NetworkDissolveAlreadyQueued": { + "code": "already_exists", + "description": "The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request." + }, + "NetworkTxRateLimitExceeded": { + "code": "rate_limited", + "description": "The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks." + }, + "NeuronNoValidatorPermit": { + "code": "not_authorized", + "description": "The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator." + }, + "NewColdKeyIsHotkey": { + "code": "invalid_argument", + "description": "The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey." + }, + "NewHotKeyIsSameWithOld": { + "code": "invalid_argument", + "description": "swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey." + }, + "NewHotKeyNotCleanForRootSwap": { + "code": "invalid_argument", + "description": "The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey." + }, + "NoApprovalsNeeded": { + "code": "invalid_argument", + "description": "The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it." + }, + "NoChainExtension": { + "code": "disabled", + "description": "The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against." + }, + "NoContribution": { + "code": "not_found", + "description": "The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question." + }, + "NoDeposit": { + "code": "not_found", + "description": "No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block." + }, + "NoExistingLock": { + "code": "not_found", + "description": "move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey." + }, + "NoMigrationPerformed": { + "code": "invalid_argument", + "description": "A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument." + }, + "NoNeuronIdAvailable": { + "code": "limit_exceeded", + "description": "Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire." + }, + "NoPermission": { + "code": "not_authorized", + "description": "The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments." + }, + "NoSelfProxy": { + "code": "invalid_argument", + "description": "An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account." + }, + "NoTimepoint": { + "code": "invalid_argument", + "description": "No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`." + }, + "NoWeightsCommitFound": { + "code": "not_found", + "description": "A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window." + }, + "NonAssociatedColdKey": { + "code": "not_authorized", + "description": "The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it." + }, + "NonDefaultComposite": { + "code": "invalid_argument", + "description": "The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way." + }, + "NonZeroRefCount": { + "code": "invalid_argument", + "description": "The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first." + }, + "NoneValue": { + "code": "not_found", + "description": "Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization." + }, + "NotAllowed": { + "code": "not_authorized", + "description": "Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value." + }, + "NotAuthorized": { + "code": "not_authorized", + "description": "The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`." + }, + "NotConfigured": { + "code": "disabled", + "description": "The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants." + }, + "NotEnoughAlphaOutToRecycle": { + "code": "insufficient_liquidity", + "description": "A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount." + }, + "NotEnoughBalanceToPaySwapColdKey": { + "code": "insufficient_balance", + "description": "The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap." + }, + "NotEnoughBalanceToPaySwapHotKey": { + "code": "insufficient_balance", + "description": "The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying." + }, + "NotEnoughBalanceToStake": { + "code": "insufficient_balance", + "description": "The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid)." + }, + "NotEnoughStake": { + "code": "insufficient_balance", + "description": "The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs." + }, + "NotEnoughStakeToSetChildkeys": { + "code": "insufficient_balance", + "description": "Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value." + }, + "NotEnoughStakeToSetWeights": { + "code": "insufficient_balance", + "description": "Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`." + }, + "NotEnoughStakeToWithdraw": { + "code": "insufficient_balance", + "description": "An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage)." + }, + "NotFound": { + "code": "not_found", + "description": "The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state." + }, + "NotNoted": { + "code": "not_found", + "description": "The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored." + }, + "NotOwner": { + "code": "not_authorized", + "description": "Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash." + }, + "NotPermittedOnRootSubnet": { + "code": "invalid_argument", + "description": "An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0." + }, + "NotProxy": { + "code": "not_authorized", + "description": "The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call." + }, + "NotReadyToDissolve": { + "code": "too_early", + "description": "`dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record." + }, + "NotRequested": { + "code": "not_found", + "description": "The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`." + }, + "NotRootSubnet": { + "code": "invalid_argument", + "description": "A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0." + }, + "NotSubnetOwner": { + "code": "not_authorized", + "description": "The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`)." + }, + "NothingAuthorized": { + "code": "not_found", + "description": "No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code." + }, + "OrderAlreadyProcessed": { + "code": "already_exists", + "description": "The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`." + }, + "OrderCancelled": { + "code": "expired", + "description": "The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order." + }, + "OrderExpired": { + "code": "expired", + "description": "The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value." + }, + "OrderNetUidMismatch": { + "code": "invalid_argument", + "description": "An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out." + }, + "OutOfBounds": { + "code": "invalid_argument", + "description": "A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug." + }, + "OutOfGas": { + "code": "limit_exceeded", + "description": "The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight." + }, + "OutOfTransientStorage": { + "code": "limit_exceeded", + "description": "A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit." + }, + "OutputBufferTooSmall": { + "code": "invalid_argument", + "description": "The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug." + }, + "Overflow": { + "code": "internal", + "description": "A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values." + }, + "POWRegistrationDisabled": { + "code": "disabled", + "description": "`sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled." + }, + "PalletHotkeyNotRegistered": { + "code": "not_registered", + "description": "Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs." + }, + "PartialFillsNotEnabled": { + "code": "disabled", + "description": "A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing." + }, + "PauseFailed": { + "code": "invalid_argument", + "description": "A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause." + }, + "PaymentOverflow": { + "code": "internal", + "description": "Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction." + }, + "PreLogExists": { + "code": "invalid_argument", + "description": "An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it." + }, + "PriceConditionNotMet": { + "code": "too_early", + "description": "The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field." + }, + "PriceLimitExceeded": { + "code": "insufficient_liquidity", + "description": "The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting." + }, + "ProportionOverflow": { + "code": "invalid_argument", + "description": "The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX." + }, + "PulseVerificationError": { + "code": "invalid_argument", + "description": "BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key)." + }, + "RandomSubjectTooLong": { + "code": "limit_exceeded", + "description": "The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section." + }, + "ReentranceDenied": { + "code": "invalid_argument", + "description": "A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag." + }, + "Reentrancy": { + "code": "internal", + "description": "EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call." + }, + "RegistrationNotPermittedOnRootSubnet": { + "code": "invalid_argument", + "description": "A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership." + }, + "RegistrationPriceLimitExceeded": { + "code": "limit_exceeded", + "description": "`burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay." + }, + "RelayerMissMatch": { + "code": "invalid_argument", + "description": "The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload." + }, + "RelayerRequiredForPartialFill": { + "code": "invalid_argument", + "description": "A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount." + }, + "Requested": { + "code": "invalid_argument", + "description": "The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed." + }, + "RequireSudo": { + "code": "not_authorized", + "description": "The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item." + }, + "RescheduleNoChange": { + "code": "invalid_argument", + "description": "The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block." + }, + "ReservesOutOfBalance": { + "code": "insufficient_liquidity", + "description": "Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry." + }, + "ReservesTooLow": { + "code": "insufficient_liquidity", + "description": "The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size." + }, + "ResumeFailed": { + "code": "invalid_argument", + "description": "A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume." + }, + "RevealPeriodTooLarge": { + "code": "invalid_argument", + "description": "`set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid." + }, + "RevealPeriodTooSmall": { + "code": "invalid_argument", + "description": "`set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid." + }, + "RevealTooEarly": { + "code": "too_early", + "description": "A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch." + }, + "RootNetUidNotAllowed": { + "code": "invalid_argument", + "description": "The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet." + }, + "RootNetworkDoesNotExist": { + "code": "subnet_not_exists", + "description": "Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`." + }, + "SameAutoStakeHotkeyAlreadySet": { + "code": "already_exists", + "description": "The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted." + }, + "SameNetuid": { + "code": "invalid_argument", + "description": "A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ." + }, + "SenderInSignatories": { + "code": "invalid_argument", + "description": "The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting." + }, + "ServingRateLimitExceeded": { + "code": "rate_limited", + "description": "`serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait." + }, + "SettingWeightsTooFast": { + "code": "rate_limited", + "description": "The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks." + }, + "SignatoriesOutOfOrder": { + "code": "invalid_argument", + "description": "The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting." + }, + "SlippageTooHigh": { + "code": "insufficient_liquidity", + "description": "A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution." + }, + "SpaceLimitExceeded": { + "code": "rate_limited", + "description": "The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage." + }, + "SpecVersionNeedsToIncrease": { + "code": "invalid_argument", + "description": "The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain." + }, + "StakeTooLowForRoot": { + "code": "insufficient_balance", + "description": "`root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`)." + }, + "StakeUnavailable": { + "code": "insufficient_balance", + "description": "An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked." + }, + "StakingRateLimitExceeded": { + "code": "rate_limited", + "description": "Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block." + }, + "StartCallNotReady": { + "code": "too_early", + "description": "`start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder." + }, + "StateChangeDenied": { + "code": "not_authorized", + "description": "The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context." + }, + "StorageDepositLimitExhausted": { + "code": "limit_exceeded", + "description": "The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`." + }, + "StorageDepositNotEnoughFunds": { + "code": "insufficient_balance", + "description": "The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit." + }, + "StorageOverflow": { + "code": "internal", + "description": "Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit." + }, + "SubNetRegistrationDisabled": { + "code": "disabled", + "description": "Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid." + }, + "SubnetBuybackRateLimitExceeded": { + "code": "rate_limited", + "description": "A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback." + }, + "SubnetDoesNotExist": { + "code": "subnet_not_exists", + "description": "The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters." + }, + "SubnetLimitReached": { + "code": "limit_exceeded", + "description": "`register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable." + }, + "SubnetNotExists": { + "code": "subnet_not_exists", + "description": "The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved." + }, + "SubtokenDisabled": { + "code": "subtoken_disabled", + "description": "The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved." + }, + "SwapInputTooLarge": { + "code": "insufficient_liquidity", + "description": "The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed." + }, + "SwapReturnedZero": { + "code": "insufficient_liquidity", + "description": "The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit." + }, + "SymbolAlreadyInUse": { + "code": "already_exists", + "description": "The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken." + }, + "SymbolDoesNotExist": { + "code": "not_found", + "description": "The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry." + }, + "TargetBlockNumberInPast": { + "code": "invalid_argument", + "description": "The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block." + }, + "TempoOutOfBounds": { + "code": "invalid_argument", + "description": "`set_tempo` was given a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range. Check the tempo argument against those chain constants and pick a value inside the bounds." + }, + "TerminatedInConstructor": { + "code": "internal", + "description": "The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls." + }, + "TerminatedWhileReentrant": { + "code": "invalid_argument", + "description": "`seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated." + }, + "TooBig": { + "code": "limit_exceeded", + "description": "The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it." + }, + "TooFew": { + "code": "invalid_argument", + "description": "The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`." + }, + "TooFewSignatories": { + "code": "invalid_argument", + "description": "The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using." + }, + "TooMany": { + "code": "limit_exceeded", + "description": "A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`." + }, + "TooManyCalls": { + "code": "limit_exceeded", + "description": "The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions." + }, + "TooManyChildren": { + "code": "limit_exceeded", + "description": "`set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries." + }, + "TooManyFieldsInCommitmentInfo": { + "code": "limit_exceeded", + "description": "The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit." + }, + "TooManyFreezes": { + "code": "limit_exceeded", + "description": "The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first." + }, + "TooManyHolds": { + "code": "limit_exceeded", + "description": "The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another." + }, + "TooManyPendingExtrinsics": { + "code": "limit_exceeded", + "description": "`store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire." + }, + "TooManyRegistrationsThisBlock": { + "code": "rate_limited", + "description": "Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block." + }, + "TooManyRegistrationsThisInterval": { + "code": "rate_limited", + "description": "Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start." + }, + "TooManyReserves": { + "code": "limit_exceeded", + "description": "The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another." + }, + "TooManySignatories": { + "code": "limit_exceeded", + "description": "The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant." + }, + "TooManyTopics": { + "code": "limit_exceeded", + "description": "The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit." + }, + "TooManyUIDsPerMechanism": { + "code": "limit_exceeded", + "description": "Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit." + }, + "TooManyUnrevealedCommits": { + "code": "limit_exceeded", + "description": "`commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again." + }, + "TooSoon": { + "code": "rate_limited", + "description": "A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change." + }, + "TransactionMustComeFromEOA": { + "code": "not_authorized", + "description": "Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead." + }, + "TransactorAccountShouldBeHotKey": { + "code": "not_authorized", + "description": "The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin." + }, + "TransferDisallowed": { + "code": "disabled", + "description": "A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first." + }, + "TransferFailed": { + "code": "insufficient_balance", + "description": "A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit." + }, + "TrimmingWouldExceedMaxImmunePercentage": { + "code": "limit_exceeded", + "description": "Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target." + }, + "TxChildkeyTakeRateLimitExceeded": { + "code": "rate_limited", + "description": "`set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder." + }, + "TxRateLimitExceeded": { + "code": "rate_limited", + "description": "An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass." + }, + "UidMapCouldNotBeCleared": { + "code": "internal", + "description": "During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it." + }, + "UidVecContainInvalidOne": { + "code": "invalid_argument", + "description": "The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`)." + }, + "UidsLengthExceedUidsInSubNet": { + "code": "limit_exceeded", + "description": "The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector." + }, + "UnableToRecoverPublicKey": { + "code": "invalid_argument", + "description": "While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key." + }, + "Unannounced": { + "code": "too_early", + "description": "The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`." + }, + "Unauthorized": { + "code": "not_authorized", + "description": "In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`." + }, + "Undefined": { + "code": "internal", + "description": "Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs." + }, + "Underflow": { + "code": "internal", + "description": "A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`." + }, + "UnexpectedTimepoint": { + "code": "invalid_argument", + "description": "A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry." + }, + "UnexpectedUnreserveLeftover": { + "code": "internal", + "description": "While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`." + }, + "UnlockAmountTooHigh": { + "code": "insufficient_balance", + "description": "An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount." + }, + "Unproxyable": { + "code": "not_authorized", + "description": "The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call." + }, + "Unreachable": { + "code": "internal", + "description": "`announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring." + }, + "UnverifiedPulse": { + "code": "invalid_argument", + "description": "Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`." + }, + "ValueNotInBounds": { + "code": "invalid_argument", + "description": "An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds." + }, + "ValueTooLarge": { + "code": "limit_exceeded", + "description": "A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant." + }, + "VestingBalance": { + "code": "insufficient_balance", + "description": "The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs." + }, + "VotingPowerTrackingNotEnabled": { + "code": "disabled", + "description": "Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic." + }, + "WaitingForDissolvedSubnetCleanup": { + "code": "too_early", + "description": "The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes." + }, + "WeightExceedsAbsoluteMax": { + "code": "limit_exceeded", + "description": "`set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant." + }, + "WeightVecLengthIsLow": { + "code": "invalid_argument", + "description": "The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid." + }, + "WeightVecNotEqualSize": { + "code": "invalid_argument", + "description": "The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID." + }, + "WithdrawFailed": { + "code": "insufficient_balance", + "description": "Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance." + }, + "WrongTimepoint": { + "code": "invalid_argument", + "description": "The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint." + }, + "XCMDecodeFailed": { + "code": "invalid_argument", + "description": "The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports." + }, + "ZeroBalanceAfterWithdrawn": { + "code": "insufficient_balance", + "description": "Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn." + }, + "ZeroShareInBatch": { + "code": "invalid_argument", + "description": "An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch." + } } } diff --git a/website/apps/bittensor-website/scripts/generate.py b/website/apps/bittensor-website/scripts/generate.py index 3b01bcc175..465a286161 100644 --- a/website/apps/bittensor-website/scripts/generate.py +++ b/website/apps/bittensor-website/scripts/generate.py @@ -24,7 +24,7 @@ from dataclasses import MISSING, fields from pathlib import Path -from bittensor import error_map, result +from bittensor import error_descriptions, error_map, result from bittensor.intents import REGISTRY as INTENTS from bittensor.intents.registry import list_tools from bittensor.namespaces import NAMESPACES @@ -466,12 +466,14 @@ def errors_page() -> str: parts.append("## Chain error classification\n") parts.append( - "The exact chain error name (from the extrinsic receipt) maps to a code:\n" + "The exact chain error name (from the extrinsic receipt) maps to a code; " + "the description says what triggered it and where to check:\n" ) - parts.append("| Chain error | Code |") - parts.append("| --- | --- |") + parts.append("| Chain error | Code | Description |") + parts.append("| --- | --- | --- |") for name, code in sorted(error_map.NAME_TO_CODE.items()): - parts.append(f"| `{name}` | `{code.value}` |") + description = error_descriptions.DESCRIPTIONS[name] + parts.append(f"| `{name}` | `{code.value}` | {cell(description)} |") parts.append("") return "\n".join(parts) @@ -504,7 +506,10 @@ def write_catalogs(catalog_root: Path) -> None: r["python"] = f"client.{namespace_attr(spec)}.{spec.name}(...)" errors = { "codes": {code.value: result.REMEDIATION[code] for code in error_map.ErrorCode}, - "chain_errors": {n: c.value for n, c in sorted(error_map.NAME_TO_CODE.items())}, + "chain_errors": { + n: {"code": c.value, "description": error_descriptions.DESCRIPTIONS[n]} + for n, c in sorted(error_map.NAME_TO_CODE.items()) + }, } (catalog_root / "intents.json").write_text(json.dumps(tools, indent=2) + "\n") (catalog_root / "reads.json").write_text(json.dumps(reads, indent=2) + "\n") From 3e4f4bc72410c8b6e410ab4df48428f0d338c25c Mon Sep 17 00:00:00 2001 From: unarbos Date: Mon, 13 Jul 2026 15:34:31 -0600 Subject: [PATCH 02/43] restore PEP 740 provenance attestations on PyPI releases The move from gh-action-pypi-publish to uv publish silently dropped attestation generation: uv only uploads attestations that already exist in dist/. Generate them with astral-sh/attest-action in each publish job (stable, rc, and dev channels) so releases are provenance-signed again. Co-authored-by: Cursor --- .github/workflows/publish-sdk-dev.yml | 6 ++++++ .github/workflows/release-train.yml | 6 ++++++ .github/workflows/watch-mainnet-release.yml | 8 ++++++++ docs/internals/release-process.mdx | 3 ++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-sdk-dev.yml b/.github/workflows/publish-sdk-dev.yml index 81a339000e..53bfec9322 100644 --- a/.github/workflows/publish-sdk-dev.yml +++ b/.github/workflows/publish-sdk-dev.yml @@ -53,6 +53,12 @@ jobs: working-directory: sdk/python run: uv build --out-dir ../../dist + # PEP 740 provenance, same as the rc/stable publish jobs. Running it on + # the dev channel means a broken attestation step fails here on every + # push to main instead of for the first time during a release. + - name: Generate PEP 740 attestations + uses: astral-sh/attest-action@f589a42a7efb6fe400b4f400de60b4bc90390027 # v0.0.6 + - name: Publish to TestPyPI run: | uv publish --trusted-publishing always \ diff --git a/.github/workflows/release-train.yml b/.github/workflows/release-train.yml index 95d69bd113..ce9885b7a2 100644 --- a/.github/workflows/release-train.yml +++ b/.github/workflows/release-train.yml @@ -360,6 +360,12 @@ jobs: - name: Build SDK wheel and sdist working-directory: sdk/python run: uv build --out-dir ../../dist + # PEP 740 provenance: sign every dist with this job's OIDC identity + # (must match the trusted publisher, so it runs here rather than in + # build-core-wheels.yml). uv publish uploads the resulting + # *.publish.attestation files alongside each dist. + - name: Generate PEP 740 attestations + uses: astral-sh/attest-action@f589a42a7efb6fe400b4f400de60b4bc90390027 # v0.0.6 # --check-url makes a re-run after a partial upload idempotent: files # already on the index are skipped instead of failing with a 400 # duplicate (e.g. the SDK wheel landed but bittensor-core didn't). diff --git a/.github/workflows/watch-mainnet-release.yml b/.github/workflows/watch-mainnet-release.yml index 22f8bac488..3ee09e50a9 100644 --- a/.github/workflows/watch-mainnet-release.yml +++ b/.github/workflows/watch-mainnet-release.yml @@ -254,6 +254,14 @@ jobs: working-directory: sdk/python run: uv build --out-dir ../../dist + # PEP 740 provenance: sign every dist with this job's OIDC identity. + # Must happen here, not in build-core-wheels.yml — PyPI only accepts + # attestations whose Sigstore identity matches the trusted publisher + # doing the upload. uv publish picks up the *.publish.attestation + # files from dist/ automatically. + - name: Generate PEP 740 attestations + uses: astral-sh/attest-action@f589a42a7efb6fe400b4f400de60b4bc90390027 # v0.0.6 + # --check-url makes a re-run after a partial upload idempotent: files # already on the index are skipped instead of failing with a 400 # duplicate (e.g. the SDK wheel landed but bittensor-core didn't). diff --git a/docs/internals/release-process.mdx b/docs/internals/release-process.mdx index f9b889f8e2..a6648ba1a5 100644 --- a/docs/internals/release-process.mdx +++ b/docs/internals/release-process.mdx @@ -74,7 +74,8 @@ running your runtime with a public endpoint yet, it cuts the release train's artifacts: 1. **GitHub release** `v` -2. **Python SDK + bittensor-core wheels** to PyPI (trusted publishing) +2. **Python SDK + bittensor-core wheels** to PyPI (trusted publishing, with + PEP 740 provenance attestations) 3. **Publishable Rust crates** to crates.io (auto-discovered; workspace crates are `publish = false` while they depend on the patched polkadot-sdk fork) 4. **Production website/docs** to Vercel From d316a4532dbcc76e0f763f2a089276f08eee424c Mon Sep 17 00:00:00 2001 From: unarbos Date: Mon, 13 Jul 2026 16:32:40 -0600 Subject: [PATCH 03/43] expose every owner-settable hyperparameter and describe each in the listing Co-authored-by: Cursor --- docs/tx/set-hyperparameter.mdx | 14 ++- sdk/python/bittensor/cli/commands/subnets.py | 4 +- sdk/python/bittensor/cli/commands/sudo.py | 6 +- sdk/python/bittensor/cli/hyperparams_view.py | 34 +++++- sdk/python/bittensor/cli/output.py | 36 ++++-- sdk/python/bittensor/hyperparams.py | 103 +++++++++++++++++- .../bittensor/intents/hyperparameters.py | 49 +++++++-- sdk/python/bittensor/settings.py | 4 + sdk/python/codegen/check.py | 19 ++-- .../public/catalog/intents.json | 4 +- 10 files changed, 226 insertions(+), 47 deletions(-) diff --git a/docs/tx/set-hyperparameter.mdx b/docs/tx/set-hyperparameter.mdx index c5eb742fe2..869ed4962c 100644 --- a/docs/tx/set-hyperparameter.mdx +++ b/docs/tx/set-hyperparameter.mdx @@ -6,10 +6,12 @@ description: "Set an owner-settable subnet hyperparameter (btcli `sudo set`)." {/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} Dispatches the matching AdminUtils `sudo_set_*` call for the named -parameter. The signer must be the subnet's owner coldkey; root-only -parameters are not available here and must go through the raw-call escape -hatch. Changes take effect on chain immediately and shape subnet economics -and consensus (registration costs, weight rules, immunity, transfers), so +parameter (`alpha_low`/`alpha_high` read the current pair from chain and +set both via `sudo_set_alpha_values`). The signer must be the subnet's +owner coldkey; root-only parameters are not available here and must go +through the raw-call escape hatch. Changes take effect on chain immediately +and shape subnet economics and consensus (registration costs, weight +rules, immunity, transfers), so verify the raw value before sending — `value` accepts either the raw on-chain integer or a human form that is converted for you. Some parameters are rate-limited by the chain, so a quick follow-up change can @@ -17,14 +19,14 @@ fail. Read current values back with the `subnet_hyperparameters` read. | Signer | Pallet | Wraps | | --- | --- | --- | -| `coldkey` | AdminUtils | `AdminUtils.sudo_set_immunity_period`, `AdminUtils.sudo_set_min_allowed_weights`, `AdminUtils.sudo_set_weights_version_key`, `AdminUtils.sudo_set_activity_cutoff`, `AdminUtils.sudo_set_min_burn`, `AdminUtils.sudo_set_bonds_moving_average`, `AdminUtils.sudo_set_serving_rate_limit`, `AdminUtils.sudo_set_commit_reveal_weights_interval`, `AdminUtils.sudo_set_max_allowed_uids`, `AdminUtils.sudo_set_burn_increase_mult`, `AdminUtils.sudo_set_burn_half_life`, `AdminUtils.sudo_set_commit_reveal_weights_enabled`, `AdminUtils.sudo_set_liquid_alpha_enabled`, `AdminUtils.sudo_set_network_pow_registration_allowed`, `AdminUtils.sudo_set_yuma3_enabled`, `AdminUtils.sudo_set_bonds_reset_enabled`, `AdminUtils.sudo_set_toggle_transfer`, `AdminUtils.sudo_set_owner_cut_enabled`, `AdminUtils.sudo_set_owner_cut_auto_lock_enabled` | +| `coldkey` | AdminUtils | `AdminUtils.sudo_set_immunity_period`, `AdminUtils.sudo_set_min_allowed_weights`, `AdminUtils.sudo_set_weights_version_key`, `AdminUtils.sudo_set_activity_cutoff`, `AdminUtils.sudo_set_min_burn`, `AdminUtils.sudo_set_max_burn`, `AdminUtils.sudo_set_bonds_moving_average`, `AdminUtils.sudo_set_bonds_penalty`, `AdminUtils.sudo_set_serving_rate_limit`, `AdminUtils.sudo_set_commit_reveal_weights_interval`, `AdminUtils.sudo_set_max_allowed_uids`, `AdminUtils.sudo_set_burn_increase_mult`, `AdminUtils.sudo_set_burn_half_life`, `AdminUtils.sudo_set_adjustment_alpha`, `AdminUtils.sudo_set_rho`, `AdminUtils.sudo_set_max_difficulty`, `AdminUtils.sudo_set_alpha_sigmoid_steepness`, `AdminUtils.sudo_set_min_childkey_take_per_subnet`, `AdminUtils.sudo_set_owner_immune_neuron_limit`, `AdminUtils.sudo_set_alpha_values`, `AdminUtils.sudo_set_commit_reveal_weights_enabled`, `AdminUtils.sudo_set_liquid_alpha_enabled`, `AdminUtils.sudo_set_network_pow_registration_allowed`, `AdminUtils.sudo_set_yuma3_enabled`, `AdminUtils.sudo_set_bonds_reset_enabled`, `AdminUtils.sudo_set_toggle_transfer`, `AdminUtils.sudo_set_owner_cut_enabled`, `AdminUtils.sudo_set_owner_cut_auto_lock_enabled` | ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `netuid` | integer | yes | Subnet to configure; the signer must be its owner. | -| `name` | string | yes | Hyperparameter to set. One of: activity_cutoff, bonds_moving_avg, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, min_allowed_weights, min_burn, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, serving_rate_limit, transfers_enabled, weights_version, yuma3_enabled. | +| `name` | string | yes | Hyperparameter to set. One of: activity_cutoff, adjustment_alpha, alpha_high, alpha_low, alpha_sigmoid_steepness, bonds_moving_avg, bonds_penalty, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, max_burn, max_difficulty, min_allowed_weights, min_burn, min_childkey_take, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, owner_immune_neuron_limit, rho, serving_rate_limit, transfers_enabled, weights_version, yuma3_enabled. | | `value` | integer \| number \| string | yes | New value. Give the raw on-chain integer, or the human form as a float or a string with a decimal point (a 0..1 fraction for normalized parameters, a TAO amount for rao parameters). Boolean parameters take true/false or 0/1. | Address parameters (`--hotkey`, `--coldkey`, `--dest`, ...) accept a raw ss58 diff --git a/sdk/python/bittensor/cli/commands/subnets.py b/sdk/python/bittensor/cli/commands/subnets.py index 8eb0f06067..b682bfbd6b 100644 --- a/sdk/python/bittensor/cli/commands/subnets.py +++ b/sdk/python/bittensor/cli/commands/subnets.py @@ -15,7 +15,7 @@ from ..context import AppContext, address_cli_name, ctx_of, ss58_param_help from ..globals import with_globals, with_tx_globals from ..helpers import chain_identity_names, local_address_names -from ..hyperparams_view import show_hyperparameters +from ..hyperparams_view import fetch_hyperparameters, show_hyperparameters from ..metagraph_view import show_metagraph app = typer.Typer(no_args_is_help=True, help="Inspect subnets.") @@ -120,7 +120,7 @@ def hyperparameters( ): """Show subnet hyperparameters.""" app_ctx: AppContext = ctx_of(ctx) - params = app_ctx.run(lambda c: c.read("subnet_hyperparameters", netuid=netuid)) + params = app_ctx.run(lambda c: fetch_hyperparameters(c, netuid)) show_hyperparameters(app_ctx, netuid, params, name) diff --git a/sdk/python/bittensor/cli/commands/sudo.py b/sdk/python/bittensor/cli/commands/sudo.py index 476c5b7ea7..1531cd54e7 100644 --- a/sdk/python/bittensor/cli/commands/sudo.py +++ b/sdk/python/bittensor/cli/commands/sudo.py @@ -23,7 +23,7 @@ from ...settings import U16_MAX from ..context import AppContext, address_cli_name, ctx_of, ss58_param_help from ..globals import with_globals, with_tx_globals -from ..hyperparams_view import show_hyperparameters +from ..hyperparams_view import fetch_hyperparameters, show_hyperparameters from ..prompt import PromptSpec, fill_missing, interactive from ..tx import _parse_money @@ -61,7 +61,7 @@ def _prompt_set_args( specs: list[PromptSpec] = [] if name is None: if interactive(app_ctx): - params = app_ctx.run(lambda c: c.read("subnet_hyperparameters", netuid=netuid)) + params = app_ctx.run(lambda c: fetch_hyperparameters(c, netuid)) show_hyperparameters( app_ctx, netuid, @@ -139,7 +139,7 @@ def sudo_get( ): """Show subnet hyperparameters.""" app_ctx: AppContext = ctx_of(ctx) - params = app_ctx.run(lambda c: c.read("subnet_hyperparameters", netuid=netuid)) + params = app_ctx.run(lambda c: fetch_hyperparameters(c, netuid)) show_hyperparameters(app_ctx, netuid, params, name) diff --git a/sdk/python/bittensor/cli/hyperparams_view.py b/sdk/python/bittensor/cli/hyperparams_view.py index 7ca3f07575..d66c3e80c5 100644 --- a/sdk/python/bittensor/cli/hyperparams_view.py +++ b/sdk/python/bittensor/cli/hyperparams_view.py @@ -9,14 +9,39 @@ from __future__ import annotations +import asyncio from typing import Any, Optional import typer from .. import hyperparams as hp from ..intents.hyperparameters import OWNER_HYPERPARAMETERS +from ..settings import DOCS_URL from .context import AppContext +HYPERPARAMS_DOCS_URL = f"{DOCS_URL}/hyperparameters" + + +async def fetch_hyperparameters(client, netuid: int) -> dict[str, Any]: + """The ``subnet_hyperparameters`` read plus the owner-settable values it + omits (queried from their storage items), so the listing shows everything + ``sudo set`` can change.""" + params = await client.read("subnet_hyperparameters", netuid=netuid) + extras = sorted( + name for name in OWNER_HYPERPARAMETERS if name not in params and name in hp.STORAGE_ITEMS + ) + values = await asyncio.gather( + *(client.query(hp.STORAGE_ITEMS[name], [netuid]) for name in extras) + ) + for name, value in zip(extras, values): + if isinstance(value, dict) and set(value) == {"bits"}: + # Fixed-point newtypes (U64F64) decode as {'bits': raw}; the raw + # bits are the value `sudo set` takes and `annotate` reads. + value = value["bits"] + if value is not None: + params[name] = value + return params + def show_hyperparameters( app_ctx: AppContext, @@ -45,13 +70,17 @@ def show_hyperparameters( def _listing( app_ctx: AppContext, netuid: int, params: dict[str, Any], hint: Optional[str] = None ) -> None: - rows = [(key, str(value), hp.annotate(key, value)) for key, value in params.items()] + rows = [ + (key, str(value), hp.annotate(key, value), hp.short_of(key)) + for key, value in params.items() + ] example = "kappa" if "kappa" in params else next(iter(params), "tempo") app_ctx.output.hyperparameters( f"hyperparameters netuid {netuid}", rows, params, hint=hint or f"`--name {example}` explains one parameter and how to set it", + docs=HYPERPARAMS_DOCS_URL, ) @@ -91,6 +120,7 @@ def _single(app_ctx: AppContext, netuid: int, name: str, raw: Any) -> None: }, help=help_text, note=note, + see=f"{HYPERPARAMS_DOCS_URL}/{name.replace('_', '-')}", ) @@ -100,6 +130,8 @@ def _example_value(kind: str, fraction: Optional[float], raw: Any) -> str: return _with_decimal_point(f"{fraction:.4g}") if kind == "rao" and isinstance(raw, int): return _with_decimal_point(f"{raw / hp.RAO_PER_TAO:g}") + if kind == "fixed128" and isinstance(raw, int): + return _with_decimal_point(f"{raw / hp.FIXED128_ONE:g}") if kind == "bool": return "true" if raw else "false" return str(raw) diff --git a/sdk/python/bittensor/cli/output.py b/sdk/python/bittensor/cli/output.py index a00530d5d3..49f8b1dc15 100644 --- a/sdk/python/bittensor/cli/output.py +++ b/sdk/python/bittensor/cli/output.py @@ -448,12 +448,16 @@ def _print_fields(self, fields: dict[str, Any]) -> None: def hyperparameters( self, title: str, - rows: list[tuple[str, str, Optional[str]]], + rows: list[tuple[str, str, Optional[str], Optional[str]]], json_fields: dict[str, Any], hint: Optional[str] = None, + docs: Optional[str] = None, ) -> None: - """Aligned hyperparameter listing: raw value plus its dim human reading - (``kappa 32767 ≈ 0.5``). JSON carries the raw record untouched.""" + """Aligned hyperparameter listing: raw value, its dim human reading, and + a one-line description (``kappa 32767 ≈ 0.5 consensus majority-stake + threshold``). ``docs`` links each name (OSC-8) to its explainer page + under that URL and prints as a ``see:`` footer. JSON carries the raw + record untouched.""" if self.json_mode: self._json(json_fields) return @@ -461,19 +465,28 @@ def hyperparameters( if not rows: self._out.print(" [dim]none[/dim]") return - name_width = max(len(name) for name, _, _ in rows) - value_width = max(len(value) for _, value, _ in rows) - for name, value, note in rows: + name_width = max(len(name) for name, _, _, _ in rows) + value_width = max(len(value) for _, value, _, _ in rows) + note_width = max((len(note) for _, _, note, _ in rows if note), default=0) + for name, value, note, short in rows: line = Text(" ", overflow="ignore", no_wrap=True) - line.append(name.rjust(name_width), style=STYLE_KEY) + name_style = f"{STYLE_KEY} link {docs}/{name.replace('_', '-')}" if docs else STYLE_KEY + line.append(name.rjust(name_width), style=name_style) line.append(" ") line.append(value.rjust(value_width)) - if note: + if short: + # The reading column is padded so descriptions align. + line.append(f" {(note or '').ljust(note_width)}", style=STYLE_HINT) + line.append(f" {short}", style=STYLE_INCIDENTAL) + elif note: line.append(f" {note}", style=STYLE_HINT) self._out.print(line, soft_wrap=True) - if hint: + if hint or docs: self._out.print() + if hint: self._sub_diag("help", hint, console=self._out) + if docs: + self._sub_diag("see", docs, console=self._out) def hyperparameter( self, @@ -484,6 +497,7 @@ def hyperparameter( *, help: Optional[str] = None, note: Optional[str] = None, + see: Optional[str] = None, ) -> None: """One hyperparameter in full: value fields, the explanation paragraph, and the how-to-set diagnostics.""" @@ -495,12 +509,14 @@ def hyperparameter( if doc: self._out.print() self._out.print(Padding(_prose(doc), (0, 0, 0, 2))) - if help or note: + if help or note or see: self._out.print() if help: self._sub_diag("help", help, console=self._out) if note: self._sub_diag("note", note, console=self._out) + if see: + self._sub_diag("see", see, console=self._out) def table( self, diff --git a/sdk/python/bittensor/hyperparams.py b/sdk/python/bittensor/hyperparams.py index 7339b85654..71253db6f1 100644 --- a/sdk/python/bittensor/hyperparams.py +++ b/sdk/python/bittensor/hyperparams.py @@ -60,18 +60,39 @@ def ratio_fraction(type_ident: Optional[str], raw: int) -> Optional[float]: # blocks block count (12s blocks; annotated with wall-clock time) # epochs tempo count # difficulty raw u64 PoW difficulty (u64::MAX = effectively disabled) +# fixed128 U64F64 fixed-point multiplier (bits / 2^64 = the real value) # int plain integer # bool flag -KINDS = ("u16", "u64", "per_million", "rao", "blocks", "epochs", "difficulty", "int", "bool") +KINDS = ( + "u16", + "u64", + "per_million", + "rao", + "blocks", + "epochs", + "difficulty", + "fixed128", + "int", + "bool", +) + +# Scale of the U64F64 fixed-point kind (bits value / 2^64 = the real number). +FIXED128_ONE = 2**64 # Denominator for each fraction kind (raw / denominator = normalized 0..1). _FRACTION_DENOMINATOR = {"u16": U16_MAX, "u64": U64_MAX, "per_million": PER_MILLION} +# Ceiling for `Hyperparam.short`, so the listing's description column stays +# one glanceable line (enforced by `codegen.check --units`). +SHORT_MAX = 38 + + @dataclass(frozen=True) class Hyperparam: kind: str doc: str + short: str = "" HYPERPARAMS: dict[str, Hyperparam] = { @@ -79,161 +100,221 @@ class Hyperparam: "int", "Temperature of the sigmoid that maps a validator's consensus alignment to " "trust; higher values make the trust curve steeper.", + short="trust curve steepness", ), "kappa": Hyperparam( "u16", "Majority-stake threshold of Yuma consensus: the stake fraction at which a " "weight counts as consensus-supported. Stored as u16 (65535 = 1.0), so " "32767 means 0.5 — a simple stake majority.", + short="consensus majority-stake threshold", ), "immunity_period": Hyperparam( "blocks", "Blocks a newly registered neuron is immune from being pruned as the " "lowest-scoring UID when the subnet is full.", + short="prune-immunity window for new neurons", ), "min_allowed_weights": Hyperparam( "int", "Minimum number of distinct weights a validator must submit in one set_weights call.", + short="minimum weights per submission", ), "max_weights_limit": Hyperparam( "u16", "Cap on any single normalized weight a validator can assign to one miner. " "Stored as u16 (65535 = 1.0 — no cap).", + short="cap on a single miner's weight", ), "tempo": Hyperparam( "blocks", "Blocks per epoch: how often the subnet runs consensus and distributes emissions.", + short="blocks per consensus epoch", ), "min_difficulty": Hyperparam( "difficulty", "Lower bound for the PoW registration difficulty controller. u64::MAX " "pins difficulty at maximum, effectively disabling PoW registration.", + short="PoW registration difficulty floor", ), "max_difficulty": Hyperparam( "difficulty", "Upper bound for the PoW registration difficulty controller. u64::MAX " "leaves the difficulty unbounded above.", + short="PoW registration difficulty ceiling", ), "difficulty": Hyperparam( "difficulty", "Current PoW registration difficulty. u64::MAX means PoW registration is " "effectively disabled (burned registration only).", + short="current PoW registration difficulty", ), "weights_version": Hyperparam( "int", "Minimum version key validators must send with set_weights; raising it " "forces validators to upgrade before their weights are accepted.", + short="minimum version key for set_weights", ), "weights_rate_limit": Hyperparam( "blocks", "Minimum blocks a validator must wait between weight submissions.", + short="wait between weight submissions", ), "adjustment_interval": Hyperparam( "blocks", "Blocks between adjustments of the registration difficulty and burn cost.", + short="difficulty/burn adjustment cadence", ), "activity_cutoff": Hyperparam( "blocks", "Blocks without setting weights after which a validator is considered " "inactive and excluded from consensus.", + short="no-weights window before inactive", ), "registration_allowed": Hyperparam( "bool", "Whether new neuron registrations are currently accepted on this subnet.", + short="new neuron registrations allowed", ), "network_pow_registration_allowed": Hyperparam( "bool", "Whether proof-of-work registration is allowed (as opposed to burned registration only).", + short="PoW registration toggle", ), "target_regs_per_interval": Hyperparam( "int", "Registrations per adjustment interval the difficulty/burn controller steers toward.", + short="registration-rate controller target", ), "min_burn": Hyperparam( "rao", "Floor for the burned-registration cost, in rao (1 TAO = 1e9 rao).", + short="burned-registration cost floor", ), "max_burn": Hyperparam( "rao", "Ceiling for the burned-registration cost, in rao (1 TAO = 1e9 rao).", + short="burned-registration cost ceiling", ), "bonds_moving_avg": Hyperparam( "per_million", "Bonds EMA smoothing factor, stored over 1,000,000 (900000 = 0.9): higher " "retains more of a validator's past bonds each epoch.", + short="bonds EMA smoothing factor", ), "max_regs_per_block": Hyperparam( "int", "Maximum registrations accepted in a single block.", + short="per-block registration cap", ), "serving_rate_limit": Hyperparam( "blocks", "Minimum blocks between axon serve calls for one neuron.", + short="cooldown between axon serve calls", ), "max_validators": Hyperparam( "int", "Maximum validator permits: only the top-stake neurons up to this count may validate.", + short="top-stake validator permit cap", ), "adjustment_alpha": Hyperparam( "u64", "Smoothing factor for the difficulty/burn adjustment, stored as u64 " "(u64::MAX = 1.0): higher values adjust more slowly.", + short="difficulty/burn adjust smoothing", ), "commit_reveal_period": Hyperparam( "epochs", "Epochs (tempos) between committing a weights hash and revealing the actual weights.", + short="weight commit-to-reveal delay", ), "commit_reveal_weights_enabled": Hyperparam( "bool", "Whether validators must use commit-reveal for weights, hiding them from " "copiers until the reveal.", + short="commit-reveal weights toggle", ), "alpha_high": Hyperparam( "u16", "Upper bound of the liquid-alpha bonds smoothing range. Stored as u16 (65535 = 1.0).", + short="liquid-alpha smoothing upper bound", ), "alpha_low": Hyperparam( "u16", "Lower bound of the liquid-alpha bonds smoothing range. Stored as u16 (65535 = 1.0).", + short="liquid-alpha smoothing lower bound", ), "liquid_alpha_enabled": Hyperparam( "bool", "Whether liquid alpha is on: the bonds EMA factor then varies per-weight " "between alpha_low and alpha_high instead of using bonds_moving_avg.", + short="per-weight bonds EMA (liquid alpha)", + ), + "bonds_penalty": Hyperparam( + "u16", + "Penalty applied to bonds for out-of-consensus weights. Stored as u16 " + "(65535 = 1.0 — full penalty).", + short="penalty on out-of-consensus bonds", + ), + "alpha_sigmoid_steepness": Hyperparam( + "int", + "Steepness of the liquid-alpha sigmoid mapping consensus alignment to the " + "bonds EMA factor; negative values (root only) invert the curve.", + short="liquid-alpha sigmoid steepness", + ), + "min_childkey_take": Hyperparam( + "u16", + "Minimum childkey take allowed on this subnet. Stored as u16 (65535 = 1.0).", + short="floor for childkey take", + ), + "owner_immune_neuron_limit": Hyperparam( + "int", + "Number of subnet-owner-designated neurons that are immune from pruning.", + short="owner-designated prune-immune UIDs", ), # Owner-settable parameters that the hyperparameters read does not list. "max_allowed_uids": Hyperparam( "int", "Maximum neuron slots (UIDs) on the subnet; registrations beyond this " "prune the lowest-scoring neuron.", + short="neuron slot capacity before pruning", ), "burn_increase_mult": Hyperparam( - "int", - "Multiplier applied to the burn cost after each registration within an adjustment window.", + "fixed128", + "Multiplier applied to the burn cost after each registration within an " + "adjustment window. U64F64 fixed-point: the raw bits divided by 2^64 " + "give the real multiplier.", + short="burn cost bump per registration", ), "burn_half_life": Hyperparam( "blocks", "Blocks for the burn cost to decay halfway back toward min_burn.", + short="burn cost decay half-life", ), "yuma3_enabled": Hyperparam( "bool", "Whether the Yuma3 consensus variant is enabled for this subnet.", + short="yuma3 consensus variant toggle", ), "bonds_reset_enabled": Hyperparam( "bool", "Whether validator bonds are reset on certain subnet events.", + short="bonds reset on metadata commit", ), "transfers_enabled": Hyperparam( "bool", "Whether stake transfers between coldkeys are enabled on this subnet.", + short="stake transfers between coldkeys", ), "owner_cut_enabled": Hyperparam( "bool", "Whether the subnet owner takes their emission cut.", + short="owner emission cut toggle", ), "owner_cut_auto_lock_enabled": Hyperparam( "bool", "Whether the owner's emission cut is automatically locked.", + short="auto-lock the owner's emission cut", ), } @@ -270,6 +351,10 @@ class Hyperparam: "commit_reveal_period": st.SubtensorModule.RevealPeriodEpochs, "commit_reveal_weights_enabled": st.SubtensorModule.CommitRevealWeightsEnabled, "liquid_alpha_enabled": st.SubtensorModule.LiquidAlphaOn, + "bonds_penalty": st.SubtensorModule.BondsPenalty, + "alpha_sigmoid_steepness": st.SubtensorModule.AlphaSigmoidSteepness, + "min_childkey_take": st.SubtensorModule.MinChildkeyTakePerSubnet, + "owner_immune_neuron_limit": st.SubtensorModule.ImmuneOwnerUidsLimit, "max_allowed_uids": st.SubtensorModule.MaxAllowedUids, "burn_increase_mult": st.SubtensorModule.BurnIncreaseMult, "burn_half_life": st.SubtensorModule.BurnHalfLife, @@ -324,6 +409,12 @@ def doc_of(name: str) -> Optional[str]: return meta.doc if meta else None +def short_of(name: str) -> Optional[str]: + """The one-line blurb shown next to a value in the listing, or None.""" + meta = HYPERPARAMS.get(name) + return meta.short or None if meta else None + + def normalized(name: str, raw: int) -> Optional[float]: """The 0..1 fraction a raw fixed-point value encodes, or None for other kinds.""" denominator = _FRACTION_DENOMINATOR.get(kind_of(name)) @@ -363,6 +454,8 @@ def annotate(name: str, raw) -> Optional[str]: return f"≈ {duration}" if duration else None if kind == "difficulty" and raw == U64_MAX: return "= u64::MAX" + if kind == "fixed128": + return f"≈ {raw / FIXED128_ONE:.4g}" return None @@ -374,6 +467,8 @@ def value_forms(name: str) -> str: return f"a 0..1 fraction (e.g. 0.5) or the raw integer (0..{denominator})" if kind == "rao": return "a TAO amount with a decimal point (e.g. 0.7) or the raw rao integer" + if kind == "fixed128": + return "a multiplier with a decimal point (e.g. 1.5) or the raw U64F64 bits" if kind == "bool": return "true/false (or 1/0)" if kind == "blocks": @@ -465,6 +560,8 @@ def to_raw(name: str, value: Union[int, float, str, bool]) -> int: return round(value * denominator) if kind == "rao": return round(value * RAO_PER_TAO) + if kind == "fixed128": + return round(value * FIXED128_ONE) if value.is_integer(): return int(value) raise ValueError(f"{name} takes {value_forms(name)}; got {value!r}") diff --git a/sdk/python/bittensor/intents/hyperparameters.py b/sdk/python/bittensor/intents/hyperparameters.py index 7436c41076..59d0bce79e 100644 --- a/sdk/python/bittensor/intents/hyperparameters.py +++ b/sdk/python/bittensor/intents/hyperparameters.py @@ -3,9 +3,10 @@ The AdminUtils pallet's ``sudo_set_*`` calls are mostly root-only, but a subset is settable by the subnet owner for their own subnet. This exposes exactly that owner-settable subset through one ``SetHyperparameter`` intent, keyed by a stable -name (the same names btcli uses). Root-only params, the enum-valued -``recycle_or_burn``, multi-value ``alpha_values``, and ``sn_owner_hotkey`` are left -to the raw-call escape hatch. +name (the same names btcli uses). ``alpha_low`` and ``alpha_high`` share the +two-value ``sudo_set_alpha_values`` call: setting one reads the current pair from +chain and keeps the other side. Root-only params, the enum-valued +``recycle_or_burn``, and ``sn_owner_hotkey`` are left to the raw-call escape hatch. Read current values back with the ``subnet_hyperparameters`` read. """ @@ -16,23 +17,35 @@ from typing import Any from .._generated import calls -from ..hyperparams import to_raw +from .._generated.storage import SubtensorModule as st +from ..hyperparams import kind_of, to_raw from .base import Intent from .registry import register -# name -> (AdminUtils setter, value is boolean). Every setter takes (netuid, value). +# name -> (AdminUtils setter, value is boolean). Every setter takes (netuid, value), +# except the alpha pair below, which shares the two-value sudo_set_alpha_values. OWNER_HYPERPARAMETERS: dict[str, tuple[str, bool]] = { "immunity_period": ("sudo_set_immunity_period", False), "min_allowed_weights": ("sudo_set_min_allowed_weights", False), "weights_version": ("sudo_set_weights_version_key", False), "activity_cutoff": ("sudo_set_activity_cutoff", False), "min_burn": ("sudo_set_min_burn", False), + "max_burn": ("sudo_set_max_burn", False), "bonds_moving_avg": ("sudo_set_bonds_moving_average", False), + "bonds_penalty": ("sudo_set_bonds_penalty", False), "serving_rate_limit": ("sudo_set_serving_rate_limit", False), "commit_reveal_period": ("sudo_set_commit_reveal_weights_interval", False), "max_allowed_uids": ("sudo_set_max_allowed_uids", False), "burn_increase_mult": ("sudo_set_burn_increase_mult", False), "burn_half_life": ("sudo_set_burn_half_life", False), + "adjustment_alpha": ("sudo_set_adjustment_alpha", False), + "rho": ("sudo_set_rho", False), + "max_difficulty": ("sudo_set_max_difficulty", False), + "alpha_sigmoid_steepness": ("sudo_set_alpha_sigmoid_steepness", False), + "min_childkey_take": ("sudo_set_min_childkey_take_per_subnet", False), + "owner_immune_neuron_limit": ("sudo_set_owner_immune_neuron_limit", False), + "alpha_low": ("sudo_set_alpha_values", False), + "alpha_high": ("sudo_set_alpha_values", False), "commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", True), "liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", True), "network_pow_registration_allowed": ("sudo_set_network_pow_registration_allowed", True), @@ -43,6 +56,9 @@ "owner_cut_auto_lock_enabled": ("sudo_set_owner_cut_auto_lock_enabled", True), } +# Names sharing the two-value alpha call: position of each in (alpha_low, alpha_high). +_ALPHA_PAIR: dict[str, int] = {"alpha_low": 0, "alpha_high": 1} + HYPERPARAMETER_NAME_HELP = ( "Hyperparameter to set. One of: " + ", ".join(sorted(OWNER_HYPERPARAMETERS)) + "." ) @@ -60,10 +76,12 @@ class SetHyperparameter(Intent): """Set an owner-settable subnet hyperparameter (btcli ``sudo set``). Dispatches the matching AdminUtils ``sudo_set_*`` call for the named - parameter. The signer must be the subnet's owner coldkey; root-only - parameters are not available here and must go through the raw-call escape - hatch. Changes take effect on chain immediately and shape subnet economics - and consensus (registration costs, weight rules, immunity, transfers), so + parameter (``alpha_low``/``alpha_high`` read the current pair from chain and + set both via ``sudo_set_alpha_values``). The signer must be the subnet's + owner coldkey; root-only parameters are not available here and must go + through the raw-call escape hatch. Changes take effect on chain immediately + and shape subnet economics and consensus (registration costs, weight + rules, immunity, transfers), so verify the raw value before sending — ``value`` accepts either the raw on-chain integer or a human form that is converted for you. Some parameters are rate-limited by the chain, so a quick follow-up change can @@ -72,7 +90,9 @@ class SetHyperparameter(Intent): op = "set_hyperparameter" signer = "coldkey" - wraps = tuple(("AdminUtils", method) for method, _ in OWNER_HYPERPARAMETERS.values()) + wraps = tuple( + dict.fromkeys(("AdminUtils", method) for method, _ in OWNER_HYPERPARAMETERS.values()) + ) netuid: int = field(metadata={"help": "Subnet to configure; the signer must be its owner."}) name: str = field(metadata={"help": HYPERPARAMETER_NAME_HELP}) @@ -88,7 +108,16 @@ def __post_init__(self): async def build(self, substrate, wallet: Any): method, is_bool = OWNER_HYPERPARAMETERS[self.name] + if self.name in _ALPHA_PAIR: + # The chain sets alpha_low/alpha_high together; keep the other side. + pair = list(await substrate.query(*st.AlphaValues, [self.netuid])) + pair[_ALPHA_PAIR[self.name]] = int(self.value) + call = calls.AdminUtils.sudo_set_alpha_values(self.netuid, *pair) + return await substrate.compose(call) value: Any = bool(self.value) if is_bool else int(self.value) + if kind_of(self.name) == "fixed128": + # Fixed-point newtypes (U64F64) encode as a one-field struct. + value = {"bits": value} return await substrate.compose(getattr(calls.AdminUtils, method)(self.netuid, value)) def summary(self) -> str: diff --git a/sdk/python/bittensor/settings.py b/sdk/python/bittensor/settings.py index 090182a08d..59a25ed6d8 100644 --- a/sdk/python/bittensor/settings.py +++ b/sdk/python/bittensor/settings.py @@ -100,6 +100,10 @@ def resolve_endpoint(network: str) -> tuple[str, str]: _REVERSE_NETWORKS = {url: name for name, url in NETWORKS.items()} +# The published SDK/CLI documentation site (docs pages referenced from CLI +# output link here). +DOCS_URL = "https://www.bittensor.com/docs" + # Public block-explorer pages for an extrinsic, keyed by network label. ``{id}`` # is the on-chain extrinsic identifier "block_number-index" (index zero-padded # to 4 digits), the format both taostats and taomarketcap use. taomarketcap is diff --git a/sdk/python/codegen/check.py b/sdk/python/codegen/check.py index e7d3d2a108..83c419b572 100644 --- a/sdk/python/codegen/check.py +++ b/sdk/python/codegen/check.py @@ -215,12 +215,8 @@ def check_drift(endpoint: str) -> int: # Enumerated explicitly (not computed) so a newly added unwrapped call is # flagged as missing and requires a deliberate wrap-or-raw-only decision. "schedule_grandpa_change", - "sudo_set_adjustment_alpha", "sudo_set_adjustment_interval", "sudo_set_admin_freeze_window", - "sudo_set_alpha_sigmoid_steepness", - "sudo_set_alpha_values", - "sudo_set_bonds_penalty", "sudo_set_ck_burn", "sudo_set_coldkey_swap_announcement_delay", "sudo_set_coldkey_swap_reannouncement_delay", @@ -233,13 +229,10 @@ def check_drift(endpoint: str) -> int: "sudo_set_kappa", "sudo_set_lock_reduction_interval", "sudo_set_max_allowed_validators", - "sudo_set_max_burn", - "sudo_set_max_difficulty", "sudo_set_max_epochs_per_block", "sudo_set_max_mechanism_count", "sudo_set_max_registrations_per_block", "sudo_set_min_allowed_uids", - "sudo_set_min_childkey_take_per_subnet", "sudo_set_min_delegate_take", "sudo_set_min_difficulty", "sudo_set_min_non_immune_uids", @@ -250,10 +243,8 @@ def check_drift(endpoint: str) -> int: "sudo_set_network_registration_allowed", "sudo_set_nominator_min_required_stake", "sudo_set_owner_hparam_rate_limit", - "sudo_set_owner_immune_neuron_limit", "sudo_set_rao_recycled", "sudo_set_recycle_or_burn", - "sudo_set_rho", "sudo_set_sn_owner_hotkey", "sudo_set_stake_threshold", "sudo_set_start_call_delay", @@ -384,6 +375,13 @@ def check_units() -> int: problems: list[str] = [] derived = 0 for name, meta in hyperparams.HYPERPARAMS.items(): + if not meta.short: + problems.append(f"{name}: no short description (the listing's blurb column)") + elif len(meta.short) > hyperparams.SHORT_MAX: + problems.append( + f"{name}: short description is {len(meta.short)} chars " + f"(max {hyperparams.SHORT_MAX}): {meta.short!r}" + ) metadata_kind = hyperparams.metadata_kind(name) if metadata_kind is None: # No dedicated storage value, or the (pre-newtype) metadata @@ -403,7 +401,8 @@ def check_units() -> int: return 1 print( f"units ok: {derived} metadata-derived hyperparameter kinds agree with the hand " - f"table ({len(hyperparams.HYPERPARAMS) - derived} carry no unit-bearing identity)" + f"table ({len(hyperparams.HYPERPARAMS) - derived} carry no unit-bearing identity), " + f"and all {len(hyperparams.HYPERPARAMS)} carry a short description" ) return 0 diff --git a/website/apps/bittensor-website/public/catalog/intents.json b/website/apps/bittensor-website/public/catalog/intents.json index 990cc26d4d..d63ece39c6 100644 --- a/website/apps/bittensor-website/public/catalog/intents.json +++ b/website/apps/bittensor-website/public/catalog/intents.json @@ -1571,7 +1571,7 @@ { "name": "set_hyperparameter", "summary": "Set an owner-settable subnet hyperparameter (btcli `sudo set`).", - "description": "Set an owner-settable subnet hyperparameter (btcli `sudo set`).\n\nDispatches the matching AdminUtils `sudo_set_*` call for the named\nparameter. The signer must be the subnet's owner coldkey; root-only\nparameters are not available here and must go through the raw-call escape\nhatch. Changes take effect on chain immediately and shape subnet economics\nand consensus (registration costs, weight rules, immunity, transfers), so\nverify the raw value before sending \u2014 `value` accepts either the raw\non-chain integer or a human form that is converted for you. Some\nparameters are rate-limited by the chain, so a quick follow-up change can\nfail. Read current values back with the `subnet_hyperparameters` read.", + "description": "Set an owner-settable subnet hyperparameter (btcli `sudo set`).\n\nDispatches the matching AdminUtils `sudo_set_*` call for the named\nparameter (`alpha_low`/`alpha_high` read the current pair from chain and\nset both via `sudo_set_alpha_values`). The signer must be the subnet's\nowner coldkey; root-only parameters are not available here and must go\nthrough the raw-call escape hatch. Changes take effect on chain immediately\nand shape subnet economics and consensus (registration costs, weight\nrules, immunity, transfers), so\nverify the raw value before sending \u2014 `value` accepts either the raw\non-chain integer or a human form that is converted for you. Some\nparameters are rate-limited by the chain, so a quick follow-up change can\nfail. Read current values back with the `subnet_hyperparameters` read.", "signer": "coldkey", "input_schema": { "type": "object", @@ -1582,7 +1582,7 @@ }, "name": { "type": "string", - "description": "Hyperparameter to set. One of: activity_cutoff, bonds_moving_avg, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, min_allowed_weights, min_burn, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, serving_rate_limit, transfers_enabled, weights_version, yuma3_enabled." + "description": "Hyperparameter to set. One of: activity_cutoff, adjustment_alpha, alpha_high, alpha_low, alpha_sigmoid_steepness, bonds_moving_avg, bonds_penalty, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, max_burn, max_difficulty, min_allowed_weights, min_burn, min_childkey_take, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, owner_immune_neuron_limit, rho, serving_rate_limit, transfers_enabled, weights_version, yuma3_enabled." }, "value": { "type": [ From 7b548b61dbc921be7221ed0bfad5ecf450fe693b Mon Sep 17 00:00:00 2001 From: unarbos Date: Mon, 13 Jul 2026 16:32:40 -0600 Subject: [PATCH 04/43] give each hyperparameter an explainer page with a playable demo Co-authored-by: Cursor --- docs/hyperparameters/activity-cutoff.mdx | 54 +++ docs/hyperparameters/adjustment-alpha.mdx | 54 +++ docs/hyperparameters/adjustment-interval.mdx | 51 +++ docs/hyperparameters/alpha-high.mdx | 38 +++ docs/hyperparameters/alpha-low.mdx | 38 +++ .../alpha-sigmoid-steepness.mdx | 37 ++ docs/hyperparameters/bonds-moving-avg.mdx | 38 +++ docs/hyperparameters/bonds-penalty.mdx | 35 ++ docs/hyperparameters/bonds-reset-enabled.mdx | 30 ++ docs/hyperparameters/burn-half-life.mdx | 51 +++ docs/hyperparameters/burn-increase-mult.mdx | 56 +++ docs/hyperparameters/commit-reveal-period.mdx | 51 +++ .../commit-reveal-weights-enabled.mdx | 53 +++ docs/hyperparameters/difficulty.mdx | 55 +++ docs/hyperparameters/immunity-period.mdx | 32 ++ docs/hyperparameters/index.mdx | 51 +++ docs/hyperparameters/kappa.mdx | 49 +++ docs/hyperparameters/liquid-alpha-enabled.mdx | 32 ++ docs/hyperparameters/max-allowed-uids.mdx | 30 ++ docs/hyperparameters/max-burn.mdx | 53 +++ docs/hyperparameters/max-difficulty.mdx | 55 +++ docs/hyperparameters/max-regs-per-block.mdx | 56 +++ docs/hyperparameters/max-validators.mdx | 48 +++ docs/hyperparameters/max-weights-limit.mdx | 46 +++ docs/hyperparameters/meta.json | 46 +++ docs/hyperparameters/min-allowed-weights.mdx | 48 +++ docs/hyperparameters/min-burn.mdx | 48 +++ docs/hyperparameters/min-childkey-take.mdx | 47 +++ docs/hyperparameters/min-difficulty.mdx | 54 +++ .../network-pow-registration-allowed.mdx | 58 ++++ .../owner-cut-auto-lock-enabled.mdx | 51 +++ docs/hyperparameters/owner-cut-enabled.mdx | 45 +++ .../owner-immune-neuron-limit.mdx | 30 ++ docs/hyperparameters/registration-allowed.mdx | 49 +++ docs/hyperparameters/rho.mdx | 57 ++++ docs/hyperparameters/serving-rate-limit.mdx | 28 ++ .../target-regs-per-interval.mdx | 57 ++++ docs/hyperparameters/tempo.mdx | 48 +++ docs/hyperparameters/transfers-enabled.mdx | 44 +++ docs/hyperparameters/weights-rate-limit.mdx | 49 +++ docs/hyperparameters/weights-version.mdx | 50 +++ docs/hyperparameters/yuma3-enabled.mdx | 31 ++ docs/meta.json | 1 + .../bittensor-website/scripts/generate.py | 88 ++++- .../docs/hyperparam-burn-controller.tsx | 243 +++++++++++++ .../docs/hyperparam-consensus-sigmoid.tsx | 140 ++++++++ .../docs/hyperparam-liquid-alpha.tsx | 214 ++++++++++++ .../components/docs/hyperparam-owner-cut.tsx | 156 +++++++++ .../docs/hyperparam-pow-difficulty.tsx | 221 ++++++++++++ .../docs/hyperparam-uid-lifecycle.tsx | 320 ++++++++++++++++++ .../docs/hyperparam-weights-rules.tsx | 280 +++++++++++++++ .../bittensor-website/src/components/mdx.tsx | 14 + 52 files changed, 3603 insertions(+), 7 deletions(-) create mode 100644 docs/hyperparameters/activity-cutoff.mdx create mode 100644 docs/hyperparameters/adjustment-alpha.mdx create mode 100644 docs/hyperparameters/adjustment-interval.mdx create mode 100644 docs/hyperparameters/alpha-high.mdx create mode 100644 docs/hyperparameters/alpha-low.mdx create mode 100644 docs/hyperparameters/alpha-sigmoid-steepness.mdx create mode 100644 docs/hyperparameters/bonds-moving-avg.mdx create mode 100644 docs/hyperparameters/bonds-penalty.mdx create mode 100644 docs/hyperparameters/bonds-reset-enabled.mdx create mode 100644 docs/hyperparameters/burn-half-life.mdx create mode 100644 docs/hyperparameters/burn-increase-mult.mdx create mode 100644 docs/hyperparameters/commit-reveal-period.mdx create mode 100644 docs/hyperparameters/commit-reveal-weights-enabled.mdx create mode 100644 docs/hyperparameters/difficulty.mdx create mode 100644 docs/hyperparameters/immunity-period.mdx create mode 100644 docs/hyperparameters/index.mdx create mode 100644 docs/hyperparameters/kappa.mdx create mode 100644 docs/hyperparameters/liquid-alpha-enabled.mdx create mode 100644 docs/hyperparameters/max-allowed-uids.mdx create mode 100644 docs/hyperparameters/max-burn.mdx create mode 100644 docs/hyperparameters/max-difficulty.mdx create mode 100644 docs/hyperparameters/max-regs-per-block.mdx create mode 100644 docs/hyperparameters/max-validators.mdx create mode 100644 docs/hyperparameters/max-weights-limit.mdx create mode 100644 docs/hyperparameters/meta.json create mode 100644 docs/hyperparameters/min-allowed-weights.mdx create mode 100644 docs/hyperparameters/min-burn.mdx create mode 100644 docs/hyperparameters/min-childkey-take.mdx create mode 100644 docs/hyperparameters/min-difficulty.mdx create mode 100644 docs/hyperparameters/network-pow-registration-allowed.mdx create mode 100644 docs/hyperparameters/owner-cut-auto-lock-enabled.mdx create mode 100644 docs/hyperparameters/owner-cut-enabled.mdx create mode 100644 docs/hyperparameters/owner-immune-neuron-limit.mdx create mode 100644 docs/hyperparameters/registration-allowed.mdx create mode 100644 docs/hyperparameters/rho.mdx create mode 100644 docs/hyperparameters/serving-rate-limit.mdx create mode 100644 docs/hyperparameters/target-regs-per-interval.mdx create mode 100644 docs/hyperparameters/tempo.mdx create mode 100644 docs/hyperparameters/transfers-enabled.mdx create mode 100644 docs/hyperparameters/weights-rate-limit.mdx create mode 100644 docs/hyperparameters/weights-version.mdx create mode 100644 docs/hyperparameters/yuma3-enabled.mdx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx diff --git a/docs/hyperparameters/activity-cutoff.mdx b/docs/hyperparameters/activity-cutoff.mdx new file mode 100644 index 0000000000..1e6da64f03 --- /dev/null +++ b/docs/hyperparameters/activity-cutoff.mdx @@ -0,0 +1,54 @@ +--- +title: activity_cutoff +description: Blocks without setting weights after which a validator is inactive and excluded from consensus. +--- + +`activity_cutoff` is the window, in blocks, that a validator can go without +setting weights before the epoch marks it inactive and removes its stake from +consensus. Validators care because an expired cutoff silently zeroes their +influence and dividends; owners tune it to keep consensus limited to +validators that are actually evaluating miners. + +## How it works + +At each epoch (`pallets/subtensor/src/epoch/run_epoch.rs`), a neuron is +inactive when `last_update + activity_cutoff` is less than the current block, +where `last_update` is the block of its last accepted weight submission. +Inactive stake is masked out of the active-stake vector before consensus, so +an inactive validator contributes nothing to the +[`kappa`](/docs/hyperparameters/kappa)-weighted median and earns no +dividends until it sets weights again. + +The effective value is derived, not stored directly: +`get_activity_cutoff_blocks` (`pallets/subtensor/src/utils/misc.rs`) computes +`factor_milli × tempo / 1000`, clamped to at least 1 block. The per-mille +factor is bounded to 1,000–50,000 (one to fifty tempos); the default 13,889 +at tempo 360 yields the legacy 5,000-block cutoff (~16.7 hours). + +## Reading and setting + +Inspect with: + +``` +btcli sudo get --netuid N --name activity_cutoff +``` + +This returns the effective block count. Owner-settable: + +``` +btcli sudo set --netuid N --name activity_cutoff --value 5000 +``` + +The value is a raw block count (12s blocks), floor 360. Note that this +dispatches the legacy absolute-blocks extrinsic; the epoch reads the +factor-derived value, so the tempo-relative `set_activity_cutoff_factor` +extrinsic (per-mille of [`tempo`](/docs/hyperparameters/tempo)) is the +authoritative way to change what the epoch actually uses. + +## Related + +[`tempo`](/docs/hyperparameters/tempo) · +[`kappa`](/docs/hyperparameters/kappa) · +[`rho`](/docs/hyperparameters/rho) · +[`max_validators`](/docs/hyperparameters/max-validators) · +[`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) diff --git a/docs/hyperparameters/adjustment-alpha.mdx b/docs/hyperparameters/adjustment-alpha.mdx new file mode 100644 index 0000000000..236edfd51d --- /dev/null +++ b/docs/hyperparameters/adjustment-alpha.mdx @@ -0,0 +1,54 @@ +--- +title: adjustment_alpha +description: Smoothing factor of the legacy difficulty/burn adjustment, stored as u64 (u64::MAX = 1.0). +--- + +The smoothing factor of Bittensor's original registration-price controller. +When the chain adjusted burn and PoW difficulty once per +[`adjustment_interval`](/docs/hyperparameters/adjustment-interval), this value +blended the old price into the new one — an exponential moving average where +higher alpha meant slower movement. Owners still see it in the hyperparameter +listing; on the current chain it is inert. + +## How it works + +The value lives in `AdjustmentAlpha` storage as a u64 fraction where +`u64::MAX` encodes 1.0. The mainnet default is **0** +(`SubtensorInitialAdjustmentAlpha` in `runtime/src/lib.rs`) — in the legacy +formula `next = alpha × current + (1 − alpha) × proposed`, zero meant no +weight on the previous value, i.e. no smoothing at all. + +In the current runtime the legacy interval controller is gone, and **nothing +reads this value** outside of the RPC/metagraph views: registration pricing is +handled per block in `pallets/subtensor/src/subnets/registration.rs`, where +each registration bumps the burn by +[`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) and decay with +half-life [`burn_half_life`](/docs/hyperparameters/burn-half-life) pulls it +back toward [`min_burn`](/docs/hyperparameters/min-burn). The setter +(`sudo_set_adjustment_alpha` in `pallets/admin-utils/src/lib.rs`) remains +callable by the subnet owner, subject only to the owner rate limit and admin +freeze window — but setting it changes nothing about how registrations are +priced. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name adjustment_alpha +btcli sudo set --netuid 12 --name adjustment_alpha --value 0.5 +``` + +Settable by the subnet owner or root. A value with a decimal point is a 0..1 +fraction (`0.5` = half weight on the previous value); a plain integer is the +raw u64 (u64::MAX = 1.0). + +## Related + +- [`adjustment_interval`](/docs/hyperparameters/adjustment-interval) — the + legacy controller's cadence +- [`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) + — the target it steered toward +- [`burn_half_life`](/docs/hyperparameters/burn-half-life) / + [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) — the + controller that replaced it diff --git a/docs/hyperparameters/adjustment-interval.mdx b/docs/hyperparameters/adjustment-interval.mdx new file mode 100644 index 0000000000..edde319549 --- /dev/null +++ b/docs/hyperparameters/adjustment-interval.mdx @@ -0,0 +1,51 @@ +--- +title: adjustment_interval +description: Blocks between adjustments of the registration difficulty and burn cost (legacy cadence). +--- + +Historically the cadence of Bittensor's registration-price controller: every +`adjustment_interval` blocks, the chain compared registrations against +[`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) +and moved the burn cost and PoW difficulty up or down. It matters today mostly +as context — the current chain adjusts the burn price continuously instead. + +## How it works + +The parameter lives in `AdjustmentInterval` storage (u16 block count, default +100 blocks ≈ 20 minutes, from `SubtensorInitialAdjustmentInterval` in +`runtime/src/lib.rs`). In the current runtime, however, **no adjustment logic +reads it**: the interval-based controller was replaced by a per-block +mechanism in `pallets/subtensor/src/subnets/registration.rs` where each +registration multiplies the burn by +[`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) and the price +decays every block with half-life +[`burn_half_life`](/docs/hyperparameters/burn-half-life), clamped to +\[[`min_burn`](/docs/hyperparameters/min-burn), +[`max_burn`](/docs/hyperparameters/max-burn)\]. The value is still stored, +returned by the `subnet_hyperparameters` query, and settable — the extrinsic +(`sudo_set_adjustment_interval` in `pallets/admin-utils/src/lib.rs`) checks +only that the subnet exists — but changing it has no effect on registration +pricing. Even the root subnet's per-interval registration counter resets on +the root epoch boundary (`tempo`), not on this interval. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name adjustment_interval +``` + +Root/governance only — `sudo_set_adjustment_interval` requires the root +origin, so subnet owners cannot change it. The value is a plain block count +(12-second blocks). + +## Related + +- [`burn_half_life`](/docs/hyperparameters/burn-half-life) — the cadence's + replacement for burn decay +- [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) — the + per-registration response +- [`adjustment_alpha`](/docs/hyperparameters/adjustment-alpha) — the smoothing + factor of the same legacy controller +- [`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) diff --git a/docs/hyperparameters/alpha-high.mdx b/docs/hyperparameters/alpha-high.mdx new file mode 100644 index 0000000000..d4508adee8 --- /dev/null +++ b/docs/hyperparameters/alpha-high.mdx @@ -0,0 +1,38 @@ +--- +title: alpha_high +description: Upper bound of the liquid-alpha bonds EMA range — the smoothing rate for weights that deviate most from consensus. +--- + +`alpha_high` is the ceiling of the per-pair bonds EMA rate when [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) is on. Pairs whose weights deviate strongly from consensus approach this rate, so their bonds move fastest. Subnet owners tune it to decide how quickly a bold, off-consensus position translates into bonds; validators care because it caps how fast conviction can build or unwind. + +## How it works + +Each epoch, `alpha_sigmoid` (`pallets/subtensor/src/epoch/run_epoch.rs`) maps a pair's deviation from consensus into the EMA rate: + +``` +alpha = alpha_low + sigmoid(diff) × (alpha_high − alpha_low) +``` + +The deviation is `weight − consensus` when a validator is raising its bond, or `bond − weight` when lowering it (both clamped to 0..1). As deviation grows past 0.5 the sigmoid saturates toward 1 and alpha approaches `alpha_high`; the result is clamped into the `alpha_low`..`alpha_high` window. The resulting per-pair matrix drives the bonds EMA `B(t) = alpha × W + (1 − alpha) × B(t−1)` in `mat_ema_alpha`. Defaults are (45875, 58982) — 0.7 and 0.9 of `u16::MAX`. + +Validation in `do_set_alpha_values`: liquid alpha must already be enabled (`LiquidAlphaDisabled`), and `alpha_high` must be at least 1638 (`u16::MAX / 40` ≈ 0.025), else `AlphaHighTooLow`. `alpha_low` may not exceed it. + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name alpha_high +``` + +Stored as u16 (65535 = 1.0); the CLI accepts the raw integer or a 0..1 fraction with a decimal point: + +``` +btcli sudo set --netuid N --name alpha_high --value 0.9 +``` + +On chain, [`alpha_low`](/docs/hyperparameters/alpha-low) and `alpha_high` live in one storage value set by a single `sudo_set_alpha_values` call. The CLI reads the current pair and resubmits it with only `alpha_high` changed, so the other side is preserved. + +## Related + +[`alpha_low`](/docs/hyperparameters/alpha-low), [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness), [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled), [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) diff --git a/docs/hyperparameters/alpha-low.mdx b/docs/hyperparameters/alpha-low.mdx new file mode 100644 index 0000000000..233a32a0e7 --- /dev/null +++ b/docs/hyperparameters/alpha-low.mdx @@ -0,0 +1,38 @@ +--- +title: alpha_low +description: Lower bound of the liquid-alpha bonds EMA range — the smoothing rate for weights that sit at consensus. +--- + +`alpha_low` is the floor of the per-pair bonds EMA rate when [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) is on. It is the rate applied to validator–miner pairs whose weights match consensus — the slow, steady end of the liquid-alpha range. Subnet owners tune it to set how sluggish bonds are in the default case; validators care because it governs how fast their conviction decays or accrues when they are not deviating. + +## How it works + +Each epoch, `alpha_sigmoid` (`pallets/subtensor/src/epoch/run_epoch.rs`) computes a per-pair rate: + +``` +alpha = alpha_low + sigmoid(diff) × (alpha_high − alpha_low) +``` + +where `diff` is the pair's deviation from consensus and the sigmoid rises with [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness). At zero deviation the sigmoid is near 0, so alpha sits at `alpha_low`; the result is always clamped into the `alpha_low`..`alpha_high` window. Defaults are (45875, 58982), i.e. 0.7 and 0.9 of `u16::MAX`. + +Validation in `do_set_alpha_values`: liquid alpha must already be enabled (`LiquidAlphaDisabled`), `alpha_low` must be at least 1638 (`u16::MAX / 40` ≈ 0.025) and at most `alpha_high`, else `AlphaLowOutOfRange`. + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name alpha_low +``` + +Stored as u16 (65535 = 1.0); the CLI accepts the raw integer or a 0..1 fraction with a decimal point: + +``` +btcli sudo set --netuid N --name alpha_low --value 0.7 +``` + +On chain, `alpha_low` and [`alpha_high`](/docs/hyperparameters/alpha-high) live in one storage value set by a single `sudo_set_alpha_values` call. The CLI reads the current pair and resubmits it with only `alpha_low` changed, so the other side is preserved. + +## Related + +[`alpha_high`](/docs/hyperparameters/alpha-high), [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness), [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled), [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) diff --git a/docs/hyperparameters/alpha-sigmoid-steepness.mdx b/docs/hyperparameters/alpha-sigmoid-steepness.mdx new file mode 100644 index 0000000000..617a06de65 --- /dev/null +++ b/docs/hyperparameters/alpha-sigmoid-steepness.mdx @@ -0,0 +1,37 @@ +--- +title: alpha_sigmoid_steepness +description: Slope of the liquid-alpha sigmoid mapping consensus deviation to the bonds EMA rate; negative values (root only) invert the curve. +--- + +`alpha_sigmoid_steepness` shapes the transition between [`alpha_low`](/docs/hyperparameters/alpha-low) and [`alpha_high`](/docs/hyperparameters/alpha-high) when [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) is on. Subnet owners tune it to make the liquid-alpha response gradual (small values) or nearly a step function (large values); validators care because it decides how much deviation from consensus is needed before their bonds start moving at the fast rate. + +## How it works + +For each validator–miner pair, `alpha_sigmoid` (`pallets/subtensor/src/epoch/run_epoch.rs`) computes + +``` +sigmoid = 1 / (1 + e^(-(steepness / 100) × (diff − 0.5))) +alpha = alpha_low + sigmoid × (alpha_high − alpha_low) +``` + +where `diff` is the pair's deviation from consensus, clamped to 0..1. The stored i16 is divided by 100, so the default 1000 gives an effective slope of 10: alpha sits near `alpha_low` for small deviations, crosses the midpoint at `diff = 0.5`, and saturates near `alpha_high` beyond it. Steepness near 0 flattens the curve to the midpoint of the range; very large values approximate a hard threshold at 0.5. + +Negative steepness inverts the curve — consensus-aligned pairs get the fast rate — and `sudo_set_alpha_sigmoid_steepness` in `pallets/admin-utils/src/lib.rs` reserves that to root: a subnet owner passing a negative value gets `NegativeSigmoidSteepness`. + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name alpha_sigmoid_steepness +``` + +Plain integer (i16); owners may set 0 or positive values: + +``` +btcli sudo set --netuid N --name alpha_sigmoid_steepness --value 1000 +``` + +## Related + +[`alpha_low`](/docs/hyperparameters/alpha-low), [`alpha_high`](/docs/hyperparameters/alpha-high), [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) diff --git a/docs/hyperparameters/bonds-moving-avg.mdx b/docs/hyperparameters/bonds-moving-avg.mdx new file mode 100644 index 0000000000..a0d1ae0fff --- /dev/null +++ b/docs/hyperparameters/bonds-moving-avg.mdx @@ -0,0 +1,38 @@ +--- +title: bonds_moving_avg +description: Smoothing factor for the validator bonds EMA — higher retains more of past bonds each epoch. +--- + +`bonds_moving_avg` controls how slowly validator bonds track a validator's current weights. Subnet owners tune it to decide how long validators must hold a position before their bonds (and thus dividends) catch up; validators care because it sets how fast early, correct weight calls pay off. + +## How it works + +Bonds are an exponential moving average over each validator–miner pair. Every epoch the chain computes + +``` +B(t) = alpha × ΔB + (1 − alpha) × B(t−1) +``` + +where `alpha = 1 − bonds_moving_avg / 1,000,000` (`compute_ema_bonds_normal` in `pallets/subtensor/src/epoch/run_epoch.rs`). The default 900,000 gives alpha = 0.1: each epoch a bond moves 10% of the way toward the validator's instant bond. Higher values mean stickier bonds and slower dividend response; lower values make bonds chase current weights quickly, weakening the reward for early conviction. + +The flat rate applies on the classic consensus path, and also on the [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) path whenever [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) is off (`compute_disabled_liquid_alpha`). With liquid alpha on, the per-pair sigmoid rate replaces it entirely. + +Subnet owners can set at most 975,000 (`BondsMovingAverageMaxReached` in `pallets/admin-utils/src/lib.rs`); only root can go higher. + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name bonds_moving_avg +``` + +Stored over 1,000,000 (900000 = 0.9). The set command accepts either the raw integer or the human fraction with a decimal point: + +``` +btcli sudo set --netuid N --name bonds_moving_avg --value 0.9 +``` + +## Related + +[`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled), [`alpha_low`](/docs/hyperparameters/alpha-low), [`alpha_high`](/docs/hyperparameters/alpha-high), [`bonds_penalty`](/docs/hyperparameters/bonds-penalty), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) diff --git a/docs/hyperparameters/bonds-penalty.mdx b/docs/hyperparameters/bonds-penalty.mdx new file mode 100644 index 0000000000..7719366bdf --- /dev/null +++ b/docs/hyperparameters/bonds-penalty.mdx @@ -0,0 +1,35 @@ +--- +title: bonds_penalty +description: How much out-of-consensus weight is excluded from bond accrual, from none (0) to full clipping (1). +--- + +`bonds_penalty` decides whether validators build bonds from their raw weights or only from the consensus-clipped portion. Subnet owners use it to punish (or tolerate) weight-setting that deviates from the stake-weighted consensus; validators care because it determines whether an out-of-consensus bet still accrues bonds. + +## How it works + +Before the bonds EMA runs, the epoch interpolates between raw and clipped weight matrices (`pallets/subtensor/src/epoch/run_epoch.rs`, around the "Bonds and Dividends" step): + +``` +weights_for_bonds = (1 − penalty) × weights + penalty × clipped_weights +``` + +- `bonds_penalty = 0`: bonds accrue from raw weights — deviating from consensus costs nothing in bond terms. +- `bonds_penalty = 1` (the default, stored as 65535): bonds accrue only from consensus-clipped weights, so any weight above the stake-weighted median is ignored for bonding. + +Values in between blend the two. The interpolated matrix feeds the bonds EMA on both the classic path and the [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) path, so the penalty applies regardless of which consensus variant is active. See the [Yuma Consensus overview](/docs/concepts/emissions#yuma-consensus) for where this sits in the epoch. + +## Reading and setting + +``` +btcli sudo get --netuid N --name bonds_penalty +``` + +Stored as u16 (65535 = 1.0, full penalty). The set command accepts the raw integer or a 0..1 fraction with a decimal point: + +``` +btcli sudo set --netuid N --name bonds_penalty --value 1.0 +``` + +## Related + +[`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg), [`bonds_reset_enabled`](/docs/hyperparameters/bonds-reset-enabled), [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) diff --git a/docs/hyperparameters/bonds-reset-enabled.mdx b/docs/hyperparameters/bonds-reset-enabled.mdx new file mode 100644 index 0000000000..f9186db9af --- /dev/null +++ b/docs/hyperparameters/bonds-reset-enabled.mdx @@ -0,0 +1,30 @@ +--- +title: bonds_reset_enabled +description: Whether a neuron's accrued validator bonds are wiped when it commits new on-chain metadata. +--- + +`bonds_reset_enabled` makes metadata commitments costly for miners: when enabled, any hotkey that publishes a commitment on the subnet has all bonds pointing at it erased. Subnet owners enable it on subnets where a metadata commit signals a model or identity change that should reset accumulated validator conviction; validators care because their bonds on that miner — and the dividends they earn from them — restart from zero. + +## How it works + +When a hotkey commits metadata (the commitments pallet's `OnMetadataCommitment` hook, wired up as `ResetBondsOnCommit` in `runtime/src/lib.rs`), the chain calls `do_reset_bonds` in `pallets/subtensor/src/epoch/run_epoch.rs` for each mechanism of the subnet. If this flag is off, the call returns immediately. If it is on, the chain looks up the committing hotkey's UID and filters that UID's column out of every validator's bond vector — every bond held **on** the committing neuron is deleted, while bonds the neuron holds as a validator on others are untouched. + +Bonds then rebuild through the normal EMA at the rate set by [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg) (or the liquid-alpha rate), so validators who re-endorse the refreshed miner regain dividends over subsequent epochs. + +The flag is off by default and toggling it emits a `BondsResetToggled` event (`sudo_set_bonds_reset_enabled` in `pallets/admin-utils/src/lib.rs`). + +## Reading and setting + +``` +btcli sudo get --netuid N --name bonds_reset_enabled +``` + +Boolean — pass true or false: + +``` +btcli sudo set --netuid N --name bonds_reset_enabled --value true +``` + +## Related + +[`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg), [`bonds_penalty`](/docs/hyperparameters/bonds-penalty), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled), [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) diff --git a/docs/hyperparameters/burn-half-life.mdx b/docs/hyperparameters/burn-half-life.mdx new file mode 100644 index 0000000000..bd0e1c3d73 --- /dev/null +++ b/docs/hyperparameters/burn-half-life.mdx @@ -0,0 +1,51 @@ +--- +title: burn_half_life +description: Blocks for the burn cost to decay halfway back toward min_burn. +--- + +Sets how quickly an elevated registration price cools off. After registrations +bump the burn cost up, it decays exponentially — this parameter is the number +of blocks for the price to halve. Owners tune it against +[`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) to pick the +registration rate their subnet sustains; miners watching an expensive subnet +can read it as "how long until the price is reasonable again." + +## How it works + +Every block, `update_registration_prices_for_networks` (in +`pallets/subtensor/src/subnets/registration.rs`, called from `block_step`) +multiplies each subnet's burn by a per-block factor `f` chosen so that +`f ^ burn_half_life = 1/2`, then clamps into +\[[`min_burn`](/docs/hyperparameters/min-burn), +[`max_burn`](/docs/hyperparameters/max-burn)\]. The factor is computed in Q32 +fixed-point by binary search (`decay_factor_q32` in +`pallets/subtensor/src/utils/misc.rs`), giving continuous exponential decay: +after `n` blocks without registrations the price is `burn × 0.5^(n / +half_life)`, until it hits the `min_burn` floor. + +The value is stored in `BurnHalfLife` as a u16 block count; the default is +**360 blocks** (~72 minutes at 12s blocks). A stored value of 0 disables decay +entirely, but the owner-set extrinsic (`sudo_set_burn_half_life` in +`pallets/admin-utils/src/lib.rs`) requires **1 to 36,100 blocks** (~5 days) and +rejects the root subnet. Together with the multiplier, the break-even +registration cadence is one registration per `half_life × log2(mult)` blocks — +faster than that and the price climbs, slower and it falls. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name burn_half_life +btcli sudo set --netuid 12 --name burn_half_life --value 720 +``` + +Settable by the subnet owner or root; the value is a plain block count +(12-second blocks). + +## Related + +- [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) — the bump + this decay works against +- [`min_burn`](/docs/hyperparameters/min-burn) — where the decay comes to rest +- [`max_burn`](/docs/hyperparameters/max-burn) — the ceiling it decays down from diff --git a/docs/hyperparameters/burn-increase-mult.mdx b/docs/hyperparameters/burn-increase-mult.mdx new file mode 100644 index 0000000000..8c165066e2 --- /dev/null +++ b/docs/hyperparameters/burn-increase-mult.mdx @@ -0,0 +1,56 @@ +--- +title: burn_increase_mult +description: Multiplier applied to the burn cost after each successful registration. +--- + +Controls how sharply the registration price reacts to demand: every successful +registration multiplies the current burn cost by this factor. Owners tune it to +decide how strongly a registration burst should price out the next entrant; +miners see it as the reason the cost quoted a moment ago can jump before their +own transaction lands. + +## How it works + +After each successful registration, `bump_registration_price_after_registration` +(in `pallets/subtensor/src/subnets/registration.rs`) sets + +``` +new_burn = clamp(burn × burn_increase_mult, min_burn, max_burn) +``` + +The bump is immediate — the very next registration, even in the same block, +pays the raised price. Values below 1 are treated as 1 at read time +(`max(mult, 1)`), so the multiplier can never shrink the price. Between +registrations, the per-block decay governed by +[`burn_half_life`](/docs/hyperparameters/burn-half-life) pulls the price back +toward [`min_burn`](/docs/hyperparameters/min-burn). The steady-state +registration rate the pair supports is where bumps and decay cancel: +`half_life × log2(mult)` blocks per registration. + +The value is stored in `BurnIncreaseMult` as U64F64 fixed-point (raw bits +divided by 2^64 give the real multiplier); the default is **1.26** (~3 +registrations to double the price). The owner-set extrinsic +(`sudo_set_burn_increase_mult` in `pallets/admin-utils/src/lib.rs`) requires +the value to be **between 1 and 3** inclusive and rejects the root subnet, +which does not use the bump path. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name burn_increase_mult +btcli sudo set --netuid 12 --name burn_increase_mult --value 1.5 +``` + +Settable by the subnet owner or root. A value with a decimal point is the +multiplier itself (`1.5`); a plain integer is the raw U64F64 bits. + +## Related + +- [`burn_half_life`](/docs/hyperparameters/burn-half-life) — the decay that + counteracts these bumps +- [`min_burn`](/docs/hyperparameters/min-burn) / + [`max_burn`](/docs/hyperparameters/max-burn) — the clamp bounds +- [`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) — the hard + per-block cap behind the price mechanism diff --git a/docs/hyperparameters/commit-reveal-period.mdx b/docs/hyperparameters/commit-reveal-period.mdx new file mode 100644 index 0000000000..f1549ff3a7 --- /dev/null +++ b/docs/hyperparameters/commit-reveal-period.mdx @@ -0,0 +1,51 @@ +--- +title: commit_reveal_period +description: Epochs between committing a weights hash and revealing the weights, when commit-reveal is enabled. +--- + +`commit_reveal_period` (on chain: `RevealPeriodEpochs`) is how long committed +weights stay hidden before they are revealed, measured in **epochs (tempos), +not blocks**. With the default of 1 and a 360-block tempo, weights committed +in one epoch become public roughly one tempo (~72 minutes) later. Subnet +owners tune it to balance copy-resistance (longer hiding) against how stale +weights are when they finally land. + +## How it works + +Each commit is tagged with the subnet's current epoch index. The reveal is +valid in **exactly one epoch**: `is_reveal_block_range` +(`pallets/subtensor/src/subnets/weights.rs`) requires +`current_epoch == commit_epoch + commit_reveal_period`. Revealing earlier +fails with `RevealTooEarly`; once the current epoch moves past that target, +`is_commit_expired` drops the commit and a late reveal fails with +`ExpiredWeightCommit`. A hotkey may hold at most 10 unrevealed commits. + +The value is bounded on-chain: `set_reveal_period` accepts 1 to 100 epochs. + +In practice validators rarely reveal by hand. `btcli tx set-weights` (the +`set_weights` intent) uses timelocked commits: it reads `RevealPeriodEpochs` +and the subnet's epoch schedule, computes the drand round whose randomness +becomes available in the reveal epoch, and encrypts the payload to that round +— the chain then decrypts and applies the weights itself, with no reveal +transaction. + + + +## Reading and setting + +```bash +btcli sudo get --netuid N --name commit_reveal_period +``` + +Owner-settable; the value is an epoch (tempo) count: + +```bash +btcli sudo set --netuid N --name commit_reveal_period --value 2 +``` + +## Related + +- [`commit_reveal_weights_enabled`](/docs/hyperparameters/commit-reveal-weights-enabled) — the toggle that activates this delay +- [`tempo`](/docs/hyperparameters/tempo) — the block length of one epoch +- [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) — cooldown applied at commit time +- [`weights_version`](/docs/hyperparameters/weights-version) — version gate checked when revealed weights land diff --git a/docs/hyperparameters/commit-reveal-weights-enabled.mdx b/docs/hyperparameters/commit-reveal-weights-enabled.mdx new file mode 100644 index 0000000000..4615b3e5a9 --- /dev/null +++ b/docs/hyperparameters/commit-reveal-weights-enabled.mdx @@ -0,0 +1,53 @@ +--- +title: commit_reveal_weights_enabled +description: Whether validators must submit weights through commit-reveal, hiding them from copiers until the reveal. +--- + +`commit_reveal_weights_enabled` decides how weights reach the chain. When on +(the default for new subnets), validators must commit a hidden form of their +weights first and the actual values only become public an epoch or more later +— so weight-copying validators cannot free-ride on others' scoring work by +mirroring their submissions in the same epoch. + +## How it works + +The flag flips the accepted submission path. With it **on**, the plain +`set_weights` extrinsic is rejected outright with `CommitRevealEnabled` +(`pallets/subtensor/src/macros/dispatches.rs`); validators must instead +commit — either a salted hash (revealed later by a matching +`reveal_weights` call) or a timelock-encrypted payload that the chain +auto-decrypts at a drand round, no reveal transaction needed. With it +**off**, commits are rejected with `CommitRevealDisabled` and plain +`set_weights` is the only path. + +The reveal delay is governed by +[`commit_reveal_period`](/docs/hyperparameters/commit-reveal-period), and the +[`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) cooldown +applies at commit time rather than set time. Revealed weights pass through +the full `set_weights` validation (length, cap, version key) when they land. + +Validators do not need to branch on this flag themselves: `btcli tx +set-weights` (the `set_weights` intent) reads it and automatically dispatches +to plaintext `set_weights` or a timelocked commit, so the same command works +in either regime. + + + +## Reading and setting + +```bash +btcli sudo get --netuid N --name commit_reveal_weights_enabled +``` + +Owner-settable; the value is a flag (`true`/`false` or `1`/`0`): + +```bash +btcli sudo set --netuid N --name commit_reveal_weights_enabled --value true +``` + +## Related + +- [`commit_reveal_period`](/docs/hyperparameters/commit-reveal-period) — how long weights stay hidden +- [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) — cooldown applied at commit time +- [`weights_version`](/docs/hyperparameters/weights-version) — version gate on revealed weights +- [`min_allowed_weights`](/docs/hyperparameters/min-allowed-weights) — floor on submission size in either mode diff --git a/docs/hyperparameters/difficulty.mdx b/docs/hyperparameters/difficulty.mdx new file mode 100644 index 0000000000..e347fbfa24 --- /dev/null +++ b/docs/hyperparameters/difficulty.mdx @@ -0,0 +1,55 @@ +--- +title: difficulty +description: Current PoW registration difficulty; u64::MAX means PoW registration is effectively disabled. +--- + +`difficulty` is the proof-of-work target a miner's registration nonce must +beat to claim a UID via PoW registration. It is a raw u64: finding a valid +nonce takes about `difficulty` hash attempts on average, so the value is a +direct price in compute. Miners planning PoW registration care about it; +`u64::MAX` is the sentinel for "no nonce can ever pass" — PoW registration +effectively disabled, burned registration only. + +## How it works + +A PoW registration submits a seal built from a recent block hash, the +hotkey, and a nonce (`create_seal_hash` in +`pallets/subtensor/src/subnets/registration.rs`). The check is +`hash_meets_difficulty`: the seal hash times `difficulty` must not overflow +a 256-bit integer, which passes with probability roughly 1 in `difficulty`. +At `u64::MAX` essentially nothing passes. + +On the current runtime this check no longer gates subnet registration: the +`register` extrinsic (`pallets/subtensor/src/macros/dispatches.rs`, call +index 6) accepts the work arguments but ignores them and routes to the +burned-registration path (`do_register`). No controller adjusts `difficulty` +anymore either — the per-block price update +(`update_registration_prices_for_networks`) only decays the burn cost. The +value stays on-chain, is reported in the metagraph, and root can still +change it. The seal check itself survives in the testnet faucet +(`do_faucet`, fixed difficulty 1,000,000). + +Historically, `difficulty` walked between its floor and ceiling as the +chain steered registrations toward a target rate: + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name difficulty +``` + +Root/governance only: `sudo_set_difficulty` in the AdminUtils pallet +requires the root origin and takes a raw u64. It is not settable by the +subnet owner via `btcli sudo set`. + +## Related + +[`min_difficulty`](/docs/hyperparameters/min-difficulty) · +[`max_difficulty`](/docs/hyperparameters/max-difficulty) · +[`network_pow_registration_allowed`](/docs/hyperparameters/network-pow-registration-allowed) · +[`registration_allowed`](/docs/hyperparameters/registration-allowed) · +[`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) · +[`min_burn`](/docs/hyperparameters/min-burn) · +[`max_burn`](/docs/hyperparameters/max-burn) diff --git a/docs/hyperparameters/immunity-period.mdx b/docs/hyperparameters/immunity-period.mdx new file mode 100644 index 0000000000..76142c8978 --- /dev/null +++ b/docs/hyperparameters/immunity-period.mdx @@ -0,0 +1,32 @@ +--- +title: immunity_period +description: Blocks a newly registered neuron is protected from being pruned as the lowest-scoring UID on a full subnet. +--- + +`immunity_period` is the number of blocks a freshly registered neuron cannot be pruned to make room for a new registration. Subnet owners tune it to give new miners time to earn emission before they compete for their slot; miners care because it is their grace window to prove themselves. + +## How it works + +When a subnet is at [`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids), each new registration must recycle an existing slot. `get_neuron_to_prune` (`pallets/subtensor/src/subnets/registration.rs`) scans every UID and treats a neuron as immune while `current_block − registration_block` is less than `immunity_period`. It picks the lowest-emission non-immune neuron (ties broken by older registration, then lower UID). Owner-immune UIDs (see [`owner_immune_neuron_limit`](/docs/hyperparameters/owner-immune-neuron-limit)) are skipped entirely. + +Immunity is not absolute: if pruning a non-immune neuron would leave `MinNonImmuneUids` (default 10) or fewer non-immune UIDs, the chain instead prunes the lowest-emission immune neuron. If no candidate exists at all, registration fails with `NoNeuronIdAvailable`. + +The default is 4096 blocks, about 13.7 hours at 12-second blocks. Longer periods shelter newcomers but shrink the pool of prunable slots; with heavy registration churn, most of the subnet can end up immune. + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name immunity_period +``` + +The value is a plain block count: + +``` +btcli sudo set --netuid N --name immunity_period --value 4096 +``` + +## Related + +[`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids), [`owner_immune_neuron_limit`](/docs/hyperparameters/owner-immune-neuron-limit), [`serving_rate_limit`](/docs/hyperparameters/serving-rate-limit), [`min_burn`](/docs/hyperparameters/min-burn), [`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) diff --git a/docs/hyperparameters/index.mdx b/docs/hyperparameters/index.mdx new file mode 100644 index 0000000000..0943865155 --- /dev/null +++ b/docs/hyperparameters/index.mdx @@ -0,0 +1,51 @@ +--- +title: "Hyperparameters" +description: "What each subnet hyperparameter controls, its unit, and how to change it." +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Read them with `btcli sudo get --netuid N` (the [`subnet_hyperparameters`](/docs/query/subnet-hyperparameters) read); the subnet owner changes the owner-settable ones with `btcli sudo set` (the [`set_hyperparameter`](/docs/tx/set-hyperparameter) intent). Raw on-chain integers are primary; where a parameter is a fixed-point fraction or a rao amount, the value also accepts the human form with a decimal point. Each parameter has its own explainer page. + +| Hyperparameter | Unit | Owner-settable | What it controls | +| --- | --- | --- | --- | +| [`rho`](/docs/hyperparameters/rho) | integer | yes | trust curve steepness | +| [`kappa`](/docs/hyperparameters/kappa) | fraction (u16, 65535 = 1.0) | root only | consensus majority-stake threshold | +| [`immunity_period`](/docs/hyperparameters/immunity-period) | blocks (12s) | yes | prune-immunity window for new neurons | +| [`min_allowed_weights`](/docs/hyperparameters/min-allowed-weights) | integer | yes | minimum weights per submission | +| [`max_weights_limit`](/docs/hyperparameters/max-weights-limit) | fraction (u16, 65535 = 1.0) | root only | cap on a single miner's weight | +| [`tempo`](/docs/hyperparameters/tempo) | blocks (12s) | root only | blocks per consensus epoch | +| [`min_difficulty`](/docs/hyperparameters/min-difficulty) | PoW difficulty (u64) | root only | PoW registration difficulty floor | +| [`max_difficulty`](/docs/hyperparameters/max-difficulty) | PoW difficulty (u64) | yes | PoW registration difficulty ceiling | +| [`difficulty`](/docs/hyperparameters/difficulty) | PoW difficulty (u64) | root only | current PoW registration difficulty | +| [`weights_version`](/docs/hyperparameters/weights-version) | integer | yes | minimum version key for set_weights | +| [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) | blocks (12s) | root only | wait between weight submissions | +| [`adjustment_interval`](/docs/hyperparameters/adjustment-interval) | blocks (12s) | root only | difficulty/burn adjustment cadence | +| [`activity_cutoff`](/docs/hyperparameters/activity-cutoff) | blocks (12s) | yes | no-weights window before inactive | +| [`registration_allowed`](/docs/hyperparameters/registration-allowed) | flag | root only | new neuron registrations allowed | +| [`network_pow_registration_allowed`](/docs/hyperparameters/network-pow-registration-allowed) | flag | yes | PoW registration toggle | +| [`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) | integer | root only | registration-rate controller target | +| [`min_burn`](/docs/hyperparameters/min-burn) | TAO amount in rao | yes | burned-registration cost floor | +| [`max_burn`](/docs/hyperparameters/max-burn) | TAO amount in rao | yes | burned-registration cost ceiling | +| [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg) | fraction (1,000,000 = 1.0) | yes | bonds EMA smoothing factor | +| [`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) | integer | root only | per-block registration cap | +| [`serving_rate_limit`](/docs/hyperparameters/serving-rate-limit) | blocks (12s) | yes | cooldown between axon serve calls | +| [`max_validators`](/docs/hyperparameters/max-validators) | integer | root only | top-stake validator permit cap | +| [`adjustment_alpha`](/docs/hyperparameters/adjustment-alpha) | fraction (u64, u64::MAX = 1.0) | yes | difficulty/burn adjust smoothing | +| [`commit_reveal_period`](/docs/hyperparameters/commit-reveal-period) | epochs (tempos) | yes | weight commit-to-reveal delay | +| [`commit_reveal_weights_enabled`](/docs/hyperparameters/commit-reveal-weights-enabled) | flag | yes | commit-reveal weights toggle | +| [`alpha_high`](/docs/hyperparameters/alpha-high) | fraction (u16, 65535 = 1.0) | yes | liquid-alpha smoothing upper bound | +| [`alpha_low`](/docs/hyperparameters/alpha-low) | fraction (u16, 65535 = 1.0) | yes | liquid-alpha smoothing lower bound | +| [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) | flag | yes | per-weight bonds EMA (liquid alpha) | +| [`bonds_penalty`](/docs/hyperparameters/bonds-penalty) | fraction (u16, 65535 = 1.0) | yes | penalty on out-of-consensus bonds | +| [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness) | integer | yes | liquid-alpha sigmoid steepness | +| [`min_childkey_take`](/docs/hyperparameters/min-childkey-take) | fraction (u16, 65535 = 1.0) | yes | floor for childkey take | +| [`owner_immune_neuron_limit`](/docs/hyperparameters/owner-immune-neuron-limit) | integer | yes | owner-designated prune-immune UIDs | +| [`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids) | integer | yes | neuron slot capacity before pruning | +| [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) | multiplier (U64F64 bits / 2^64) | yes | burn cost bump per registration | +| [`burn_half_life`](/docs/hyperparameters/burn-half-life) | blocks (12s) | yes | burn cost decay half-life | +| [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) | flag | yes | yuma3 consensus variant toggle | +| [`bonds_reset_enabled`](/docs/hyperparameters/bonds-reset-enabled) | flag | yes | bonds reset on metadata commit | +| [`transfers_enabled`](/docs/hyperparameters/transfers-enabled) | flag | yes | stake transfers between coldkeys | +| [`owner_cut_enabled`](/docs/hyperparameters/owner-cut-enabled) | flag | yes | owner emission cut toggle | +| [`owner_cut_auto_lock_enabled`](/docs/hyperparameters/owner-cut-auto-lock-enabled) | flag | yes | auto-lock the owner's emission cut | diff --git a/docs/hyperparameters/kappa.mdx b/docs/hyperparameters/kappa.mdx new file mode 100644 index 0000000000..a2217d282d --- /dev/null +++ b/docs/hyperparameters/kappa.mdx @@ -0,0 +1,49 @@ +--- +title: kappa +description: Majority-stake threshold at which a weight counts as consensus-supported in Yuma Consensus. +--- + +`kappa` is the majority-stake threshold of Yuma Consensus: the fraction of +active stake that must support a weight level for it to count as consensus. +It shapes how much a stake majority can discipline outlier validators, so +validators and subnet designers both care — but only root governance can +change it. + +## How it works + +Each epoch, the chain computes a per-miner consensus score as a stake-weighted +median (`weighted_median_col` in `pallets/subtensor/src/epoch/math.rs`, +called from `epoch/run_epoch.rs` with `kappa` as the majority ratio): the +highest weight level such that validators holding at least `kappa` of active +stake set a weight at or above it. Every weight above that consensus value is +clipped down to it (`inplace_col_clip`), and the clipped matrix drives ranks, +incentive, and validator trust. In the classic sigmoid formulation, `kappa` +is also the midpoint of the trust curve that +[`rho`](/docs/hyperparameters/rho) steepens. + +Stored as u16 where 65535 = 1.0; the default 32767 means 0.5 — a simple +stake majority. Raising it demands broader agreement before a weight +survives clipping; lowering it lets smaller stake coalitions set consensus. +The full pipeline is described in +[Yuma Consensus](/docs/concepts/emissions#yuma-consensus). + + + +## Reading and setting + +Inspect with: + +``` +btcli sudo get --netuid N --name kappa +``` + +Not settable by the subnet owner — root/governance only +(`sudo_set_kappa` in the AdminUtils pallet requires the root origin). When +set, the raw value is a u16: 32767 ≈ 0.5. + +## Related + +[`rho`](/docs/hyperparameters/rho) · +[`tempo`](/docs/hyperparameters/tempo) · +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) · +[`max_validators`](/docs/hyperparameters/max-validators) diff --git a/docs/hyperparameters/liquid-alpha-enabled.mdx b/docs/hyperparameters/liquid-alpha-enabled.mdx new file mode 100644 index 0000000000..a490bcd962 --- /dev/null +++ b/docs/hyperparameters/liquid-alpha-enabled.mdx @@ -0,0 +1,32 @@ +--- +title: liquid_alpha_enabled +description: Switches the bonds EMA from one flat rate to a per-weight rate that varies between alpha_low and alpha_high. +--- + +`liquid_alpha_enabled` turns on "liquid alpha": instead of every validator–miner bond smoothing at the same flat rate, each pair gets its own EMA rate based on how far the validator's weight deviates from consensus. Subnet owners enable it to reward decisive, differentiated weight-setting; validators care because it changes how fast their bonds — and dividends — respond to weight changes. + +## How it works + +In the epoch's `compute_bonds` (`pallets/subtensor/src/epoch/run_epoch.rs`), if this flag is on and consensus is non-empty, the chain builds a full matrix of per-pair alphas via `compute_liquid_alpha_values`: each pair's deviation (weight above consensus when increasing a bond, bond above weight when decreasing) is pushed through a sigmoid and mapped into the [`alpha_low`](/docs/hyperparameters/alpha-low)..[`alpha_high`](/docs/hyperparameters/alpha-high) range, with [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness) controlling the transition sharpness. Larger deviations get a higher alpha, so those bonds move faster. + +When the flag is off, every pair uses the flat rate `1 − bonds_moving_avg / 1,000,000` (`compute_disabled_liquid_alpha`). + +One important dependency: `compute_bonds` only runs on the Yuma3 path. If [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) is off, the classic bond code ignores this toggle entirely and always uses [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg). Setting `alpha_low`/`alpha_high` also requires this flag to be on first (`LiquidAlphaDisabled` error otherwise). + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name liquid_alpha_enabled +``` + +Boolean — pass true or false: + +``` +btcli sudo set --netuid N --name liquid_alpha_enabled --value true +``` + +## Related + +[`alpha_low`](/docs/hyperparameters/alpha-low), [`alpha_high`](/docs/hyperparameters/alpha-high), [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness), [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled), [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg) diff --git a/docs/hyperparameters/max-allowed-uids.mdx b/docs/hyperparameters/max-allowed-uids.mdx new file mode 100644 index 0000000000..8214de8c50 --- /dev/null +++ b/docs/hyperparameters/max-allowed-uids.mdx @@ -0,0 +1,30 @@ +--- +title: max_allowed_uids +description: Neuron slot capacity of the subnet — registrations beyond it prune the lowest-scoring UID. +--- + +`max_allowed_uids` is the number of neuron slots (UIDs) a subnet has. Subnet owners size it to match how many miners and validators they actually want; participants care because a full subnet means every new registration evicts someone. + +## How it works + +While the neuron count is below `max_allowed_uids`, a registration simply appends a new UID (`append_neuron`). Once full, `get_neuron_to_prune` selects the lowest-emission prunable neuron and `replace_neuron` hands its slot to the entrant (`pallets/subtensor/src/subnets/registration.rs`) — see [`immunity_period`](/docs/hyperparameters/immunity-period) for who is protected. + +Raising the value with `btcli sudo set` is straightforward, but lowering it below the current neuron count is rejected (`MaxAllowedUIdsLessThanCurrentUIds` in `pallets/admin-utils/src/lib.rs`); the setter also enforces the range between the subnet's minimum and the chain-wide cap of 256. To shrink an occupied subnet, use `btcli sudo trim`, which calls `trim_to_max_allowed_uids` (`pallets/subtensor/src/subnets/uids.rs`): it removes the lowest-emission neurons while preserving temporally and owner-immune UIDs, refuses to act if immune UIDs would exceed 80% of the new capacity, then compacts the surviving UIDs to the left. Trimming is heavily rate-limited (about 30 days between trims). + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name max_allowed_uids +``` + +The value is a plain integer slot count: + +``` +btcli sudo set --netuid N --name max_allowed_uids --value 256 +``` + +## Related + +[`immunity_period`](/docs/hyperparameters/immunity-period), [`owner_immune_neuron_limit`](/docs/hyperparameters/owner-immune-neuron-limit), [`serving_rate_limit`](/docs/hyperparameters/serving-rate-limit), [`min_burn`](/docs/hyperparameters/min-burn), [`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) diff --git a/docs/hyperparameters/max-burn.mdx b/docs/hyperparameters/max-burn.mdx new file mode 100644 index 0000000000..b3d8aeb0b8 --- /dev/null +++ b/docs/hyperparameters/max-burn.mdx @@ -0,0 +1,53 @@ +--- +title: max_burn +description: Ceiling for the burned-registration cost, in rao. +--- + +Caps how expensive a burned registration can get, no matter how many +registrations pile in. Miners care because it bounds their worst-case entry +cost during a registration rush; owners tune it to decide how hard a rush +should be throttled by price. + +## How it works + +The burn price moves in two ways, and both are clamped into +`[min_burn, max_burn]` in `pallets/subtensor/src/subnets/registration.rs`: + +- Each successful registration multiplies the price by + [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) + (`bump_registration_price_after_registration`). Once the product exceeds + `max_burn`, the price is pinned at `max_burn` — further registrations in the + same burst cost exactly `max_burn` each. +- Each block, the price decays exponentially with half-life + [`burn_half_life`](/docs/hyperparameters/burn-half-life) + (`update_registration_prices_for_networks`), pulling it back down from the + ceiling toward [`min_burn`](/docs/hyperparameters/min-burn). + +The value lives in `MaxBurn` storage as a rao amount (1 TAO = 1e9 rao); the +chain default is 100 TAO. The owner-set extrinsic (`sudo_set_max_burn` in +`pallets/admin-utils/src/lib.rs`) requires the new value to be **above 0.1 TAO** +(`MaxBurnLowerBound`) and **strictly greater than the subnet's current +`min_burn`**. A low ceiling makes registration cheap but lets bursts through; a +high ceiling makes sustained bursts increasingly expensive. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name max_burn +btcli sudo set --netuid 12 --name max_burn --value 50.0 +``` + +Settable by the subnet owner or root. A value with a decimal point is a TAO +amount (`50.0` = τ50); a plain integer is raw rao. + +## Related + +- [`min_burn`](/docs/hyperparameters/min-burn) — the matching floor +- [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) — how fast a + rush drives the price toward this cap +- [`burn_half_life`](/docs/hyperparameters/burn-half-life) — how fast it comes + back down +- [`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) — the + non-price rate limit diff --git a/docs/hyperparameters/max-difficulty.mdx b/docs/hyperparameters/max-difficulty.mdx new file mode 100644 index 0000000000..571ebc49ca --- /dev/null +++ b/docs/hyperparameters/max-difficulty.mdx @@ -0,0 +1,55 @@ +--- +title: max_difficulty +description: Upper bound for the PoW registration difficulty controller; u64::MAX leaves difficulty unbounded above. +--- + +`max_difficulty` is the ceiling over +[`difficulty`](/docs/hyperparameters/difficulty), the proof-of-work target +for PoW neuron registration. However hot registration demand runs, the +difficulty controller never pushes the PoW price above this value. At +`u64::MAX` the ceiling is effectively removed — difficulty is unbounded +above. Subnet owners tune it to cap how expensive a PoW slot can become +during registration rushes. + +## How it works + +Storage is `MaxDifficulty` in `pallets/subtensor/src/lib.rs`, accessed via +`get_max_difficulty` / `set_max_difficulty` +(`pallets/subtensor/src/utils/misc.rs`). In the classic controller, +difficulty was rescaled each adjustment interval by registration pressure +against the target rate, then clamped to the +\[`min_difficulty`, `max_difficulty`\] band — sustained over-target demand +walked difficulty up until it hit this ceiling. The mainnet default is +`u64::MAX / 4` (`SubtensorInitialMaxDifficulty` in `runtime/src/lib.rs`). + +On the current runtime PoW registration is deprecated — the `register` +extrinsic routes to burned registration and nothing adjusts `difficulty` +between intervals — so this ceiling is dormant. The playground shows the +controller it bounds: + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name max_difficulty +``` + +Owner-settable (the AdminUtils extrinsic `sudo_set_max_difficulty` accepts +the subnet owner or root, inside the admin window and subject to the owner +rate limit): + +``` +btcli sudo set --netuid N --name max_difficulty --value 4611686018427387903 +``` + +The value is a raw u64 difficulty, no human form. + +## Related + +[`difficulty`](/docs/hyperparameters/difficulty) · +[`min_difficulty`](/docs/hyperparameters/min-difficulty) · +[`network_pow_registration_allowed`](/docs/hyperparameters/network-pow-registration-allowed) · +[`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) · +[`adjustment_interval`](/docs/hyperparameters/adjustment-interval) · +[`max_burn`](/docs/hyperparameters/max-burn) diff --git a/docs/hyperparameters/max-regs-per-block.mdx b/docs/hyperparameters/max-regs-per-block.mdx new file mode 100644 index 0000000000..4cc9f1668d --- /dev/null +++ b/docs/hyperparameters/max-regs-per-block.mdx @@ -0,0 +1,56 @@ +--- +title: max_regs_per_block +description: Maximum neuron registrations accepted on a subnet in a single block. +--- + +`max_regs_per_block` caps how many neurons can register on a subnet within +one 12-second block. It is a burst limiter: even when the burn cost is low +and demand spikes, at most this many UIDs can turn over per block, which +protects existing neurons from being pruned en masse in a single block. +Anyone scripting registrations should expect rejections beyond the cap; +root/governance sets it, with a mainnet default of 1 +(`SubtensorInitialMaxRegistrationsPerBlock` in `runtime/src/lib.rs`). + +## How it works + +Each successful registration increments the `RegistrationsThisBlock` +counter (`do_register`, step 11, in +`pallets/subtensor/src/subnets/registration.rs`), and the counter is reset +to zero every block by `update_registration_prices_for_networks` (same +file), which runs in `on_initialize`. + +The cap is checked against that counter in two places: + +- Root registration: `do_root_register` + (`pallets/subtensor/src/coinbase/root.rs`) fails with + `TooManyRegistrationsThisBlock` when the block's registrations reach + `get_max_registrations_per_block`, and additionally caps the interval at + 3 × [`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval). +- The registration validity helper `checked_allowed_register` + (`pallets/subtensor/src/lib.rs`) reports a subnet as closed for the + block once the counter reaches the cap, alongside the + [`registration_allowed`](/docs/hyperparameters/registration-allowed) + gate and the same 3 × target interval cap. + +Because the burn cost also bumps multiplicatively after every registration +in a block ([`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult)), +the price and the cap work together against registration floods. + +## Reading and setting + +``` +btcli sudo get --netuid N --name max_regs_per_block +``` + +Root/governance only: `sudo_set_max_registrations_per_block` in the +AdminUtils pallet requires the root origin and takes a plain integer (u16). +It is not settable by the subnet owner via `btcli sudo set`. + +## Related + +[`registration_allowed`](/docs/hyperparameters/registration-allowed) · +[`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) · +[`immunity_period`](/docs/hyperparameters/immunity-period) · +[`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids) · +[`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) · +[`min_burn`](/docs/hyperparameters/min-burn) diff --git a/docs/hyperparameters/max-validators.mdx b/docs/hyperparameters/max-validators.mdx new file mode 100644 index 0000000000..b6b321a3cc --- /dev/null +++ b/docs/hyperparameters/max-validators.mdx @@ -0,0 +1,48 @@ +--- +title: max_validators +description: Maximum validator permits — only the top-stake neurons up to this count may validate. +--- + +`max_validators` caps how many neurons on a subnet hold a validator permit at +once. Anyone deciding whether their stake is enough to validate on a subnet +needs this number: without a permit, a neuron's weights are ignored and it +earns no dividends. + +## How it works + +Every epoch recomputes permits from scratch +(`pallets/subtensor/src/epoch/run_epoch.rs`): `is_topk_nonzero(&stake, k)` +with `k = MaxAllowedValidators` grants permits to the top-`k` neurons by +stake weight (alpha stake plus TAO stake scaled by `tao_weight`), skipping +zero-stake neurons; the subnet owner's UID is always permitted. The mainnet +default is 128, and the value must not exceed `max_allowed_uids`. + +Losing a permit is immediate and total: non-permitted validators' stake is +masked from the active-stake vector, their weight rows are discarded before +consensus, and their accumulated bonds are cleared — so a validator that +slips out of the top-`k` re-enters later with no bond history. Permits +interact with [`activity_cutoff`](/docs/hyperparameters/activity-cutoff): +holding a permit is necessary but not sufficient, since an inactive permitted +validator is also excluded. See +[Yuma Consensus](/docs/concepts/emissions#yuma-consensus) for where permits +sit in the pipeline. + +## Reading and setting + +Inspect with: + +``` +btcli sudo get --netuid N --name max_validators +``` + +Not settable by the subnet owner — root/governance only +(`sudo_set_max_allowed_validators` in AdminUtils requires the root origin +and enforces the `max_allowed_uids` ceiling). The value is a plain integer. + +## Related + +[`rho`](/docs/hyperparameters/rho) · +[`kappa`](/docs/hyperparameters/kappa) · +[`tempo`](/docs/hyperparameters/tempo) · +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) · +[`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids) diff --git a/docs/hyperparameters/max-weights-limit.mdx b/docs/hyperparameters/max-weights-limit.mdx new file mode 100644 index 0000000000..247b6c4d3b --- /dev/null +++ b/docs/hyperparameters/max-weights-limit.mdx @@ -0,0 +1,46 @@ +--- +title: max_weights_limit +description: Cap on the share of a validator's total weight that any single miner may receive. +--- + +`max_weights_limit` caps how much of a validator's normalized weight can land +on one miner, forcing weight to spread across the pool. It is stored as a u16 +fraction: 65535 means 1.0 — no cap — and, say, 6553 means no miner may hold +more than ~10% of a submission's total weight. + +## How it works + +The check is on the **normalized** distribution, not the raw values. On +submission the chain first max-upscales the u16 values so the largest equals +65535 (`vec_u16_max_upscale_to_u16`), then `max_weight_limited` +(`pallets/subtensor/src/subnets/weights.rs`) sum-normalizes them and rejects +the whole submission with `MaxWeightExceeded` if the largest share exceeds +`max_weights_limit / 65535` (`check_vec_max_limited` in `epoch/math.rs`). A +single self-weight is exempt. + +In the current runtime the enforced limit is pinned: `get_max_weight_limit` +(`pallets/subtensor/src/utils/misc.rs`) is a constant returning `u16::MAX`, so +the on-chain check always passes and there is no extrinsic to change it. The +`MaxWeightsLimit` storage map still exists and is what queries return; the SDK +reads it and `btcli tx set-weights` (the `set_weights` intent) proactively +clips and renormalizes your weights to fit the stored value — redistributing +the excess mass rather than discarding it — and warns when clipping occurs. + + + +## Reading and setting + +```bash +btcli sudo get --netuid N --name max_weights_limit +``` + +Root/governance-only — not settable by the subnet owner. Where a value is +taken, it is a fraction: either the human 0..1 form with a decimal point +(e.g. `0.1`) or the raw integer 0..65535. + +## Related + +- [`min_allowed_weights`](/docs/hyperparameters/min-allowed-weights) — the floor on submission size +- [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) — how often submissions are accepted +- [`commit_reveal_weights_enabled`](/docs/hyperparameters/commit-reveal-weights-enabled) — whether weights go through commit-reveal +- [`kappa`](/docs/hyperparameters/kappa) — consensus clipping applied later, at epoch time diff --git a/docs/hyperparameters/meta.json b/docs/hyperparameters/meta.json new file mode 100644 index 0000000000..d3f36a6779 --- /dev/null +++ b/docs/hyperparameters/meta.json @@ -0,0 +1,46 @@ +{ + "title": "Hyperparameters", + "pages": [ + "index", + "rho", + "kappa", + "immunity-period", + "min-allowed-weights", + "max-weights-limit", + "tempo", + "min-difficulty", + "max-difficulty", + "difficulty", + "weights-version", + "weights-rate-limit", + "adjustment-interval", + "activity-cutoff", + "registration-allowed", + "network-pow-registration-allowed", + "target-regs-per-interval", + "min-burn", + "max-burn", + "bonds-moving-avg", + "max-regs-per-block", + "serving-rate-limit", + "max-validators", + "adjustment-alpha", + "commit-reveal-period", + "commit-reveal-weights-enabled", + "alpha-high", + "alpha-low", + "liquid-alpha-enabled", + "bonds-penalty", + "alpha-sigmoid-steepness", + "min-childkey-take", + "owner-immune-neuron-limit", + "max-allowed-uids", + "burn-increase-mult", + "burn-half-life", + "yuma3-enabled", + "bonds-reset-enabled", + "transfers-enabled", + "owner-cut-enabled", + "owner-cut-auto-lock-enabled" + ] +} diff --git a/docs/hyperparameters/min-allowed-weights.mdx b/docs/hyperparameters/min-allowed-weights.mdx new file mode 100644 index 0000000000..d4b1764738 --- /dev/null +++ b/docs/hyperparameters/min-allowed-weights.mdx @@ -0,0 +1,48 @@ +--- +title: min_allowed_weights +description: Minimum number of distinct weights a validator must include in one weight submission. +--- + +`min_allowed_weights` is the floor on how many miners a validator must score in +a single weight submission. Subnet owners raise it to force validators to +evaluate a broad slice of the miner pool instead of concentrating weight on a +favored few; validators care because a submission with too few entries is +rejected outright. + +## How it works + +`set_weights` validates the submission length in `check_length` +(`pallets/subtensor/src/subnets/weights.rs`). The effective minimum is the +smaller of `min_allowed_weights` and the subnet's current neuron count, so a +freshly launched subnet with 5 neurons and a minimum of 50 still accepts +5-entry submissions. Anything below the effective minimum fails with +`WeightVecLengthIsLow`. A single **self-weight** — one entry naming the +validator's own UID — is exempt, as it is from most weight checks. + +What counts is the number of weights that actually reach the chain. The SDK +quantizes weights to u16 and drops zeros before submitting, then enforces the +minimum on what remains — so `btcli tx set-weights` (the `set_weights` intent) +fails fast client-side with the same rule instead of burning an on-chain +submission. Assigning zero to a miner does not help you meet the minimum. + + + +## Reading and setting + +```bash +btcli sudo get --netuid N --name min_allowed_weights +``` + +Owner-settable; the value is a plain integer count: + +```bash +btcli sudo set --netuid N --name min_allowed_weights --value 8 +``` + +## Related + +- [`max_weights_limit`](/docs/hyperparameters/max-weights-limit) — cap on any single weight in the same submission +- [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) — how often submissions are accepted +- [`weights_version`](/docs/hyperparameters/weights-version) — version gate on submissions +- [`commit_reveal_weights_enabled`](/docs/hyperparameters/commit-reveal-weights-enabled) — whether weights go through commit-reveal +- [`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids) — the pool of UIDs available to weight diff --git a/docs/hyperparameters/min-burn.mdx b/docs/hyperparameters/min-burn.mdx new file mode 100644 index 0000000000..a9d9e93d9f --- /dev/null +++ b/docs/hyperparameters/min-burn.mdx @@ -0,0 +1,48 @@ +--- +title: min_burn +description: Floor for the burned-registration cost, in rao. +--- + +Sets the lowest price a subnet can charge for a burned registration. Miners +watch it because it is the cost of joining a quiet subnet; owners tune it to +keep registration from ever becoming free while still letting the price decay +to something affordable. + +## How it works + +Every block, `update_registration_prices_for_networks` (in +`pallets/subtensor/src/subnets/registration.rs`, run from `block_step`) decays +the current burn price exponentially toward zero — and then clamps it into +`[min_burn, max_burn]`. The same clamp is applied after each registration bumps +the price by [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult). +So with no registrations arriving, the price settles at exactly `min_burn` and +stays there; `min_burn` is the resting price of an idle subnet. + +The value is stored in `MinBurn` as a rao amount (1 TAO = 1e9 rao). The chain +default is 500,000 rao (τ0.0005). The owner-set extrinsic +(`sudo_set_min_burn` in `pallets/admin-utils/src/lib.rs`) enforces two bounds: +the new value must be **below 1 TAO** (`MinBurnUpperBound`) and **strictly less +than the subnet's current `max_burn`**. Registration burns are recycled — they +are subtracted from total issuance and can be re-emitted, which pushes halvings +out (see [emissions](/docs/concepts/emissions)). + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name min_burn +btcli sudo set --netuid 12 --name min_burn --value 0.001 +``` + +Settable by the subnet owner or root. A value with a decimal point is a TAO +amount (`0.001` = τ0.001); a plain integer is raw rao (`1000000` = τ0.001). + +## Related + +- [`max_burn`](/docs/hyperparameters/max-burn) — the matching ceiling +- [`burn_half_life`](/docs/hyperparameters/burn-half-life) — how fast the price + decays back to this floor +- [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) — the bump + per registration +- [`registration_allowed`](/docs/hyperparameters/registration-allowed) diff --git a/docs/hyperparameters/min-childkey-take.mdx b/docs/hyperparameters/min-childkey-take.mdx new file mode 100644 index 0000000000..540cd92962 --- /dev/null +++ b/docs/hyperparameters/min-childkey-take.mdx @@ -0,0 +1,47 @@ +--- +title: min_childkey_take +description: Per-subnet floor on the take a childkey may charge its parent hotkeys. +--- + +Sets the minimum take a childkey can charge on this subnet. It matters to +validators running parent–child hotkey setups +([`set-children`](/docs/tx/set-children)): the take is the share of +child-earned dividends the childkey keeps before passing the rest back to its +parents. A subnet owner can raise this floor to stop childkeys from +undercutting each other to zero. + +## How it works + +The value is stored per subnet as a `PerU16` fraction (65535 = 100%). The +chain combines it with the global, root-set minimum: the **effective floor is +the greater of the two**, so a subnet can only make the global minimum +stricter, never looser. Both defaults are currently 0. + +The floor is enforced in two places. Setting a take via +[`set-childkey-take`](/docs/tx/set-childkey-take) rejects values below the +effective floor (or above the global maximum, 11796/65535 ≈ 18%) with +`InvalidChildkeyTake`. And every read of a childkey's take clamps up to the +floor — so raising it immediately re-prices existing childkeys that were set +lower, without anyone resubmitting. + +The setter itself bounds the floor to the \[global min, global max\] range, so +an owner cannot set a floor above 18%. + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name min_childkey_take +btcli sudo set --netuid 12 --name min_childkey_take --value 0.05 +``` + +Settable by the subnet owner or root. The value is a fraction between 0 and 1 +written with a decimal point (`0.05` = 5%, stored as 3276/65535). The get +command reports the effective floor — the max of global and per-subnet values. + +## Related + +- [`transfers_enabled`](/docs/hyperparameters/transfers-enabled) +- [`owner_cut_enabled`](/docs/hyperparameters/owner-cut-enabled) +- [`set-children`](/docs/tx/set-children) and + [`set-childkey-take`](/docs/tx/set-childkey-take) — the transactions this + floor governs diff --git a/docs/hyperparameters/min-difficulty.mdx b/docs/hyperparameters/min-difficulty.mdx new file mode 100644 index 0000000000..5bcf617a4d --- /dev/null +++ b/docs/hyperparameters/min-difficulty.mdx @@ -0,0 +1,54 @@ +--- +title: min_difficulty +description: Lower bound for the PoW registration difficulty controller; u64::MAX pins difficulty at maximum, disabling PoW registration. +--- + +`min_difficulty` is the floor under +[`difficulty`](/docs/hyperparameters/difficulty), the proof-of-work target +for PoW neuron registration. However cheap registrations get, the +difficulty controller never lets the PoW price fall below this value. +Setting it to `u64::MAX` pins difficulty at maximum, which effectively +disables PoW registration outright. Miners care because it fixes the +minimum compute cost of a PoW slot; root/governance sets it. + +## How it works + +Storage is `MinDifficulty` in `pallets/subtensor/src/lib.rs`, read and +written by `get_min_difficulty` / `set_min_difficulty` +(`pallets/subtensor/src/utils/misc.rs`). In the classic controller, +difficulty was rescaled each adjustment interval by how far registrations +ran over or under target, then clamped to the +\[`min_difficulty`, `max_difficulty`\] band — so with quiet demand, +difficulty decayed until it sat on this floor. + +The chain-wide migration `migrate_set_min_difficulty` +(`pallets/subtensor/src/migrations/migrate_set_min_difficulty.rs`) set the +floor to 10,000,000 on every subnet, matching the runtime default +(`SubtensorInitialMinDifficulty` in `runtime/src/lib.rs`). + +Note that on the current runtime PoW registration is deprecated: the +`register` extrinsic routes to burned registration and no controller +adjusts `difficulty` between intervals, so this floor is dormant. The +playground below shows the controller behavior it bounds — drag the floor +to its top stop to see the `u64::MAX` disabled state: + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name min_difficulty +``` + +Root/governance only: `sudo_set_min_difficulty` in the AdminUtils pallet +requires the root origin and takes a raw u64. It is not settable by the +subnet owner via `btcli sudo set`. + +## Related + +[`difficulty`](/docs/hyperparameters/difficulty) · +[`max_difficulty`](/docs/hyperparameters/max-difficulty) · +[`network_pow_registration_allowed`](/docs/hyperparameters/network-pow-registration-allowed) · +[`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) · +[`adjustment_interval`](/docs/hyperparameters/adjustment-interval) · +[`min_burn`](/docs/hyperparameters/min-burn) diff --git a/docs/hyperparameters/network-pow-registration-allowed.mdx b/docs/hyperparameters/network-pow-registration-allowed.mdx new file mode 100644 index 0000000000..04e21417e8 --- /dev/null +++ b/docs/hyperparameters/network-pow-registration-allowed.mdx @@ -0,0 +1,58 @@ +--- +title: network_pow_registration_allowed +description: Whether proof-of-work registration is allowed, as opposed to burned registration only. +--- + +`network_pow_registration_allowed` is the per-subnet flag that historically +let owners choose whether miners could register by proof-of-work (grinding +nonces against [`difficulty`](/docs/hyperparameters/difficulty)) or only by +burning TAO. Miners reading the metagraph still see the flag, but on the +current runtime it is a deprecated remnant: PoW registration has been +retired chain-wide. + +## How it works + +Storage is `NetworkPowRegistrationAllowed` in +`pallets/subtensor/src/lib.rs`, exposed through the metagraph RPC as +`pow_registration_allowed`. Two pieces of code make its deprecation +concrete: + +- The migration `migrate_clear_deprecated_registration_maps` + (`pallets/subtensor/src/migrations/`) cleared every stored entry, so all + subnets read the storage default. +- The AdminUtils setter `sudo_set_network_pow_registration_allowed` + (`pallets/admin-utils/src/lib.rs`, call index 20) no longer writes + anything — it unconditionally returns the `POWRegistrationDisabled` + error. + +Independently, the PoW `register` extrinsic +(`pallets/subtensor/src/macros/dispatches.rs`) ignores its work arguments +and routes to the burned-registration path, so the flag has nothing left to +gate. The playground shows the difficulty mechanics this toggle used to +switch off: + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name network_pow_registration_allowed +``` + +Nominally owner-settable as a boolean: + +``` +btcli sudo set --netuid N --name network_pow_registration_allowed --value false +``` + +but on the current runtime the underlying extrinsic always fails with +`POWRegistrationDisabled`, so the value cannot actually be changed. + +## Related + +[`registration_allowed`](/docs/hyperparameters/registration-allowed) · +[`difficulty`](/docs/hyperparameters/difficulty) · +[`min_difficulty`](/docs/hyperparameters/min-difficulty) · +[`max_difficulty`](/docs/hyperparameters/max-difficulty) · +[`min_burn`](/docs/hyperparameters/min-burn) · +[`max_burn`](/docs/hyperparameters/max-burn) diff --git a/docs/hyperparameters/owner-cut-auto-lock-enabled.mdx b/docs/hyperparameters/owner-cut-auto-lock-enabled.mdx new file mode 100644 index 0000000000..5db8a9377d --- /dev/null +++ b/docs/hyperparameters/owner-cut-auto-lock-enabled.mdx @@ -0,0 +1,51 @@ +--- +title: owner_cut_auto_lock_enabled +description: Per-subnet toggle that conviction-locks the owner's emission cut as it is paid. +--- + +Controls whether the subnet owner's emission cut is automatically placed under +a [conviction lock](/docs/guides/conviction) the moment it is paid out. It +matters to owners weighing liquidity against conviction, and to lockers +watching the ownership race — an auto-locking owner compounds conviction every +tempo without lifting a finger. + +## How it works + +The flag defaults to **false**. When it is on, each epoch's owner-cut payout is +followed by an automatic `lock-stake` on the owner's coldkey: the freshly +staked alpha is added to the owner's locked mass. If the owner already has a +lock on the subnet, the cut locks toward that lock's existing hotkey (one lock +per coldkey per subnet); otherwise a new lock is created toward the subnet +owner hotkey. A zero cut is silently skipped. + +Locked alpha still earns dividends — the lock is a floor on unstaking, not a +separate bucket — and it accrues conviction, which counts toward the +aggregate-conviction threshold for automatic subnet ownership transfer. Locks +on the owner hotkey mature instantly (conviction equals mass), so an owner +auto-locking toward their own hotkey is defending their seat with fully mature +conviction. Turning the flag off stops future auto-locking but does not +release anything already locked. + +The flag has no effect while +[`owner_cut_enabled`](/docs/hyperparameters/owner-cut-enabled) is off — no cut, +nothing to lock. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name owner_cut_auto_lock_enabled +btcli sudo set --netuid 12 --name owner_cut_auto_lock_enabled --value true +``` + +Settable by the subnet owner or root; booleans take `true` or `false`. Not +permitted on the root subnet. + +## Related + +- [`owner_cut_enabled`](/docs/hyperparameters/owner-cut-enabled) — the cut + this flag locks +- [`transfers_enabled`](/docs/hyperparameters/transfers-enabled) +- [Conviction locks](/docs/guides/conviction) — lock mechanics and ownership + transfer diff --git a/docs/hyperparameters/owner-cut-enabled.mdx b/docs/hyperparameters/owner-cut-enabled.mdx new file mode 100644 index 0000000000..68a057d0b3 --- /dev/null +++ b/docs/hyperparameters/owner-cut-enabled.mdx @@ -0,0 +1,45 @@ +--- +title: owner_cut_enabled +description: Per-subnet toggle for the subnet owner's 18% share of alpha emission. +--- + +Controls whether the subnet owner receives their cut of the subnet's alpha +emission. Owners care because it is their revenue; stakers and miners care +because whatever the owner does not take is redistributed to them. + +## How it works + +The cut percentage itself is a **global, root-set** value (`SubnetOwnerCut`, +11796/65535 ≈ 18%). This flag only decides, per subnet, whether the deduction +happens at all. It defaults to **true**. + +Every block, when the chain accrues the subnet's `alpha_out`, it multiplies it +by the cut percentage, subtracts that from the amount destined for +participants, and accumulates it in a pending bucket. At the next epoch the +pending cut is staked directly to the subnet owner's hotkey and coldkey, while +the remainder goes through Yuma Consensus to miners, validators, and stakers +(see [the per-tempo split](/docs/concepts/emissions#the-per-tempo-split)). + +When the flag is off, no deduction happens: the full `alpha_out` flows to +participants and the owner receives nothing — the forgone cut is not stashed +or paid retroactively. Blocks are settled as they accrue, so flipping the flag +mid-tempo affects only the blocks after the change. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name owner_cut_enabled +btcli sudo set --netuid 12 --name owner_cut_enabled --value false +``` + +Settable by the subnet owner or root; booleans take `true` or `false`. Not +permitted on the root subnet. + +## Related + +- [`owner_cut_auto_lock_enabled`](/docs/hyperparameters/owner-cut-auto-lock-enabled) + — lock the cut as it arrives +- [`transfers_enabled`](/docs/hyperparameters/transfers-enabled) +- [Emissions](/docs/concepts/emissions) — the full per-tempo split diff --git a/docs/hyperparameters/owner-immune-neuron-limit.mdx b/docs/hyperparameters/owner-immune-neuron-limit.mdx new file mode 100644 index 0000000000..b6a2e6a758 --- /dev/null +++ b/docs/hyperparameters/owner-immune-neuron-limit.mdx @@ -0,0 +1,30 @@ +--- +title: owner_immune_neuron_limit +description: How many of the subnet owner's own neurons are permanently immune from pruning. +--- + +`owner_immune_neuron_limit` is the number of neurons registered under the subnet owner's coldkey that can never be pruned, regardless of emission or age. Owners use it to keep their own validator or infrastructure hotkeys safe on a full subnet; everyone else cares because each owner-immune UID is one slot removed from the competition. + +## How it works + +`get_immune_owner_tuples` (`pallets/subtensor/src/subnets/registration.rs`) collects all of the owner coldkey's hotkeys that hold a UID, sorts them by registration block (earliest first, so older keys keep priority), and truncates the list to `owner_immune_neuron_limit`. The subnet owner hotkey itself is inserted at the front of the list if it holds a UID. Both `get_neuron_to_prune` and `trim_to_max_allowed_uids` skip these UIDs entirely — unlike [`immunity_period`](/docs/hyperparameters/immunity-period) immunity, this protection never expires and has no emission-based fallback. + +The limit must stay between 1 and 10 (`set_owner_immune_neuron_limit` in `pallets/subtensor/src/utils/misc.rs` rejects anything outside `MinImmuneOwnerUidsLimit`..`MaxImmuneOwnerUidsLimit` with `InvalidValue`). The default is 1: just the owner's primary hotkey. + + + +## Reading and setting + +``` +btcli sudo get --netuid N --name owner_immune_neuron_limit +``` + +The value is a plain integer between 1 and 10: + +``` +btcli sudo set --netuid N --name owner_immune_neuron_limit --value 3 +``` + +## Related + +[`immunity_period`](/docs/hyperparameters/immunity-period), [`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids), [`serving_rate_limit`](/docs/hyperparameters/serving-rate-limit) diff --git a/docs/hyperparameters/registration-allowed.mdx b/docs/hyperparameters/registration-allowed.mdx new file mode 100644 index 0000000000..9f0dabe9c6 --- /dev/null +++ b/docs/hyperparameters/registration-allowed.mdx @@ -0,0 +1,49 @@ +--- +title: registration_allowed +description: Whether new neuron registrations are currently accepted on this subnet. +--- + +`registration_allowed` is the master on/off switch for joining a subnet. +When it is false, every neuron registration — burned or the legacy PoW +entry point — is rejected, no matter how much TAO the caller is willing to +burn. Prospective miners and validators should check it before attempting +to register; it is a root/governance-controlled gate, typically used to +close a subnet during incidents or before launch. + +## How it works + +Storage is `NetworkRegistrationAllowed` in `pallets/subtensor/src/lib.rs` +(default true; new subnets also set it explicitly to true during +initialization in `pallets/subtensor/src/subnets/subnet.rs`). The +gate is enforced at step 3 of `do_register` +(`pallets/subtensor/src/subnets/registration.rs`): the extrinsic fails with +`SubNetRegistrationDisabled` if `get_network_registration_allowed` returns +false. Both `burned_register` and the legacy PoW `register` extrinsic land +in `do_register`, so the flag closes every registration path at once. The +validity helper `checked_allowed_register` (`pallets/subtensor/src/lib.rs`) +applies the same check, alongside the per-block cap +([`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block)) and the +per-interval cap of 3 × +[`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval). + +Note the flag only stops new registrations; already-registered neurons are +unaffected, and pruning/immunity mechanics continue as normal. + +## Reading and setting + +``` +btcli sudo get --netuid N --name registration_allowed +``` + +Root/governance only: `sudo_set_network_registration_allowed` in the +AdminUtils pallet requires the root origin (a boolean). It is not settable +by the subnet owner via `btcli sudo set`. + +## Related + +[`network_pow_registration_allowed`](/docs/hyperparameters/network-pow-registration-allowed) · +[`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) · +[`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) · +[`min_burn`](/docs/hyperparameters/min-burn) · +[`max_burn`](/docs/hyperparameters/max-burn) · +[`immunity_period`](/docs/hyperparameters/immunity-period) diff --git a/docs/hyperparameters/rho.mdx b/docs/hyperparameters/rho.mdx new file mode 100644 index 0000000000..3e2e5112d8 --- /dev/null +++ b/docs/hyperparameters/rho.mdx @@ -0,0 +1,57 @@ +--- +title: rho +description: Steepness of the classic Yuma trust sigmoid mapping consensus alignment to trust. +--- + +`rho` sets the temperature (steepness) of the sigmoid that maps a validator's +consensus alignment to trust in the classic Yuma Consensus formulation. Subnet +owners tuning how sharply the network rewards agreement with consensus are the +main audience. + +## How it works + +The formula lives in `sigmoid_safe` (`pallets/subtensor/src/epoch/math.rs`): + +``` +trust = 1 / (1 + e^(−rho × (x − kappa))) +``` + +where `x` is the stake fraction aligned with a validator's view and +[`kappa`](/docs/hyperparameters/kappa) is the midpoint. Higher `rho` makes the +curve steeper: alignment just above `kappa` maps to trust near 1, just below +to near 0. The recommended range in the code is 0 to 40; the mainnet +default is 10. + +One caveat, straight from the source: the current epoch +(`pallets/subtensor/src/epoch/run_epoch.rs`) computes consensus as the +`kappa`-weighted median of weights and clips to it — the helper that would +feed `rho` into the sigmoid (`get_float_rho`) is defined but not called on +the active path. `rho` remains a stored, owner-settable parameter of the +Yuma formulation, but changing it does not alter today's epoch output. See +[Yuma Consensus](/docs/concepts/emissions#yuma-consensus) for the full +pipeline. + + + +## Reading and setting + +Inspect with: + +``` +btcli sudo get --netuid N --name rho +``` + +Owner-settable: + +``` +btcli sudo set --netuid N --name rho --value 10 +``` + +The value is a plain integer (stored as u16), not a fraction. + +## Related + +[`kappa`](/docs/hyperparameters/kappa) · +[`tempo`](/docs/hyperparameters/tempo) · +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) · +[`max_validators`](/docs/hyperparameters/max-validators) diff --git a/docs/hyperparameters/serving-rate-limit.mdx b/docs/hyperparameters/serving-rate-limit.mdx new file mode 100644 index 0000000000..1cae60d93a --- /dev/null +++ b/docs/hyperparameters/serving-rate-limit.mdx @@ -0,0 +1,28 @@ +--- +title: serving_rate_limit +description: Minimum blocks a neuron must wait between axon (or prometheus) serve calls. +--- + +`serving_rate_limit` is the minimum number of blocks between consecutive `serve_axon` calls from the same neuron on a subnet. Miners care because it caps how often they can republish their IP/port endpoint; owners tune it to keep endpoint churn and extrinsic spam down without blocking legitimate updates. + +## How it works + +When a neuron posts its axon endpoint, `do_serve_axon` (`pallets/subtensor/src/subnets/serving.rs`) checks `axon_passes_rate_limit`: the call is accepted only if `current_block − last_serve_block >= serving_rate_limit`, where `last_serve_block` is stamped on the neuron's stored axon info at each successful serve. A first-ever serve always passes, and setting the parameter to 0 disables the check entirely. Violations fail with `ServingRateLimitExceeded`. The same limit applies independently to `serve_prometheus` via `prometheus_passes_rate_limit`. + +The default is 50 blocks — about 10 minutes at 12-second blocks. Unlike the pruning family of parameters, this one does not affect who keeps a UID, only how frequently a UID's published endpoint can change; a miner that misses the window just retries after the cooldown. + +## Reading and setting + +``` +btcli sudo get --netuid N --name serving_rate_limit +``` + +The value is a plain block count: + +``` +btcli sudo set --netuid N --name serving_rate_limit --value 50 +``` + +## Related + +[`immunity_period`](/docs/hyperparameters/immunity-period), [`max_allowed_uids`](/docs/hyperparameters/max-allowed-uids), [`owner_immune_neuron_limit`](/docs/hyperparameters/owner-immune-neuron-limit), [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) diff --git a/docs/hyperparameters/target-regs-per-interval.mdx b/docs/hyperparameters/target-regs-per-interval.mdx new file mode 100644 index 0000000000..97932f06d2 --- /dev/null +++ b/docs/hyperparameters/target-regs-per-interval.mdx @@ -0,0 +1,57 @@ +--- +title: target_regs_per_interval +description: Registrations per interval the registration controller steers toward; today a hard admission cap. +--- + +Originally the setpoint of the registration-rate controller: the number of +registrations per +[`adjustment_interval`](/docs/hyperparameters/adjustment-interval) the chain +tried to hit by moving burn and difficulty. On the current chain it survives +as a **hard cap**: an interval may admit at most three times this many +registrations. Root-subnet validators hit it most directly. + +## How it works + +The value lives in `TargetRegistrationsPerInterval` storage (u16, default +**2**, so the cap is 6). Two places enforce the 3× cap: + +- `do_root_register` (`pallets/subtensor/src/coinbase/root.rs`) rejects a root + registration with `TooManyRegistrationsThisInterval` once + `RegistrationsThisInterval ≥ 3 × target_regs_per_interval`. The counter + resets on the root subnet's epoch boundary — one "interval" is effectively + one root tempo, and `adjustment_interval` itself is not consulted. +- `checked_allowed_register` (`pallets/subtensor/src/lib.rs`) applies the same + 3× comparison when reporting whether a non-root subnet accepts + registrations; on those subnets pricing is done by the continuous burn + controller ([`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) + and [`burn_half_life`](/docs/hyperparameters/burn-half-life)) rather than by + steering toward this target. + +The legacy EMA adjustment that used this value as a setpoint (together with +[`adjustment_alpha`](/docs/hyperparameters/adjustment-alpha)) no longer exists +in the runtime. + + + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name target_regs_per_interval +``` + +Root/governance only — `sudo_set_target_registrations_per_interval` in +`pallets/admin-utils/src/lib.rs` requires the root origin (plus the admin +freeze window being open), so subnet owners cannot change it. The value is a +plain integer. + +## Related + +- [`adjustment_interval`](/docs/hyperparameters/adjustment-interval) — the + legacy cadence this target was measured over +- [`adjustment_alpha`](/docs/hyperparameters/adjustment-alpha) — the legacy + smoothing factor +- [`max_regs_per_block`](/docs/hyperparameters/max-regs-per-block) — the + per-block admission cap +- [`min_burn`](/docs/hyperparameters/min-burn) / + [`max_burn`](/docs/hyperparameters/max-burn) — the price bounds of the + current controller diff --git a/docs/hyperparameters/tempo.mdx b/docs/hyperparameters/tempo.mdx new file mode 100644 index 0000000000..a987ee333d --- /dev/null +++ b/docs/hyperparameters/tempo.mdx @@ -0,0 +1,48 @@ +--- +title: tempo +description: Blocks per epoch — how often a subnet runs Yuma Consensus and distributes emissions. +--- + +`tempo` is the number of 12-second blocks between a subnet's consensus +epochs. It sets the payout cadence for everyone on the subnet: miners and +validators are paid once per tempo, not per block. + +## How it works + +Each subnet's epoch fires once `tempo` blocks have passed since its last +epoch: `should_run_epoch` (`pallets/subtensor/src/coinbase/run_coinbase.rs`) +checks `current_block − LastEpochBlock ≥ tempo`. The default is 360 blocks +(~72 minutes); at most 2 subnet epochs run per block, with extras deferred, +and the owner can trigger an early epoch. When the epoch fires, the alpha +accumulated since the previous epoch is distributed via +[Yuma Consensus](/docs/concepts/emissions#yuma-consensus); see +[Epochs](/docs/concepts/emissions#epochs) for scheduling details. + +`tempo` also anchors other parameters: the effective +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) is a per-mille +factor multiplied by `tempo`, and commit-reveal delays are counted in tempos. +Setting a new tempo resets the epoch cycle (`apply_tempo_with_cycle_reset` +re-anchors `LastEpochBlock` to the current block), so the next epoch lands a +full tempo after the change. + +## Reading and setting + +Inspect with: + +``` +btcli sudo get --netuid N --name tempo +``` + +Not settable through `btcli sudo set` — root/governance only there +(`sudo_set_tempo` in AdminUtils requires the root origin and accepts any +u16). The subtensor pallet does expose an owner-side `set_tempo` extrinsic, +bounded to 360–50,400 blocks (~72 minutes to ~7 days) and rate-limited, +for owners using raw calls. + +## Related + +[`rho`](/docs/hyperparameters/rho) · +[`kappa`](/docs/hyperparameters/kappa) · +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) · +[`max_validators`](/docs/hyperparameters/max-validators) · +[`commit_reveal_period`](/docs/hyperparameters/commit-reveal-period) diff --git a/docs/hyperparameters/transfers-enabled.mdx b/docs/hyperparameters/transfers-enabled.mdx new file mode 100644 index 0000000000..fd594bcc38 --- /dev/null +++ b/docs/hyperparameters/transfers-enabled.mdx @@ -0,0 +1,44 @@ +--- +title: transfers_enabled +description: Per-subnet toggle allowing stake to be transferred between coldkeys. +--- + +Controls whether staked alpha on this subnet can be moved from one coldkey to +another. It matters to stakers who shift positions between their own wallets or +hand alpha to someone else without unstaking, and to subnet owners who would +rather see alpha change hands only through the pool. + +## How it works + +The flag lives in `TransferToggle` storage and defaults to **true**. It is +checked only on the coldkey-changing path: +[`transfer-stake`](/docs/tx/transfer-stake) validates it and fails with +`TransferDisallowed` when the toggle is off. Moving stake between hotkeys or +subnets under the *same* coldkey ([`move-stake`](/docs/tx/move-stake), +[`swap-stake`](/docs/tx/swap-stake)) never consults the flag, and neither does +ordinary staking or unstaking — disabling transfers does not trap anyone's +stake, it only pins it to its current coldkey. + +For a cross-subnet transfer, **both** the origin and destination subnets must +have transfers enabled. If the transferred stake carries a +[conviction lock](/docs/guides/conviction), the lock follows the stake: locked +mass and conviction move to the destination coldkey in proportion to the amount +transferred. + +## Reading and setting + +```bash +btcli sudo get --netuid 12 --name transfers_enabled +btcli sudo set --netuid 12 --name transfers_enabled --value false +``` + +Settable by the subnet owner or root; booleans take `true` or `false`. + +## Related + +- [`owner_cut_enabled`](/docs/hyperparameters/owner-cut-enabled) — the other + per-subnet economics toggle +- [`min_childkey_take`](/docs/hyperparameters/min-childkey-take) +- [Money](/docs/concepts/money) — how stake, pools, and valuation work +- [Conviction locks](/docs/guides/conviction) — what happens to locked stake + on transfer diff --git a/docs/hyperparameters/weights-rate-limit.mdx b/docs/hyperparameters/weights-rate-limit.mdx new file mode 100644 index 0000000000..bdae7ea88c --- /dev/null +++ b/docs/hyperparameters/weights-rate-limit.mdx @@ -0,0 +1,49 @@ +--- +title: weights_rate_limit +description: Minimum number of blocks a validator must wait between weight submissions on a subnet. +--- + +`weights_rate_limit` (on chain: `WeightsSetRateLimit`) is the cooldown between +a validator's weight submissions, measured in 12-second blocks. The default is +100 blocks (20 minutes). It keeps validators from churning weights every +block, which would bloat chain state and make consensus inputs noisy. + +## How it works + +The chain tracks each UID's last submission block (`LastUpdate`). +`check_rate_limit` (`pallets/subtensor/src/subnets/weights.rs`) passes when +`current_block - last_update >= weights_rate_limit`; a UID that has never +submitted always passes. Too-frequent calls fail with `SettingWeightsTooFast`. + +Which call is limited depends on the commit-reveal setting. With commit-reveal +off, the limit applies to `set_weights` itself. With it on, the limit applies +to the **commit** (failing with `CommittingWeightsTooFast`), and the reveal is +exempt — the commit already paid the cooldown, and updates `LastUpdate` at +commit time. + +Because `LastUpdate` also feeds the [activity +cutoff](/docs/hyperparameters/activity-cutoff), the rate limit bounds how +fresh a validator's weights can be — a subnet's cutoff should comfortably +exceed its rate limit. + +`btcli tx set-weights` (the `set_weights` intent) preflights this check: it +reads `LastUpdate` before signing and, if you are inside the cooldown, fails +immediately with the number of blocks (and approximate seconds) left to wait +instead of submitting a doomed extrinsic. + +## Reading and setting + +```bash +btcli sudo get --netuid N --name weights_rate_limit +``` + +Root/governance-only — not settable by the subnet owner. The value is a plain +block count. + +## Related + +- [`commit_reveal_weights_enabled`](/docs/hyperparameters/commit-reveal-weights-enabled) — decides whether the limit hits set or commit +- [`min_allowed_weights`](/docs/hyperparameters/min-allowed-weights) — the floor on submission size +- [`max_weights_limit`](/docs/hyperparameters/max-weights-limit) — cap on any single weight +- [`activity_cutoff`](/docs/hyperparameters/activity-cutoff) — staleness window fed by the same LastUpdate +- [`tempo`](/docs/hyperparameters/tempo) — how often submitted weights are consumed diff --git a/docs/hyperparameters/weights-version.mdx b/docs/hyperparameters/weights-version.mdx new file mode 100644 index 0000000000..bcecf8e1a5 --- /dev/null +++ b/docs/hyperparameters/weights-version.mdx @@ -0,0 +1,50 @@ +--- +title: weights_version +description: Minimum version key a validator must send with set_weights; a forced-upgrade lever for subnet owners. +--- + +`weights_version` (on chain: `WeightsVersionKey`) is a version gate on weight +submissions. Subnet owners raise it when they ship a breaking change to their +validator code: any validator still running the old software — and therefore +sending an old version key — has its weights rejected until it upgrades. + +## How it works + +Every `set_weights` call carries a `version_key` argument. The chain compares +it in `check_version_key` (`pallets/subtensor/src/subnets/weights.rs`): the +submission passes when the subnet's `WeightsVersionKey` is 0 (the gate is +disabled) or when the submitted key is greater than or equal to it. Otherwise +the call fails with `IncorrectWeightVersionKey`. The value itself is opaque to +the chain — it is a plain u64 counter whose meaning is a convention between +the owner and their validator codebase. + +The key is checked at reveal time too: revealed commit-reveal weights pass +through the same `set_weights` validation, so a version bump between commit +and reveal invalidates in-flight commits. + +The SDK does not preflight this check — `btcli tx set-weights` (the +`set_weights` intent) sends `version_key` 0 unless told otherwise, which only +passes on subnets that leave the gate disabled. Validator code on gated +subnets must pass the current key explicitly. + +Changing it has a dedicated rate limit: the owner may update it at most once +per `WeightsVersionKeyRateLimit` tempos (currently 5). + +## Reading and setting + +```bash +btcli sudo get --netuid N --name weights_version +``` + +Owner-settable; the value is a plain integer: + +```bash +btcli sudo set --netuid N --name weights_version --value 1020 +``` + +## Related + +- [`min_allowed_weights`](/docs/hyperparameters/min-allowed-weights) — the floor on submission size +- [`max_weights_limit`](/docs/hyperparameters/max-weights-limit) — cap on any single weight +- [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) — how often submissions are accepted +- [`commit_reveal_period`](/docs/hyperparameters/commit-reveal-period) — the commit-to-reveal delay the key must survive diff --git a/docs/hyperparameters/yuma3-enabled.mdx b/docs/hyperparameters/yuma3-enabled.mdx new file mode 100644 index 0000000000..8383a5f536 --- /dev/null +++ b/docs/hyperparameters/yuma3-enabled.mdx @@ -0,0 +1,31 @@ +--- +title: yuma3_enabled +description: Enables the Yuma3 consensus variant, which changes how bonds are stored and dividends computed — and unlocks liquid alpha. +--- + +`yuma3_enabled` switches a subnet's epoch from the classic Yuma bond computation to the Yuma3 variant. Subnet owners toggle it to change how validator dividends reward conviction; validators care because it alters both the bond math and whether liquid alpha can apply at all. + +## How it works + +The epoch function branches on `Yuma3On` (`pallets/subtensor/src/epoch/run_epoch.rs`, "Bonds and Dividends" section): + +- **Classic path (off).** Instant bonds `ΔB = W ∘ S` are column-normalized, smoothed by the flat EMA from [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg) (`compute_ema_bonds_normal`), and dividends are `d_i = Σ_j B_ij × I_j`. +- **Yuma3 path (on).** Bonds are read as fixed proportions (`get_bonds_fixed_proportion`) without column normalization, the EMA runs through `compute_bonds` — which is where [`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) can swap in per-pair alpha rates — and dividends are the row-sum of normalized EMA bonds times incentive, scaled by each validator's active stake, then renormalized. + +Practical consequence: liquid alpha and its parameters ([`alpha_low`](/docs/hyperparameters/alpha-low), [`alpha_high`](/docs/hyperparameters/alpha-high), [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness)) only take effect when this flag is on; the classic path never consults them. See the [Yuma Consensus overview](/docs/concepts/emissions#yuma-consensus) for the full epoch pipeline. + +## Reading and setting + +``` +btcli sudo get --netuid N --name yuma3_enabled +``` + +Boolean — pass true or false: + +``` +btcli sudo set --netuid N --name yuma3_enabled --value true +``` + +## Related + +[`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled), [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg), [`bonds_penalty`](/docs/hyperparameters/bonds-penalty), [`bonds_reset_enabled`](/docs/hyperparameters/bonds-reset-enabled) diff --git a/docs/meta.json b/docs/meta.json index 15e19926b0..ca39f3dd31 100644 --- a/docs/meta.json +++ b/docs/meta.json @@ -13,6 +13,7 @@ "tx", "query", "errors", + "hyperparameters", "---Contributing---", "internals" ] diff --git a/website/apps/bittensor-website/scripts/generate.py b/website/apps/bittensor-website/scripts/generate.py index 465a286161..d7552e7415 100644 --- a/website/apps/bittensor-website/scripts/generate.py +++ b/website/apps/bittensor-website/scripts/generate.py @@ -1,10 +1,13 @@ """Generate the docs reference section from the SDK's own registries. -Everything under docs/tx, docs/query, docs/errors.mdx (in the repo-root docs -folder) and public/catalog/ is emitted by this script — never hand-edited. The inputs -are the same registries that generate the CLI (`bittensor.intents.REGISTRY`, -`bittensor.reads.REGISTRY`) and the error taxonomy (`bittensor.error_map`, -`bittensor.result`), so the docs cannot drift from the code. +Everything under docs/tx, docs/query, docs/errors.mdx, and the hyperparameters +index/meta (in the repo-root docs folder) plus public/catalog/ is emitted by +this script — never hand-edited (the per-hyperparameter explainer pages in +docs/hyperparameters/ are hand-written; --check verifies one exists per +parameter). The inputs are the same registries that generate the CLI +(`bittensor.intents.REGISTRY`, `bittensor.reads.REGISTRY`), the error taxonomy +(`bittensor.error_map`, `bittensor.result`), and the hyperparameter semantics +table (`bittensor.hyperparams`), so the docs cannot drift from the code. Usage (from sdk/python, whose environment provides the bittensor SDK): @@ -24,8 +27,9 @@ from dataclasses import MISSING, fields from pathlib import Path -from bittensor import error_descriptions, error_map, result +from bittensor import error_descriptions, error_map, hyperparams, result from bittensor.intents import REGISTRY as INTENTS +from bittensor.intents.hyperparameters import OWNER_HYPERPARAMETERS from bittensor.intents.registry import list_tools from bittensor.namespaces import NAMESPACES from bittensor.reads import REGISTRY as READS @@ -478,6 +482,60 @@ def errors_page() -> str: return "\n".join(parts) +# --- Hyperparameters page --------------------------------------------------- + +# Unit kind -> the label the docs table shows for it. +UNIT_LABELS = { + "u16": "fraction (u16, 65535 = 1.0)", + "u64": "fraction (u64, u64::MAX = 1.0)", + "per_million": "fraction (1,000,000 = 1.0)", + "rao": "TAO amount in rao", + "blocks": "blocks (12s)", + "epochs": "epochs (tempos)", + "difficulty": "PoW difficulty (u64)", + "fixed128": "multiplier (U64F64 bits / 2^64)", + "int": "integer", + "bool": "flag", +} + + +def hyperparameters_index() -> str: + """The overview table; each parameter links to its hand-written explainer + page (docs/hyperparameters/.mdx, checked for existence by --check).""" + header = frontmatter( + "Hyperparameters", + "What each subnet hyperparameter controls, its unit, and how to change it.", + ) + parts = [ + header, + "Read them with `btcli sudo get --netuid N` (the " + "[`subnet_hyperparameters`](/docs/query/subnet-hyperparameters) read); the " + "subnet owner changes the owner-settable ones with `btcli sudo set` (the " + "[`set_hyperparameter`](/docs/tx/set-hyperparameter) intent). Raw on-chain " + "integers are primary; where a parameter is a fixed-point fraction or a rao " + "amount, the value also accepts the human form with a decimal point. " + "Each parameter has its own explainer page.\n", + "| Hyperparameter | Unit | Owner-settable | What it controls |", + "| --- | --- | --- | --- |", + ] + for name, meta in hyperparams.HYPERPARAMS.items(): + settable = "yes" if name in OWNER_HYPERPARAMETERS else "root only" + unit = UNIT_LABELS[hyperparams.kind_of(name)] + parts.append( + f"| [`{name}`](/docs/hyperparameters/{kebab(name)}) | {unit} | " + f"{settable} | {cell(meta.short)} |" + ) + parts.append("") + return "\n".join(parts) + + +def hyperparameters_meta() -> dict: + return { + "title": "Hyperparameters", + "pages": ["index", *(kebab(name) for name in hyperparams.HYPERPARAMS)], + } + + # --- Catalogs -------------------------------------------------------------- @@ -546,6 +604,14 @@ def generate(content_root: Path) -> None: shutil.rmtree(dest) src.rename(dest) (content_root / "errors.mdx").write_text(errors) + # Only the index and meta are generated: the per-parameter explainer + # pages in this folder are hand-written and left untouched. + hyperparams_dir = content_root / "hyperparameters" + hyperparams_dir.mkdir(exist_ok=True) + (hyperparams_dir / "index.mdx").write_text(hyperparameters_index()) + (hyperparams_dir / "meta.json").write_text( + json.dumps(hyperparameters_meta(), indent=2) + "\n" + ) def check() -> int: @@ -576,6 +642,11 @@ def check() -> int: for committed in sorted(committed_dir.rglob("*")): if committed.is_file() and not (tmp_content / committed.relative_to(CONTENT)).exists(): stale.append(str(committed)) + # Every hyperparameter must have its hand-written explainer page. + for name in hyperparams.HYPERPARAMS: + page = CONTENT / "hyperparameters" / f"{kebab(name)}.mdx" + if not page.exists(): + stale.append(f"{page} (missing explainer page)") if stale: print("Generated docs are stale; run scripts/generate.py:", file=sys.stderr) for path in stale: @@ -594,7 +665,10 @@ def main() -> int: generate(CONTENT) write_catalogs(CATALOG) n_tx, n_q = len(INTENTS), len(READS) - print(f"Generated {n_tx} tx pages, {n_q} query pages, errors.mdx, and 3 catalogs.") + print( + f"Generated {n_tx} tx pages, {n_q} query pages, errors.mdx, " + "the hyperparameters index, and 3 catalogs." + ) return 0 diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx new file mode 100644 index 0000000000..7be8c38113 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx @@ -0,0 +1,243 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + LogarithmicScale, + PointElement, + LineElement, + Filler, + Tooltip, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register( + CategoryScale, + LinearScale, + LogarithmicScale, + PointElement, + LineElement, + Filler, + Tooltip, +); + +const BLOCKS_PER_DAY = 7200; // 12s blocks +const SIM_BLOCKS = BLOCKS_PER_DAY; // 24h window +const SAMPLE_EVERY = 12; +const INITIAL_BURN_TAO = 0.1; // chain's InitialBurn (100_000_000 rao) + +function formatTao(value: number): string { + if (value >= 1000) return `τ${value.toFixed(0)}`; + if (value >= 1) return `τ${value.toFixed(2)}`; + return `τ${value.toPrecision(3)}`; +} + +function sliderClass(focused: boolean): string { + return focused + ? 'border-l-2 border-[var(--bt-fg)] pl-3' + : 'border-l-2 border-transparent pl-3'; +} + +export function HyperparamBurnController({ focus }: { focus?: string }) { + const [minBurn, setMinBurn] = useState(0.0005); + const [maxBurn, setMaxBurn] = useState(100); + const [mult, setMult] = useState(1.26); + const [halfLife, setHalfLife] = useState(360); + const [regsPerDay, setRegsPerDay] = useState(20); + const [manualRegs, setManualRegs] = useState(0); + + const sim = useMemo(() => { + const effMax = Math.max(maxBurn, minBurn); + const decay = Math.pow(0.5, 1 / halfLife); + const clamp = (v: number) => Math.min(Math.max(v, minBurn), effMax); + + let burn = clamp(INITIAL_BURN_TAO); + // "Register now" bumps land at the start of the window. + for (let i = 0; i < manualRegs; i++) burn = clamp(burn * mult); + + const xs: number[] = [0]; + const ys: number[] = [burn]; + let peak = burn; + let regsSoFar = 0; + + for (let b = 1; b <= SIM_BLOCKS; b++) { + burn = clamp(burn * decay); + const due = Math.floor((b * regsPerDay) / BLOCKS_PER_DAY); + while (regsSoFar < due) { + burn = clamp(burn * mult); + regsSoFar++; + } + if (burn > peak) peak = burn; + if (b % SAMPLE_EVERY === 0) { + xs.push(b); + ys.push(burn); + } + } + + return { xs, ys, peak, final: burn }; + }, [minBurn, maxBurn, mult, halfLife, regsPerDay, manualRegs]); + + // Rate at which per-registration bumps exactly cancel the decay: + // mult * 0.5^(gap / half_life) = 1 => gap = half_life * log2(mult). + const breakEven = mult > 1 ? BLOCKS_PER_DAY / (halfLife * Math.log2(mult)) : Infinity; + + const data = useMemo( + () => ({ + labels: sim.xs.map((b) => `${(b / 300).toFixed(1)}h`), + datasets: [ + { + label: 'Burn cost (τ)', + data: sim.ys, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + ], + }), + [sim], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `${((sim.xs[idx] ?? 0) / 300).toFixed(1)}h in`; + }, + label: (ctx: { parsed: { y: number } }) => formatTao(ctx.parsed.y), + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { maxTicksLimit: 8, font: { family: 'FiraCode, monospace', size: 10 } }, + }, + y: { + type: 'logarithmic' as const, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { + maxTicksLimit: 6, + font: { family: 'FiraCode, monospace', size: 10 }, + callback: (value: string | number) => formatTao(Number(value)), + }, + title: { display: true, text: 'burn (τ, log)', font: { size: 11 } }, + }, + }, + }), + [sim.xs], + ); + + return ( + +
+ +
+ +
+ + {manualRegs > 0 && ( + + )} + + Each click adds a registration at the start of the window. + +
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx new file mode 100644 index 0000000000..b678dd5c1d --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx @@ -0,0 +1,140 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Filler, + Tooltip, + Legend, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip, Legend); + +const SAMPLE_POINTS = 100; +const KAPPA_U16_MAX = 65535; + +// Matches sigmoid_safe in pallets/subtensor/src/epoch/math.rs: +// 1 / (1 + exp(-rho * (input - kappa))) +function trustSigmoid(input: number, rho: number, kappa: number): number { + return 1 / (1 + Math.exp(-rho * (input - kappa))); +} + +export function HyperparamConsensusSigmoid({ focus }: { focus?: string }) { + const [rho, setRho] = useState(10); + const [kappa, setKappa] = useState(0.5); + + const label = (name: string, hint: string) => + (focus === name ? '▸ ' : '') + `${name} (${hint})`; + + const xs = useMemo( + () => Array.from({length: SAMPLE_POINTS + 1}, (_, i) => i / SAMPLE_POINTS), + [], + ); + const ys = useMemo(() => xs.map((x) => trustSigmoid(x, rho, kappa)), [xs, rho, kappa]); + + const data = useMemo( + () => ({ + labels: xs.map((x) => x.toFixed(2)), + datasets: [ + { + label: 'Trust', + data: ys, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + ], + }), + [xs, ys], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: {mode: 'index' as const, intersect: false}, + plugins: { + legend: {display: false}, + tooltip: { + callbacks: { + title: (items: {dataIndex: number}[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `Alignment ${(xs[idx] ?? 0).toFixed(2)}`; + }, + label: (ctx: {parsed: {y: number}}) => `trust ${ctx.parsed.y.toFixed(4)}`, + }, + }, + }, + scales: { + x: { + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {maxTicksLimit: 11, font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'consensus alignment (stake fraction)', font: {size: 11}}, + }, + y: { + min: 0, + max: 1, + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'trust', font: {size: 11}}, + }, + }, + }), + [xs], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ + +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx new file mode 100644 index 0000000000..d33dfaba44 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx @@ -0,0 +1,214 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Filler, + Tooltip, + Legend, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip, Legend); + +const SAMPLE_POINTS = 100; +// Chain floor for alpha_low/alpha_high: u16::MAX / 40 = 1638 ≈ 0.025. +const ALPHA_FLOOR = 0.025; + +// Mirrors Pallet::alpha_sigmoid in pallets/subtensor/src/epoch/run_epoch.rs: +// sigmoid = 1 / (1 + e^(-(steepness/100) * (diff - 0.5))), alpha clamped to [low, high]. +function alphaSigmoid(diff: number, low: number, high: number, steepness: number): number { + const sigmoid = 1 / (1 + Math.exp((-steepness / 100) * (diff - 0.5))); + const alpha = low + sigmoid * (high - low); + return Math.min(Math.max(alpha, low), high); +} + +export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { + const [enabled, setEnabled] = useState(true); + const [alphaLow, setAlphaLow] = useState(0.7); + const [alphaHigh, setAlphaHigh] = useState(0.9); + const [steepness, setSteepness] = useState(1000); + const [bondsMovingAvg, setBondsMovingAvg] = useState(0.9); + + // Flat EMA rate used when liquid alpha is off: 1 - bonds_moving_avg / 1e6. + const flatAlpha = 1 - bondsMovingAvg; + + // The chain forbids alpha_low > alpha_high, so the sliders drag each other. + const changeLow = (v: number) => { + setAlphaLow(v); + if (v > alphaHigh) setAlphaHigh(v); + }; + const changeHigh = (v: number) => { + setAlphaHigh(v); + if (v < alphaLow) setAlphaLow(v); + }; + + const curve = useMemo(() => { + const xs = Array.from({ length: SAMPLE_POINTS + 1 }, (_, i) => i / SAMPLE_POINTS); + const ys = xs.map((x) => (enabled ? alphaSigmoid(x, alphaLow, alphaHigh, steepness) : flatAlpha)); + return { xs, ys }; + }, [enabled, alphaLow, alphaHigh, steepness, flatAlpha]); + + const data = useMemo( + () => ({ + labels: curve.xs.map((x) => x.toFixed(2)), + datasets: [ + { + label: enabled ? 'per-pair EMA rate (liquid alpha)' : 'flat EMA rate (bonds_moving_avg)', + data: curve.ys, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + ...(enabled + ? [ + { + label: 'flat rate if disabled', + data: curve.xs.map(() => flatAlpha), + borderColor: 'rgba(41, 41, 41, 0.35)', + borderDash: [4, 4], + fill: false, + tension: 0, + pointRadius: 0, + borderWidth: 1, + }, + ] + : []), + ], + }), + [curve, enabled, flatAlpha], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `deviation ${curve.xs[idx]?.toFixed(2)}`; + }, + label: (ctx: { parsed: { y: number } }) => `alpha ${ctx.parsed.y.toFixed(3)}`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { maxTicksLimit: 11, font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'deviation from consensus (combined_diff)', font: { size: 11 } }, + }, + y: { + min: 0, + max: 1, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'bonds EMA rate (alpha)', font: { size: 11 } }, + }, + }, + }), + [curve.xs], + ); + + const focusClass = (name: string) => (focus === name ? 'border border-line bg-bg p-3' : ''); + + return ( + +
+ +
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx new file mode 100644 index 0000000000..cd0711b198 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx @@ -0,0 +1,156 @@ +'use client'; + +import { useState } from 'react'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +const OWNER_CUT_FRACTION = 11_796 / 65_535; // SubnetOwnerCut default, ≈18% + +function formatAlpha(value: number): string { + return `${value.toFixed(1)} α`; +} + +function ToggleRow({ + label, + checked, + onChange, + highlighted, +}: { + label: string; + checked: boolean; + onChange: (checked: boolean) => void; + highlighted: boolean; +}) { + return ( + + ); +} + +function BarSegment({ + fraction, + label, + background, +}: { + fraction: number; + label: string; + background: string; +}) { + return ( +
+ {fraction > 0.08 && ( + + {label} + + )} +
+ ); +} + +export function HyperparamOwnerCut({ focus }: { focus?: string }) { + const [tempoAlpha, setTempoAlpha] = useState(360); + const [ownerCutEnabled, setOwnerCutEnabled] = useState(true); + const [autoLockEnabled, setAutoLockEnabled] = useState(false); + + const ownerCut = ownerCutEnabled ? tempoAlpha * OWNER_CUT_FRACTION : 0; + const ownerLocked = autoLockEnabled ? ownerCut : 0; + const ownerLiquid = ownerCut - ownerLocked; + const remainder = tempoAlpha - ownerCut; + const miners = remainder / 2; + const validators = remainder / 2; + + const total = tempoAlpha > 0 ? tempoAlpha : 1; + + return ( + +
+ {ownerLiquid > 0 && ( + + )} + {ownerLocked > 0 && ( + + )} + + +
+ +
+ + + +
+ +
+ + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx new file mode 100644 index 0000000000..d31ed65914 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx @@ -0,0 +1,221 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LogarithmicScale, + PointElement, + LineElement, + Tooltip, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LogarithmicScale, PointElement, LineElement, Tooltip); + +const U64_MAX = 2 ** 64; +// Slider positions are log10(difficulty); the top position stands for u64::MAX. +const DISABLED_LOG = 20; +const INTERVALS = 48; +const START_DIFFICULTY = 10_000_000; // chain default (InitialDifficulty) + +function fromLog(log: number): number { + return log >= DISABLED_LOG ? U64_MAX : 10 ** log; +} + +function formatDifficulty(value: number): string { + if (value >= U64_MAX) return 'u64::MAX'; + if (value >= 1_000_000) return value.toExponential(1).replace('e+', 'e'); + return Math.round(value).toLocaleString(); +} + +function clamp(value: number, lo: number, hi: number): number { + return Math.min(Math.max(value, lo), hi); +} + +export function HyperparamPowDifficulty({ focus }: { focus?: string }) { + const [floorLog, setFloorLog] = useState(7); // min_difficulty = 1e7 (chain default) + const [ceilLog, setCeilLog] = useState(16); + const [regsPerInterval, setRegsPerInterval] = useState(6); + const [targetRegs, setTargetRegs] = useState(2); + + const floor = fromLog(floorLog); + const ceiling = Math.max(fromLog(ceilLog), floor); + const powDisabled = floor >= U64_MAX; + + const mark = (param: string, label: string) => (focus === param ? `${label} \u2190 this page` : label); + + const series = useMemo(() => { + const points: number[] = []; + let difficulty = clamp(START_DIFFICULTY, floor, ceiling); + for (let i = 0; i <= INTERVALS; i++) { + points.push(difficulty); + // Classic controller step: difficulty *= (regs + target) / (2 * target), + // clamped to [min_difficulty, max_difficulty]. + const ratio = (regsPerInterval + targetRegs) / (2 * targetRegs); + difficulty = clamp(difficulty * ratio, floor, ceiling); + } + return points; + }, [floor, ceiling, regsPerInterval, targetRegs]); + + const finalDifficulty = series[series.length - 1]; + + const trend = powDisabled + ? 'PoW disabled' + : regsPerInterval > targetRegs + ? finalDifficulty >= ceiling + ? 'pinned at ceiling' + : 'rising toward ceiling' + : regsPerInterval < targetRegs + ? finalDifficulty <= floor + ? 'pinned at floor' + : 'falling toward floor' + : 'steady at target'; + + const data = useMemo( + () => ({ + labels: series.map((_, i) => `${i}`), + datasets: [ + { + label: 'difficulty', + data: series, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: false, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + { + label: 'min_difficulty (floor)', + data: series.map(() => floor), + borderColor: 'rgba(41, 41, 41, 0.35)', + borderDash: [4, 4], + fill: false, + pointRadius: 0, + borderWidth: 1, + }, + { + label: 'max_difficulty (ceiling)', + data: series.map(() => ceiling), + borderColor: 'rgba(41, 41, 41, 0.35)', + borderDash: [2, 3], + fill: false, + pointRadius: 0, + borderWidth: 1, + }, + ], + }), + [series, floor, ceiling], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => `Interval ${items[0]?.dataIndex ?? 0}`, + label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => + `${ctx.dataset.label ?? ''}: ${formatDifficulty(ctx.parsed.y)}`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { maxTicksLimit: 8, font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'adjustment intervals', font: { size: 11 } }, + }, + y: { + type: 'logarithmic' as const, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { + font: { family: 'FiraCode, monospace', size: 10 }, + callback: (value: string | number) => formatDifficulty(Number(value)), + maxTicksLimit: 6, + }, + }, + }, + }), + [], + ); + + return ( + +
+ +
+ +
+ + + targetRegs + ? 'over target: difficulty ratchets up' + : regsPerInterval < targetRegs + ? 'under target: difficulty decays down' + : 'on target: difficulty holds' + } + /> +
+ +
+ + = U64_MAX ? 'u64::MAX = unbounded' : formatDifficulty(ceiling)} + onChange={setCeilLog} + /> + + +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx new file mode 100644 index 0000000000..6e1ded96a0 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx @@ -0,0 +1,320 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +// Chain default is 10 (MinNonImmuneUids); scaled down to suit the small demo grid. +const MIN_NON_IMMUNE = 2; +const INITIAL_MAX_UIDS = 32; +const DEFAULT_IMMUNITY = 6; +const DEFAULT_OWNER_LIMIT = 1; + +type Slot = { + id: number; + registeredAt: number; + emission: number; + isOwner: boolean; +}; + +type SimEvent = + | { kind: 'append'; uid: number } + | { kind: 'replace'; uid: number } + | { kind: 'trim'; removed: number } + | { kind: 'fail' }; + +type Sim = { + tick: number; + nextId: number; + slots: Slot[]; + lastEvent: SimEvent | null; +}; + +// Deterministic per-neuron earning rate so server and client render identically. +function rateOf(id: number): number { + const hash = (Math.imul(id + 1, 2654435761) >>> 0) % 887; + return 0.1 + (hash / 887) * 0.9; +} + +function makeInitialSim(): Sim { + const count = INITIAL_MAX_UIDS; + const tick = count + 2; + const slots: Slot[] = Array.from({ length: count }, (_, i) => ({ + id: i, + registeredAt: i, + emission: Math.round(rateOf(i) * (tick - i) * 10) / 10, + // Two owner hotkeys so the owner_immune_neuron_limit slider visibly matters. + isOwner: i === 0 || i === 5, + })); + return { tick, nextId: count, slots, lastEvent: null }; +} + +// Mirrors get_immune_owner_tuples: owner hotkeys sorted by registration block +// (earliest first), truncated to the limit. +function ownerImmuneUids(slots: Slot[], limit: number): Set { + const owners = slots + .map((slot, uid) => ({ uid, slot })) + .filter(({ slot }) => slot.isOwner) + .sort((a, b) => a.slot.registeredAt - b.slot.registeredAt || a.uid - b.uid); + return new Set(owners.slice(0, limit).map(({ uid }) => uid)); +} + +type Candidate = { uid: number; emission: number; registeredAt: number }; + +function beats(a: Candidate, b: Candidate | null): boolean { + if (b === null) return true; + if (a.emission !== b.emission) return a.emission < b.emission; + if (a.registeredAt !== b.registeredAt) return a.registeredAt < b.registeredAt; + return a.uid < b.uid; +} + +// Mirrors get_neuron_to_prune: lowest emission wins, ties broken by older +// registration then lower uid; owner-immune uids are skipped entirely; falls +// back to immune uids when few non-immune uids remain. +function pruneTarget( + slots: Slot[], + tick: number, + immunityPeriod: number, + ownerImmune: Set, +): number | null { + let bestFree: Candidate | null = null; + let bestImmune: Candidate | null = null; + let freeCount = 0; + slots.forEach((slot, uid) => { + if (ownerImmune.has(uid)) return; + const candidate: Candidate = { uid, emission: slot.emission, registeredAt: slot.registeredAt }; + if (tick - slot.registeredAt < immunityPeriod) { + if (beats(candidate, bestImmune)) bestImmune = candidate; + } else { + freeCount += 1; + if (beats(candidate, bestFree)) bestFree = candidate; + } + }); + if (freeCount > MIN_NON_IMMUNE && bestFree !== null) return (bestFree as Candidate).uid; + return bestImmune !== null ? (bestImmune as Candidate).uid : null; +} + +function eventMessage(event: SimEvent | null): string { + if (event === null) return 'Press a register button to add a neuron.'; + switch (event.kind) { + case 'append': + return `Appended as uid ${event.uid} — the subnet was not yet full.`; + case 'replace': + return `Subnet full — pruned uid ${event.uid} (lowest emission among prunable uids) and reused its slot.`; + case 'trim': + return `Trimmed ${event.removed} lowest-emission non-immune neuron${event.removed === 1 ? '' : 's'} (like btcli sudo trim).`; + case 'fail': + return 'Registration failed: every candidate is immune (NoNeuronIdAvailable).'; + default: { + const exhaustive: never = event; + return exhaustive; + } + } +} + +export function HyperparamUidLifecycle({ focus }: { focus?: string }) { + const [maxUids, setMaxUids] = useState(INITIAL_MAX_UIDS); + const [immunityPeriod, setImmunityPeriod] = useState(DEFAULT_IMMUNITY); + const [ownerLimit, setOwnerLimit] = useState(DEFAULT_OWNER_LIMIT); + const [sim, setSim] = useState(makeInitialSim); + + const register = (asOwner: boolean) => { + setSim((prev) => { + const tick = prev.tick + 1; + // Every incumbent accrues emission at its own rate before the new + // registration is processed, so weak neurons drift to the bottom. + const grown = prev.slots.map((slot) => ({ + ...slot, + emission: Math.round((slot.emission + rateOf(slot.id)) * 10) / 10, + })); + const entrant: Slot = { id: prev.nextId, registeredAt: tick, emission: 0, isOwner: asOwner }; + if (grown.length < maxUids) { + return { + tick, + nextId: prev.nextId + 1, + slots: [...grown, entrant], + lastEvent: { kind: 'append', uid: grown.length }, + }; + } + const target = pruneTarget(grown, tick, immunityPeriod, ownerImmuneUids(grown, ownerLimit)); + if (target === null) { + return { ...prev, tick, slots: grown, lastEvent: { kind: 'fail' } }; + } + return { + tick, + nextId: prev.nextId + 1, + slots: grown.map((slot, uid) => (uid === target ? entrant : slot)), + lastEvent: { kind: 'replace', uid: target }, + }; + }); + }; + + // Lowering capacity below the filled count trims the lowest emitters while + // preserving immune uids, mirroring trim_to_max_allowed_uids. + const changeMaxUids = (value: number) => { + setMaxUids(value); + setSim((prev) => { + if (prev.slots.length <= value) return prev; + const ownerSet = ownerImmuneUids(prev.slots, ownerLimit); + const removed = prev.slots + .map((slot, uid) => ({ uid, slot })) + .filter(({ uid, slot }) => !ownerSet.has(uid) && prev.tick - slot.registeredAt >= immunityPeriod) + .sort((a, b) => a.slot.emission - b.slot.emission) + .slice(0, prev.slots.length - value) + .map(({ uid }) => uid); + if (removed.length === 0) return prev; + const removeSet = new Set(removed); + return { + ...prev, + slots: prev.slots.filter((_, uid) => !removeSet.has(uid)), + lastEvent: { kind: 'trim', removed: removed.length }, + }; + }); + }; + + const reset = () => { + setSim(makeInitialSim()); + setMaxUids(INITIAL_MAX_UIDS); + setImmunityPeriod(DEFAULT_IMMUNITY); + setOwnerLimit(DEFAULT_OWNER_LIMIT); + }; + + const ownerImmune = useMemo( + () => ownerImmuneUids(sim.slots, ownerLimit), + [sim.slots, ownerLimit], + ); + + // Exact preview of what the next registration would prune. + const nextPrune = useMemo(() => { + if (sim.slots.length < maxUids) return null; + const tick = sim.tick + 1; + const grown = sim.slots.map((slot) => ({ ...slot, emission: slot.emission + rateOf(slot.id) })); + return pruneTarget(grown, tick, immunityPeriod, ownerImmuneUids(grown, ownerLimit)); + }, [sim, maxUids, immunityPeriod, ownerLimit]); + + const newImmuneCount = sim.slots.filter( + (slot, uid) => !ownerImmune.has(uid) && sim.tick - slot.registeredAt < immunityPeriod, + ).length; + const maxEmission = Math.max(...sim.slots.map((slot) => slot.emission), 0.001); + const lastTouched = + sim.lastEvent && (sim.lastEvent.kind === 'append' || sim.lastEvent.kind === 'replace') + ? sim.lastEvent.uid + : null; + + const focusClass = (name: string) => + focus === name ? 'border-l-2 border-[var(--bt-fg)] pl-3' : ''; + + const buttonClass = + 'border border-line bg-bg px-3 py-1.5 font-mono text-xs hover:bg-panel'; + + return ( + +
+ {Array.from({ length: maxUids }, (_, uid) => { + const slot = sim.slots[uid]; + if (!slot) { + return
; + } + const isOwnerImmune = ownerImmune.has(uid); + const isNewImmune = !isOwnerImmune && sim.tick - slot.registeredAt < immunityPeriod; + const shade = slot.emission / maxEmission; + const status = isOwnerImmune ? ', owner-immune' : isNewImmune ? ', immune' : ''; + return ( +
+ 0.55 ? 'text-white' : ''}>{uid} + {(isOwnerImmune || isNewImmune) && ( + 0.55 ? 'text-white' : '') + } + > + {isOwnerImmune ? 'O' : 'I'} + + )} +
+ ); + })} +
+ +

{eventMessage(sim.lastEvent)}

+ +
+ + + +
+ +
+ + + + +
+ +
+
+ +
+
+ +
+
+ +
+
+ + ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx new file mode 100644 index 0000000000..fb5b21158c --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx @@ -0,0 +1,280 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Tooltip, + Legend, +} from 'chart.js'; +import { Bar } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend); + +const U16_MAX = 65535; +const MINER_LABELS = ['uid 3', 'uid 7', 'uid 12', 'uid 21', 'uid 34']; + +/** Largest cutoff c such that, after clipping every weight to c and + * sum-normalizing, the largest share is <= limit. Mirrors the chain's + * check (`check_vec_max_limited`) and the SDK's redistribution-preserving + * clip (`clip_to_max_weight`). */ +function clipToLimit(weights: number[], limit: number): number[] { + const total = weights.reduce((a, b) => a + b, 0); + if (total <= 0) return weights.map(() => 0); + if (weights.length * limit <= 1) return weights.map(() => 1 / weights.length); + + const normalized = weights.map((w) => w / total); + if (Math.max(...normalized) <= limit) return normalized; + + let lo = 0; + let hi = Math.max(...weights); + for (let i = 0; i < 50; i++) { + const mid = (lo + hi) / 2; + const clippedSum = weights.reduce((a, w) => a + Math.min(w, mid), 0); + if (clippedSum > 0 && mid / clippedSum <= limit) lo = mid; + else hi = mid; + } + const clipped = weights.map((w) => Math.min(w, lo)); + const clippedTotal = clipped.reduce((a, b) => a + b, 0); + return clipped.map((w) => w / clippedTotal); +} + +function ClippingPlayground({ focus }: { focus?: string }) { + const [weights, setWeights] = useState([80, 35, 20, 10, 0]); + const [limitRaw, setLimitRaw] = useState(19661); // ~0.3 + const [minAllowed, setMinAllowed] = useState(3); + + const limit = limitRaw / U16_MAX; + const total = weights.reduce((a, b) => a + b, 0); + const before = weights.map((w) => (total > 0 ? w / total : 0)); + const after = useMemo(() => clipToLimit(weights, limit), [weights, limit]); + + const nonzero = weights.filter((w) => w > 0).length; + const meetsMin = nonzero >= minAllowed; + const wouldClip = Math.max(...before) > limit + 1e-9; + + const data = useMemo( + () => ({ + labels: MINER_LABELS, + datasets: [ + { + label: 'Submitted (normalized)', + data: before, + backgroundColor: 'rgba(41, 41, 41, 0.25)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + { + label: 'After clip + renormalize', + data: after, + backgroundColor: 'rgba(41, 41, 41, 0.75)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + ], + }), + [before, after], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + labels: {font: {family: 'FiraCode, monospace', size: 10}, boxWidth: 12}, + }, + tooltip: { + callbacks: { + label: (ctx: {dataset: {label?: string}; parsed: {y: number}}) => + `${ctx.dataset.label}: ${(ctx.parsed.y * 100).toFixed(1)}%`, + }, + }, + }, + scales: { + x: { + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + }, + y: { + min: 0, + max: 1, + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: { + font: {family: 'FiraCode, monospace', size: 10}, + callback: (value: string | number) => `${(Number(value) * 100).toFixed(0)}%`, + }, + title: {display: true, text: 'share of total weight', font: {size: 11}}, + }, + }, + }), + [], + ); + + const highlight = (name: string) => + focus === name ? 'border border-line bg-bg p-3' : undefined; + + return ( + +
+ +
+ +
+ + + +
+ +
+ {weights.map((w, i) => ( + + setWeights((prev) => prev.map((p, j) => (j === i ? value : p))) + } + /> + ))} +
+ +
+
+ +
+
+ +
+
+
+ ); +} + +const TEMPO_BLOCKS = 360; +const TIMELINE_EPOCHS = 8; + +function epochState(epoch: number, period: number): 'commit' | 'hidden' | 'reveal' | 'expired' { + if (epoch === 0) return 'commit'; + if (epoch < period) return 'hidden'; + if (epoch === period) return 'reveal'; + return 'expired'; +} + +const EPOCH_STYLE: Record, string> = { + commit: 'border-[rgb(41,41,41)] bg-bg', + hidden: 'border-line bg-[rgba(41,41,41,0.08)] text-mute', + reveal: 'border-[rgb(41,41,41)] bg-[rgba(41,41,41,0.75)] text-white', + expired: 'border-line bg-bg text-mute opacity-50', +}; + +const EPOCH_LABEL: Record, string> = { + commit: 'commit', + hidden: 'hidden', + reveal: 'reveal', + expired: 'expired', +}; + +function CommitRevealTimeline() { + const [period, setPeriod] = useState(1); + + const delayBlocks = period * TEMPO_BLOCKS; + const delayMinutes = (delayBlocks * 12) / 60; + + return ( + +
+ {Array.from({length: TIMELINE_EPOCHS}, (_, epoch) => { + const state = epochState(epoch, period); + return ( +
+

e+{epoch}

+

{EPOCH_LABEL[state]}

+
+ ); + })} +
+ +
+ + + +
+ +
+ +
+
+ ); +} + +export function HyperparamWeightsRules({ focus }: { focus?: string }) { + if (focus === 'commit_reveal_period' || focus === 'commit_reveal_weights_enabled') { + return ; + } + return ; +} diff --git a/website/apps/bittensor-website/src/components/mdx.tsx b/website/apps/bittensor-website/src/components/mdx.tsx index 3392cd0835..1aeaac7339 100644 --- a/website/apps/bittensor-website/src/components/mdx.tsx +++ b/website/apps/bittensor-website/src/components/mdx.tsx @@ -9,6 +9,13 @@ import { ConvictionModeComparison } from './docs/conviction-mode-comparison'; import { ConvictionSubnetScenario } from './docs/conviction-subnet-scenario'; import { EmissionFlowDiagram } from './docs/emission-flow-diagram'; import { EmissionNetworkSnapshot } from './docs/emission-network-snapshot'; +import { HyperparamBurnController } from './docs/hyperparam-burn-controller'; +import { HyperparamConsensusSigmoid } from './docs/hyperparam-consensus-sigmoid'; +import { HyperparamLiquidAlpha } from './docs/hyperparam-liquid-alpha'; +import { HyperparamOwnerCut } from './docs/hyperparam-owner-cut'; +import { HyperparamPowDifficulty } from './docs/hyperparam-pow-difficulty'; +import { HyperparamUidLifecycle } from './docs/hyperparam-uid-lifecycle'; +import { HyperparamWeightsRules } from './docs/hyperparam-weights-rules'; import { RegistrationBurnTimeline } from './docs/registration-burn-timeline'; import { RootProportionExplainer } from './docs/root-proportion-explainer'; import { SubnetEmissionShareChart } from './docs/subnet-emission-share-chart'; @@ -112,6 +119,13 @@ export function getMDXComponents(components?: MDXComponents) { ConvictionModeComparison, EvmAddressDomains, EvmMoneyFlows, + HyperparamBurnController, + HyperparamConsensusSigmoid, + HyperparamLiquidAlpha, + HyperparamOwnerCut, + HyperparamPowDifficulty, + HyperparamUidLifecycle, + HyperparamWeightsRules, ...components, } satisfies MDXComponents; } From a66ae53aec9f52634d48fafbc401d1be31289be7 Mon Sep 17 00:00:00 2001 From: unarbos Date: Mon, 13 Jul 2026 17:47:21 -0600 Subject: [PATCH 05/43] add a parameter-specific chart to every hyperparameter explainer page Every page that previously had no visual gets a dedicated interactive chart (16 new components: epoch timeline, activity bars, permit line, rate-limit timelines, version/registration gates, per-block caps, bonds clipping/reset, Yuma3 comparison, serve-rate, childkey range, transfer flow, legacy adjustment, PoW dead-end). Family demos now adapt scenarios, sliders, and captions to their focus parameter. Co-authored-by: Cursor --- docs/hyperparameters/activity-cutoff.mdx | 5 + docs/hyperparameters/adjustment-alpha.mdx | 6 +- docs/hyperparameters/adjustment-interval.mdx | 6 +- docs/hyperparameters/bonds-penalty.mdx | 4 + docs/hyperparameters/bonds-reset-enabled.mdx | 4 + docs/hyperparameters/max-difficulty.mdx | 5 +- docs/hyperparameters/max-regs-per-block.mdx | 4 + docs/hyperparameters/max-validators.mdx | 5 + docs/hyperparameters/min-childkey-take.mdx | 4 + docs/hyperparameters/min-difficulty.mdx | 5 +- .../network-pow-registration-allowed.mdx | 5 +- docs/hyperparameters/registration-allowed.mdx | 5 + docs/hyperparameters/serving-rate-limit.mdx | 4 + .../target-regs-per-interval.mdx | 5 +- docs/hyperparameters/tempo.mdx | 5 + docs/hyperparameters/transfers-enabled.mdx | 4 + docs/hyperparameters/weights-rate-limit.mdx | 4 + docs/hyperparameters/weights-version.mdx | 4 + docs/hyperparameters/yuma3-enabled.mdx | 4 + .../docs/hyperparam-activity-cutoff-chart.tsx | 159 ++++++++++++ .../docs/hyperparam-bonds-penalty-chart.tsx | 151 +++++++++++ .../docs/hyperparam-bonds-reset-chart.tsx | 170 +++++++++++++ .../docs/hyperparam-burn-controller.tsx | 207 ++++++++++++--- .../docs/hyperparam-childkey-take-range.tsx | 129 ++++++++++ .../docs/hyperparam-consensus-sigmoid.tsx | 122 ++++++--- .../docs/hyperparam-legacy-adjustment.tsx | 238 ++++++++++++++++++ .../docs/hyperparam-liquid-alpha.tsx | 229 +++++++++++++---- .../docs/hyperparam-max-validators-chart.tsx | 131 ++++++++++ .../components/docs/hyperparam-owner-cut.tsx | 13 +- .../docs/hyperparam-pow-difficulty.tsx | 103 ++++++-- .../docs/hyperparam-pow-toggle-dead-end.tsx | 59 +++++ .../docs/hyperparam-registration-gate.tsx | 80 ++++++ .../docs/hyperparam-regs-cap-chart.tsx | 173 +++++++++++++ .../docs/hyperparam-regs-per-block-chart.tsx | 141 +++++++++++ .../hyperparam-serving-rate-limit-chart.tsx | 121 +++++++++ .../docs/hyperparam-tempo-timeline.tsx | 161 ++++++++++++ .../hyperparam-transfers-enabled-flow.tsx | 142 +++++++++++ .../docs/hyperparam-uid-lifecycle.tsx | 57 ++++- .../hyperparam-weights-rate-limit-chart.tsx | 169 +++++++++++++ .../docs/hyperparam-weights-rules.tsx | 64 +++-- .../docs/hyperparam-weights-version-gate.tsx | 156 ++++++++++++ .../docs/hyperparam-yuma3-chart.tsx | 155 ++++++++++++ .../bittensor-website/src/components/mdx.tsx | 32 +++ 43 files changed, 3077 insertions(+), 173 deletions(-) create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-activity-cutoff-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-bonds-penalty-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-bonds-reset-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-childkey-take-range.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-legacy-adjustment.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-max-validators-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-pow-toggle-dead-end.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-registration-gate.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-regs-cap-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-regs-per-block-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-serving-rate-limit-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-tempo-timeline.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-transfers-enabled-flow.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-weights-rate-limit-chart.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-weights-version-gate.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/hyperparam-yuma3-chart.tsx diff --git a/docs/hyperparameters/activity-cutoff.mdx b/docs/hyperparameters/activity-cutoff.mdx index 1e6da64f03..361df2d7fc 100644 --- a/docs/hyperparameters/activity-cutoff.mdx +++ b/docs/hyperparameters/activity-cutoff.mdx @@ -25,6 +25,11 @@ The effective value is derived, not stored directly: factor is bounded to 1,000–50,000 (one to fifty tempos); the default 13,889 at tempo 360 yields the legacy 5,000-block cutoff (~16.7 hours). +The chart below plots each validator's blocks-since-last-weights against the +cutoff — slide it to see who drops out of consensus. + + + ## Reading and setting Inspect with: diff --git a/docs/hyperparameters/adjustment-alpha.mdx b/docs/hyperparameters/adjustment-alpha.mdx index 236edfd51d..4d5ac8860e 100644 --- a/docs/hyperparameters/adjustment-alpha.mdx +++ b/docs/hyperparameters/adjustment-alpha.mdx @@ -30,7 +30,11 @@ callable by the subnet owner, subject only to the owner rate limit and admin freeze window — but setting it changes nothing about how registrations are priced. - +The chart below replays the same registration burst under the old interval-EMA +controller (where alpha mattered) and the current continuous one (where it +does not). + + ## Reading and setting diff --git a/docs/hyperparameters/adjustment-interval.mdx b/docs/hyperparameters/adjustment-interval.mdx index edde319549..10881244b2 100644 --- a/docs/hyperparameters/adjustment-interval.mdx +++ b/docs/hyperparameters/adjustment-interval.mdx @@ -28,7 +28,11 @@ only that the subnet exists — but changing it has no effect on registration pricing. Even the root subnet's per-interval registration counter resets on the root epoch boundary (`tempo`), not on this interval. - +The chart below replays the same registration burst under the old +once-per-interval controller and the current per-block one — drag the interval +to see what the cadence used to change. + + ## Reading and setting diff --git a/docs/hyperparameters/bonds-penalty.mdx b/docs/hyperparameters/bonds-penalty.mdx index 7719366bdf..dfa7ad3f34 100644 --- a/docs/hyperparameters/bonds-penalty.mdx +++ b/docs/hyperparameters/bonds-penalty.mdx @@ -18,6 +18,10 @@ weights_for_bonds = (1 − penalty) × weights + penalty × clipped_weights Values in between blend the two. The interpolated matrix feeds the bonds EMA on both the classic path and the [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) path, so the penalty applies regardless of which consensus variant is active. See the [Yuma Consensus overview](/docs/concepts/emissions#yuma-consensus) for where this sits in the epoch. +Drag the penalty from 0 to 1 to watch a deviant validator's out-of-consensus weight get clipped away while an in-consensus validator is untouched: + + + ## Reading and setting ``` diff --git a/docs/hyperparameters/bonds-reset-enabled.mdx b/docs/hyperparameters/bonds-reset-enabled.mdx index f9186db9af..5f9c72f74e 100644 --- a/docs/hyperparameters/bonds-reset-enabled.mdx +++ b/docs/hyperparameters/bonds-reset-enabled.mdx @@ -11,6 +11,10 @@ When a hotkey commits metadata (the commitments pallet's `OnMetadataCommitment` Bonds then rebuild through the normal EMA at the rate set by [`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg) (or the liquid-alpha rate), so validators who re-endorse the refreshed miner regain dividends over subsequent epochs. +Here is what that looks like for a validator's bond on a miner that commits metadata mid-way — toggle the flag to compare: + + + The flag is off by default and toggling it emits a `BondsResetToggled` event (`sudo_set_bonds_reset_enabled` in `pallets/admin-utils/src/lib.rs`). ## Reading and setting diff --git a/docs/hyperparameters/max-difficulty.mdx b/docs/hyperparameters/max-difficulty.mdx index 571ebc49ca..02da701cf5 100644 --- a/docs/hyperparameters/max-difficulty.mdx +++ b/docs/hyperparameters/max-difficulty.mdx @@ -24,8 +24,9 @@ walked difficulty up until it hit this ceiling. The mainnet default is On the current runtime PoW registration is deprecated — the `register` extrinsic routes to burned registration and nothing adjusts `difficulty` -between intervals — so this ceiling is dormant. The playground shows the -controller it bounds: +between intervals — so this ceiling is dormant. The playground opens on a +registration-rush scenario where difficulty ratchets up until it pins +against the bold ceiling line: diff --git a/docs/hyperparameters/max-regs-per-block.mdx b/docs/hyperparameters/max-regs-per-block.mdx index 4cc9f1668d..c209778e02 100644 --- a/docs/hyperparameters/max-regs-per-block.mdx +++ b/docs/hyperparameters/max-regs-per-block.mdx @@ -36,6 +36,10 @@ Because the burn cost also bumps multiplicatively after every registration in a block ([`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult)), the price and the cap work together against registration floods. +Drag the cap below to see how it slices bursts block by block: + + + ## Reading and setting ``` diff --git a/docs/hyperparameters/max-validators.mdx b/docs/hyperparameters/max-validators.mdx index b6b321a3cc..09396c2f31 100644 --- a/docs/hyperparameters/max-validators.mdx +++ b/docs/hyperparameters/max-validators.mdx @@ -27,6 +27,11 @@ validator is also excluded. See [Yuma Consensus](/docs/concepts/emissions#yuma-consensus) for where permits sit in the pipeline. +The chart below sorts neurons by stake and draws the permit line at the +top-`max_validators` — slide the cap to move it. + + + ## Reading and setting Inspect with: diff --git a/docs/hyperparameters/min-childkey-take.mdx b/docs/hyperparameters/min-childkey-take.mdx index 540cd92962..45c3ff2834 100644 --- a/docs/hyperparameters/min-childkey-take.mdx +++ b/docs/hyperparameters/min-childkey-take.mdx @@ -27,6 +27,10 @@ lower, without anyone resubmitting. The setter itself bounds the floor to the \[global min, global max\] range, so an owner cannot set a floor above 18%. +Raise the floor below and watch an existing childkey's take get pushed up: + + + ## Reading and setting ```bash diff --git a/docs/hyperparameters/min-difficulty.mdx b/docs/hyperparameters/min-difficulty.mdx index 5bcf617a4d..44d9a4275d 100644 --- a/docs/hyperparameters/min-difficulty.mdx +++ b/docs/hyperparameters/min-difficulty.mdx @@ -29,8 +29,9 @@ floor to 10,000,000 on every subnet, matching the runtime default Note that on the current runtime PoW registration is deprecated: the `register` extrinsic routes to burned registration and no controller adjusts `difficulty` between intervals, so this floor is dormant. The -playground below shows the controller behavior it bounds — drag the floor -to its top stop to see the `u64::MAX` disabled state: +playground below opens on a quiet-demand scenario where difficulty decays +until it sits on the bold floor line — drag the floor to its top stop (or +use the button) to see the `u64::MAX` disabled state: diff --git a/docs/hyperparameters/network-pow-registration-allowed.mdx b/docs/hyperparameters/network-pow-registration-allowed.mdx index 04e21417e8..d295435b1c 100644 --- a/docs/hyperparameters/network-pow-registration-allowed.mdx +++ b/docs/hyperparameters/network-pow-registration-allowed.mdx @@ -28,10 +28,9 @@ concrete: Independently, the PoW `register` extrinsic (`pallets/subtensor/src/macros/dispatches.rs`) ignores its work arguments and routes to the burned-registration path, so the flag has nothing left to -gate. The playground shows the difficulty mechanics this toggle used to -switch off: +gate. Both ends of the wire are cut: - + ## Reading and setting diff --git a/docs/hyperparameters/registration-allowed.mdx b/docs/hyperparameters/registration-allowed.mdx index 9f0dabe9c6..fdd77ed660 100644 --- a/docs/hyperparameters/registration-allowed.mdx +++ b/docs/hyperparameters/registration-allowed.mdx @@ -29,6 +29,11 @@ per-interval cap of 3 × Note the flag only stops new registrations; already-registered neurons are unaffected, and pruning/immunity mechanics continue as normal. +Flip the gate below to see how the same stream of registration attempts is +accepted or rejected: + + + ## Reading and setting ``` diff --git a/docs/hyperparameters/serving-rate-limit.mdx b/docs/hyperparameters/serving-rate-limit.mdx index 1cae60d93a..61760ba24f 100644 --- a/docs/hyperparameters/serving-rate-limit.mdx +++ b/docs/hyperparameters/serving-rate-limit.mdx @@ -11,6 +11,10 @@ When a neuron posts its axon endpoint, `do_serve_axon` (`pallets/subtensor/src/s The default is 50 blocks — about 10 minutes at 12-second blocks. Unlike the pruning family of parameters, this one does not affect who keeps a UID, only how frequently a UID's published endpoint can change; a miner that misses the window just retries after the cooldown. +Drag the slider to see which of a miner's serve attempts survive the cooldown: + + + ## Reading and setting ``` diff --git a/docs/hyperparameters/target-regs-per-interval.mdx b/docs/hyperparameters/target-regs-per-interval.mdx index 97932f06d2..24afcfdd88 100644 --- a/docs/hyperparameters/target-regs-per-interval.mdx +++ b/docs/hyperparameters/target-regs-per-interval.mdx @@ -31,7 +31,10 @@ The legacy EMA adjustment that used this value as a setpoint (together with [`adjustment_alpha`](/docs/hyperparameters/adjustment-alpha)) no longer exists in the runtime. - +The chart below shows the cap in action: attempts pile up over an interval, and +admission stops once the count reaches 3× the target. + + ## Reading and setting diff --git a/docs/hyperparameters/tempo.mdx b/docs/hyperparameters/tempo.mdx index a987ee333d..7c2d7fe1be 100644 --- a/docs/hyperparameters/tempo.mdx +++ b/docs/hyperparameters/tempo.mdx @@ -25,6 +25,11 @@ Setting a new tempo resets the epoch cycle (`apply_tempo_with_cycle_reset` re-anchors `LastEpochBlock` to the current block), so the next epoch lands a full tempo after the change. +The timeline below shows emission accruing block by block and paying out at +each epoch boundary — slide `tempo` to see the cadence in wall-clock time. + + + ## Reading and setting Inspect with: diff --git a/docs/hyperparameters/transfers-enabled.mdx b/docs/hyperparameters/transfers-enabled.mdx index fd594bcc38..bfa983f984 100644 --- a/docs/hyperparameters/transfers-enabled.mdx +++ b/docs/hyperparameters/transfers-enabled.mdx @@ -25,6 +25,10 @@ have transfers enabled. If the transferred stake carries a mass and conviction move to the destination coldkey in proportion to the amount transferred. +Flip the toggle below and try moving stake between the two coldkeys: + + + ## Reading and setting ```bash diff --git a/docs/hyperparameters/weights-rate-limit.mdx b/docs/hyperparameters/weights-rate-limit.mdx index bdae7ea88c..6638ee00f9 100644 --- a/docs/hyperparameters/weights-rate-limit.mdx +++ b/docs/hyperparameters/weights-rate-limit.mdx @@ -31,6 +31,10 @@ reads `LastUpdate` before signing and, if you are inside the cooldown, fails immediately with the number of blocks (and approximate seconds) left to wait instead of submitting a doomed extrinsic. +Drag the limit to see which submission attempts survive the cooldown: + + + ## Reading and setting ```bash diff --git a/docs/hyperparameters/weights-version.mdx b/docs/hyperparameters/weights-version.mdx index bcecf8e1a5..e8994bcaaf 100644 --- a/docs/hyperparameters/weights-version.mdx +++ b/docs/hyperparameters/weights-version.mdx @@ -30,6 +30,10 @@ subnets must pass the current key explicitly. Changing it has a dedicated rate limit: the owner may update it at most once per `WeightsVersionKeyRateLimit` tempos (currently 5). +Raise the required key to watch validators on old software fall off: + + + ## Reading and setting ```bash diff --git a/docs/hyperparameters/yuma3-enabled.mdx b/docs/hyperparameters/yuma3-enabled.mdx index 8383a5f536..fd2b22ee00 100644 --- a/docs/hyperparameters/yuma3-enabled.mdx +++ b/docs/hyperparameters/yuma3-enabled.mdx @@ -14,6 +14,10 @@ The epoch function branches on `Yuma3On` (`pallets/subtensor/src/epoch/run_epoch Practical consequence: liquid alpha and its parameters ([`alpha_low`](/docs/hyperparameters/alpha-low), [`alpha_high`](/docs/hyperparameters/alpha-high), [`alpha_sigmoid_steepness`](/docs/hyperparameters/alpha-sigmoid-steepness)) only take effect when this flag is on; the classic path never consults them. See the [Yuma Consensus overview](/docs/concepts/emissions#yuma-consensus) for the full epoch pipeline. +The two paths split the same dividend pool differently whenever validators disagree — compare them on a minimal example: + + + ## Reading and setting ``` diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-activity-cutoff-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-activity-cutoff-chart.tsx new file mode 100644 index 0000000000..a8a2e90e56 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-activity-cutoff-chart.tsx @@ -0,0 +1,159 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + PointElement, + LineElement, + Filler, + Tooltip, + Legend, +} from 'chart.js'; +import { Chart } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + PointElement, + LineElement, + Filler, + Tooltip, + Legend, +); + +const BLOCK_SECONDS = 12; + +// Illustrative snapshot: blocks since each validator last set weights +// (current_block − last_update), spread from very fresh to badly stale. +const WEIGHT_AGES = [ + 120, 340, 760, 1_150, 1_900, 2_600, 3_400, 4_200, 4_900, 5_600, 6_800, 8_500, 11_000, 14_000, +]; + +function formatDuration(blocks: number): string { + const seconds = blocks * BLOCK_SECONDS; + if (seconds < 3600) return `${(seconds / 60).toFixed(0)} min`; + if (seconds < 86_400) return `${(seconds / 3600).toFixed(1)} h`; + return `${(seconds / 86_400).toFixed(1)} days`; +} + +export function HyperparamActivityCutoffChart() { + const [cutoff, setCutoff] = useState(5000); + + // run_epoch.rs: inactive when last_update + activity_cutoff < current_block, + // i.e. a validator survives while its age is at most the cutoff. + const inactive = useMemo(() => WEIGHT_AGES.map((age) => age > cutoff), [cutoff]); + const activeCount = inactive.filter((i) => !i).length; + + const data = useMemo( + () => ({ + labels: WEIGHT_AGES.map((_, i) => `v${i + 1}`), + datasets: [ + { + type: 'line' as const, + label: 'activity_cutoff', + data: WEIGHT_AGES.map(() => cutoff), + borderColor: 'rgb(41, 41, 41)', + borderDash: [6, 4], + borderWidth: 1.5, + pointRadius: 0, + fill: false, + }, + { + type: 'bar' as const, + label: 'Blocks since last weights', + data: [...WEIGHT_AGES], + backgroundColor: inactive.map((isInactive) => + isInactive ? 'rgba(41, 41, 41, 0.12)' : 'rgba(41, 41, 41, 0.65)', + ), + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + ], + }), + [cutoff, inactive], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: {mode: 'index' as const, intersect: false}, + plugins: { + legend: {display: false}, + tooltip: { + callbacks: { + title: (items: {dataIndex: number}[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `Validator ${idx + 1}`; + }, + label: (ctx: {parsed: {y: number}; datasetIndex: number; dataIndex: number}) => { + if (ctx.datasetIndex === 0) return `cutoff ${cutoff} blocks`; + const status = inactive[ctx.dataIndex] ? 'inactive — stake masked' : 'active'; + return `${ctx.parsed.y} blocks since weights — ${status}`; + }, + }, + }, + }, + scales: { + x: { + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'validators', font: {size: 11}}, + }, + y: { + min: 0, + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'blocks since last weight set', font: {size: 11}}, + }, + }, + }), + [cutoff, inactive], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-bonds-penalty-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-bonds-penalty-chart.tsx new file mode 100644 index 0000000000..ecce775b23 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-bonds-penalty-chart.tsx @@ -0,0 +1,151 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + PointElement, + LineElement, + Tooltip, + Legend, +} from 'chart.js'; +import { Chart } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, BarElement, PointElement, LineElement, Tooltip, Legend); + +const MINERS = ['M1', 'M2', 'M3', 'M4', 'M5']; +// Stake-weighted consensus per miner (what the majority of stake endorses). +const CONSENSUS = [0.3, 0.25, 0.2, 0.15, 0.1]; +// An in-consensus validator weights exactly at consensus; clipping never touches it. +const HONEST = [0.3, 0.25, 0.2, 0.15, 0.1]; +// A deviant validator goes all-in on M5, far above its consensus level. +const DEVIANT = [0.05, 0.1, 0.05, 0.1, 0.7]; + +// Mirrors inplace_col_clip + interpolate in pallets/subtensor/src/epoch/run_epoch.rs: +// weights_for_bonds = (1 - penalty) * weights + penalty * min(weights, consensus). +function bondWeights(raw: number[], penalty: number): number[] { + return raw.map((w, j) => (1 - penalty) * w + penalty * Math.min(w, CONSENSUS[j])); +} + +export function HyperparamBondsPenaltyChart() { + const [penalty, setPenalty] = useState(1); + + const deviant = useMemo(() => bondWeights(DEVIANT, penalty), [penalty]); + const honest = useMemo(() => bondWeights(HONEST, penalty), [penalty]); + + const data = useMemo( + () => ({ + labels: MINERS, + datasets: [ + { + type: 'bar' as const, + label: 'in-consensus validator (bond weights)', + data: honest, + backgroundColor: 'rgba(41, 41, 41, 0.3)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + { + type: 'bar' as const, + label: 'deviant validator (bond weights)', + data: deviant, + backgroundColor: 'rgba(41, 41, 41, 0.85)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + { + type: 'line' as const, + label: 'consensus clip level', + data: CONSENSUS, + borderColor: 'rgba(41, 41, 41, 0.6)', + borderDash: [4, 4], + borderWidth: 1, + pointRadius: 2, + pointBackgroundColor: 'rgb(41, 41, 41)', + stepped: 'middle' as const, + fill: false, + }, + ], + }), + [honest, deviant], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => + `${ctx.dataset.label ?? ''}: ${ctx.parsed.y.toFixed(3)}`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'miner', font: { size: 11 } }, + }, + y: { + min: 0, + max: 0.75, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'weight used for bond accrual', font: { size: 11 } }, + }, + }, + }), + [], + ); + + const deviantMass = deviant.reduce((a, b) => a + b, 0); + const rawMass = DEVIANT.reduce((a, b) => a + b, 0); + + return ( + +
+ +
+ +
+ + + a + b, 0) * 100).toFixed(0)}% retained`} + hint="weights at or below consensus are never clipped" + /> +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-bonds-reset-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-bonds-reset-chart.tsx new file mode 100644 index 0000000000..2878574091 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-bonds-reset-chart.tsx @@ -0,0 +1,170 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Filler, + Tooltip, + Legend, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip, Legend); + +const EPOCHS = 40; +const COMMIT_EPOCH = 20; +const TARGET_BOND = 1; // validator keeps endorsing the miner at full instant bond + +// Bonds accrue via B(t) = alpha * target + (1 - alpha) * B(t-1); do_reset_bonds +// (run_epoch.rs) zeroes the bond at the metadata-commit epoch when the flag is on. +function bondSeries(alpha: number, resetOn: boolean): number[] { + const ys: number[] = []; + let b = 0; + for (let t = 0; t <= EPOCHS; t++) { + if (resetOn && t === COMMIT_EPOCH) b = 0; + ys.push(b); + b = alpha * TARGET_BOND + (1 - alpha) * b; + } + return ys; +} + +export function HyperparamBondsResetChart() { + const [resetOn, setResetOn] = useState(true); + const [bondsMovingAvg, setBondsMovingAvg] = useState(0.9); + + const alpha = 1 - bondsMovingAvg; + const withFlag = useMemo(() => bondSeries(alpha, resetOn), [alpha, resetOn]); + const noReset = useMemo(() => bondSeries(alpha, false), [alpha]); + + const data = useMemo( + () => ({ + labels: withFlag.map((_, t) => `${t}`), + datasets: [ + { + label: resetOn ? 'bond on committing miner (reset on)' : 'bond on committing miner', + data: withFlag, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + ...(resetOn + ? [ + { + label: 'same bond if reset were off', + data: noReset, + borderColor: 'rgba(41, 41, 41, 0.35)', + borderDash: [4, 4], + fill: false, + tension: 0, + pointRadius: 0, + borderWidth: 1, + }, + ] + : []), + ], + }), + [withFlag, noReset, resetOn], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => { + const t = items[0]?.dataIndex ?? 0; + return t === COMMIT_EPOCH ? `epoch ${t} — metadata commit` : `epoch ${t}`; + }, + label: (ctx: { parsed: { y: number } }) => `bond ${ctx.parsed.y.toFixed(3)}`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { maxTicksLimit: 11, font: { family: 'FiraCode, monospace', size: 10 } }, + title: { + display: true, + text: `epoch (metadata commit at epoch ${COMMIT_EPOCH})`, + font: { size: 11 }, + }, + }, + y: { + min: 0, + max: 1, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'bond on the committing miner', font: { size: 11 } }, + }, + }, + }), + [], + ); + + const atCommit = withFlag[COMMIT_EPOCH] ?? 0; + const beforeCommit = withFlag[COMMIT_EPOCH - 1] ?? 0; + const atEnd = withFlag[EPOCHS] ?? 0; + + return ( + +
+ +
+ +
+ + + +
+ +
+ + +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx index 7be8c38113..e3326f46bb 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-burn-controller.tsx @@ -11,6 +11,7 @@ import { Filler, Tooltip, } from 'chart.js'; +import type { ChartData } from 'chart.js'; import { Line } from 'react-chartjs-2'; import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; @@ -25,9 +26,76 @@ ChartJS.register( ); const BLOCKS_PER_DAY = 7200; // 12s blocks -const SIM_BLOCKS = BLOCKS_PER_DAY; // 24h window -const SAMPLE_EVERY = 12; -const INITIAL_BURN_TAO = 0.1; // chain's InitialBurn (100_000_000 rao) + +interface Preset { + minBurn: number; + maxBurn: number; + mult: number; + halfLife: number; + regsPerDay: number; + startBurn: number; + windowBlocks: number; + sampleEvery: number; + /** Scheduled burst of registrations (used by the burn_increase_mult scenario). */ + burst?: { startBlock: number; spacing: number; count: number }; +} + +const DEFAULT_PRESET: Preset = { + minBurn: 0.0005, + maxBurn: 100, + mult: 1.26, + halfLife: 360, + regsPerDay: 20, + startBurn: 0.1, // chain's InitialBurn (100_000_000 rao) + windowBlocks: BLOCKS_PER_DAY, + sampleEvery: 12, +}; + +const PRESETS: Record = { + // No demand: a moderate spike decays all the way down and rests on the floor. + min_burn: { + ...DEFAULT_PRESET, + minBurn: 0.005, + regsPerDay: 0, + startBurn: 5, + }, + // A rush drives the price into the ceiling, where it pins. + max_burn: { + ...DEFAULT_PRESET, + maxBurn: 5, + regsPerDay: 150, + }, + // A short window with a burst of registrations so each ×mult step is visible. + burn_increase_mult: { + ...DEFAULT_PRESET, + regsPerDay: 0, + windowBlocks: 1440, + sampleEvery: 2, + burst: { startBlock: 60, spacing: 30, count: 8 }, + }, + // A big spike decaying, with markers at each half-life. + // sampleEvery must divide the half-life slider step (30) so markers land on samples. + burn_half_life: { + ...DEFAULT_PRESET, + regsPerDay: 0, + startBurn: 10, + sampleEvery: 30, + }, +}; + +const CAPTIONS: Record = { + min_burn: + 'One simulated day with no registrations: the price decays exponentially until it lands on the min_burn floor (dashed line) and rests there. min_burn is the resting price of an idle subnet — drag it to move the floor.', + max_burn: + 'One simulated day under a registration rush (150/day): each registration multiplies the price up until it pins at the max_burn ceiling (dashed line). While pinned, every registration costs exactly max_burn.', + burn_increase_mult: + 'A burst of 8 registrations, one every 30 blocks (~6 min): each multiplies the price by burn_increase_mult, stacking into a staircase that the half-life decay then unwinds. Drag the multiplier to steepen or flatten the stairs.', + burn_half_life: + 'A τ10 spike decaying with no registrations. Each marker sits one burn_half_life after the previous, at half its price, until the min_burn floor. Drag the half-life to stretch or compress the cooldown.', +}; + +const DEFAULT_CAPTION = + 'One simulated day. Every block the burn decays by f where f^burn_half_life = 1/2; every registration multiplies it by burn_increase_mult; the result is always clamped to [min_burn, max_burn].'; function formatTao(value: number): string { if (value >= 1000) return `τ${value.toFixed(0)}`; @@ -41,67 +109,132 @@ function sliderClass(focused: boolean): string { : 'border-l-2 border-transparent pl-3'; } +function formatBlocksElapsed(blocks: number, windowBlocks: number): string { + if (windowBlocks <= 1800) return `${blocks * 12 >= 3600 ? `${((blocks * 12) / 3600).toFixed(1)}h` : `${Math.round((blocks * 12) / 60)}m`}`; + return `${(blocks / 300).toFixed(1)}h`; +} + export function HyperparamBurnController({ focus }: { focus?: string }) { - const [minBurn, setMinBurn] = useState(0.0005); - const [maxBurn, setMaxBurn] = useState(100); - const [mult, setMult] = useState(1.26); - const [halfLife, setHalfLife] = useState(360); - const [regsPerDay, setRegsPerDay] = useState(20); + const preset = PRESETS[focus ?? ''] ?? DEFAULT_PRESET; + const [minBurn, setMinBurn] = useState(preset.minBurn); + const [maxBurn, setMaxBurn] = useState(preset.maxBurn); + const [mult, setMult] = useState(preset.mult); + const [halfLife, setHalfLife] = useState(preset.halfLife); + const [regsPerDay, setRegsPerDay] = useState(preset.regsPerDay); const [manualRegs, setManualRegs] = useState(0); + const { windowBlocks, sampleEvery, burst, startBurn } = preset; + const sim = useMemo(() => { const effMax = Math.max(maxBurn, minBurn); const decay = Math.pow(0.5, 1 / halfLife); const clamp = (v: number) => Math.min(Math.max(v, minBurn), effMax); - let burn = clamp(INITIAL_BURN_TAO); + let burn = clamp(startBurn); // "Register now" bumps land at the start of the window. for (let i = 0; i < manualRegs; i++) burn = clamp(burn * mult); const xs: number[] = [0]; const ys: number[] = [burn]; let peak = burn; + let low = burn; let regsSoFar = 0; - for (let b = 1; b <= SIM_BLOCKS; b++) { + for (let b = 1; b <= windowBlocks; b++) { burn = clamp(burn * decay); const due = Math.floor((b * regsPerDay) / BLOCKS_PER_DAY); while (regsSoFar < due) { burn = clamp(burn * mult); regsSoFar++; } + if (burst) { + const offset = b - burst.startBlock; + if (offset >= 0 && offset % burst.spacing === 0 && offset / burst.spacing < burst.count) { + burn = clamp(burn * mult); + } + } if (burn > peak) peak = burn; - if (b % SAMPLE_EVERY === 0) { + if (burn < low) low = burn; + if (b % sampleEvery === 0) { xs.push(b); ys.push(burn); } } - return { xs, ys, peak, final: burn }; - }, [minBurn, maxBurn, mult, halfLife, regsPerDay, manualRegs]); + return { xs, ys, peak, low, final: burn }; + }, [minBurn, maxBurn, mult, halfLife, regsPerDay, manualRegs, windowBlocks, sampleEvery, burst, startBurn]); // Rate at which per-registration bumps exactly cancel the decay: // mult * 0.5^(gap / half_life) = 1 => gap = half_life * log2(mult). const breakEven = mult > 1 ? BLOCKS_PER_DAY / (halfLife * Math.log2(mult)) : Infinity; - const data = useMemo( - () => ({ - labels: sim.xs.map((b) => `${(b / 300).toFixed(1)}h`), - datasets: [ - { - label: 'Burn cost (τ)', - data: sim.ys, - borderColor: 'rgb(41, 41, 41)', - backgroundColor: 'rgba(41, 41, 41, 0.08)', - fill: true, - tension: 0, - pointRadius: 0, - borderWidth: 1.5, - }, - ], - }), - [sim], - ); + const data = useMemo(() => { + // Only draw a clamp line when it is near the curve (or is the focused + // parameter), so it does not stretch the log axis into empty space. + const showMinLine = focus === 'min_burn' || sim.low <= minBurn * 2; + const showMaxLine = focus === 'max_burn' || sim.peak >= maxBurn * 0.5; + + const datasets: ChartData<'line', (number | null)[]>['datasets'] = [ + { + label: 'Burn cost (τ)', + data: sim.ys, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + ]; + + if (showMinLine) { + datasets.push({ + label: 'min_burn', + data: sim.ys.map(() => minBurn), + borderColor: focus === 'min_burn' ? 'rgb(41, 41, 41)' : 'rgba(41, 41, 41, 0.3)', + borderWidth: focus === 'min_burn' ? 1.5 : 1, + borderDash: focus === 'min_burn' ? [6, 4] : [2, 3], + pointRadius: 0, + fill: false, + }); + } + if (showMaxLine) { + datasets.push({ + label: 'max_burn', + data: sim.ys.map(() => Math.max(maxBurn, minBurn)), + borderColor: focus === 'max_burn' ? 'rgb(41, 41, 41)' : 'rgba(41, 41, 41, 0.3)', + borderWidth: focus === 'max_burn' ? 1.5 : 1, + borderDash: focus === 'max_burn' ? [6, 4] : [2, 3], + pointRadius: 0, + fill: false, + }); + } + + if (focus === 'burn_half_life') { + // Mark the curve at 1, 2, 3, 4 half-lives; each is half the previous + // while decay is uninterrupted and the floor has not been reached. + const markers = sim.ys.map((y, i) => { + const b = sim.xs[i] ?? 0; + const isHalfLifeMultiple = b > 0 && b % halfLife === 0 && b / halfLife <= 4; + return isHalfLifeMultiple && y > minBurn * 1.01 ? y : null; + }); + datasets.push({ + label: 'half-life markers', + data: markers, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgb(41, 41, 41)', + pointRadius: 4, + pointStyle: 'rectRot' as const, + showLine: false, + fill: false, + }); + } + + return { + labels: sim.xs.map((b) => formatBlocksElapsed(b, windowBlocks)), + datasets, + }; + }, [sim, focus, minBurn, maxBurn, halfLife, windowBlocks]); const options = useMemo( () => ({ @@ -111,10 +244,11 @@ export function HyperparamBurnController({ focus }: { focus?: string }) { plugins: { legend: { display: false }, tooltip: { + filter: (item: { datasetIndex: number }) => item.datasetIndex === 0, callbacks: { title: (items: { dataIndex: number }[]) => { const idx = items[0]?.dataIndex ?? 0; - return `${((sim.xs[idx] ?? 0) / 300).toFixed(1)}h in`; + return `${formatBlocksElapsed(sim.xs[idx] ?? 0, windowBlocks)} in`; }, label: (ctx: { parsed: { y: number } }) => formatTao(ctx.parsed.y), }, @@ -137,13 +271,13 @@ export function HyperparamBurnController({ focus }: { focus?: string }) { }, }, }), - [sim.xs], + [sim.xs, windowBlocks], ); return (
@@ -173,7 +307,10 @@ export function HyperparamBurnController({ focus }: { focus?: string }) {
- + = effectiveFloor && storedTake <= GLOBAL_MAX; + + const pct = (fraction: number) => (fraction / SCALE_MAX) * 100; + + return ( + +
+ {/* allowed window */} +
+ {/* floor edge */} +
+ {/* global max edge */} +
+ {/* stored take marker (hollow) */} +
+ {/* effective take marker (filled), pushed up to the floor when below it */} +
+
+
+ {[0, 0.05, 0.1, 0.15].map((tick) => ( + + {Math.round(tick * 100)}% + + ))} + + max + +
+ +
+ + storedTake + ? `Clamped up from stored ${formatPct(storedTake)}` + : 'Stored value, above the floor' + } + /> + +
+ +
+ + +
+ + ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx index b678dd5c1d..07c73d8b2a 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-consensus-sigmoid.tsx @@ -18,6 +18,7 @@ ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, const SAMPLE_POINTS = 100; const KAPPA_U16_MAX = 65535; +const RHO_GHOSTS = [2, 40]; // Matches sigmoid_safe in pallets/subtensor/src/epoch/math.rs: // 1 / (1 + exp(-rho * (input - kappa))) @@ -25,6 +26,22 @@ function trustSigmoid(input: number, rho: number, kappa: number): number { return 1 / (1 + Math.exp(-rho * (input - kappa))); } +function sigmoidPoints(rho: number, kappa: number): {x: number; y: number}[] { + return Array.from({length: SAMPLE_POINTS + 1}, (_, i) => { + const x = i / SAMPLE_POINTS; + return {x, y: trustSigmoid(x, rho, kappa)}; + }); +} + +const CAPTIONS: Record = { + rho: 'rho is the temperature of the trust sigmoid, sigmoid_safe in epoch/math.rs: trust = 1 / (1 + e^(−rho × (x − kappa))). The dashed ghost curves fix rho at 2 and 40 — slide rho between them and watch the curve snap from a gentle ramp into a near-step at kappa.', + kappa: + 'kappa is the midpoint of the trust sigmoid, sigmoid_safe in epoch/math.rs: trust = 1 / (1 + e^(−rho × (x − kappa))). The dashed marker is the majority threshold — alignment crossing kappa flips trust through 0.5, from mostly-distrusted to mostly-trusted. Slide kappa to move the crossing.', +}; + +const DEFAULT_CAPTION = + 'The classic Yuma trust curve, sigmoid_safe in epoch/math.rs: trust = 1 / (1 + e^(−rho × (x − kappa))). kappa is the midpoint, rho the steepness. The live epoch computes consensus as a kappa-weighted median; this sigmoid is the formulation rho parameterizes.'; + export function HyperparamConsensusSigmoid({ focus }: { focus?: string }) { const [rho, setRho] = useState(10); const [kappa, setKappa] = useState(0.5); @@ -32,50 +49,95 @@ export function HyperparamConsensusSigmoid({ focus }: { focus?: string }) { const label = (name: string, hint: string) => (focus === name ? '▸ ' : '') + `${name} (${hint})`; - const xs = useMemo( - () => Array.from({length: SAMPLE_POINTS + 1}, (_, i) => i / SAMPLE_POINTS), - [], - ); - const ys = useMemo(() => xs.map((x) => trustSigmoid(x, rho, kappa)), [xs, rho, kappa]); + const datasets = useMemo(() => { + const main = { + label: 'Trust', + data: sigmoidPoints(rho, kappa), + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + order: 0, + }; - const data = useMemo( - () => ({ - labels: xs.map((x) => x.toFixed(2)), - datasets: [ - { - label: 'Trust', - data: ys, - borderColor: 'rgb(41, 41, 41)', - backgroundColor: 'rgba(41, 41, 41, 0.08)', - fill: true, - tension: 0, - pointRadius: 0, - borderWidth: 1.5, - }, - ], - }), - [xs, ys], - ); + if (focus === 'rho') { + // Ghost curves bracketing the rho range make the steepness sweep visible. + const ghosts = RHO_GHOSTS.map((ghostRho) => ({ + label: `rho = ${ghostRho}`, + data: sigmoidPoints(ghostRho, kappa), + borderColor: 'rgba(41, 41, 41, 0.25)', + borderDash: [4, 4], + borderWidth: 1, + fill: false, + tension: 0, + pointRadius: 0, + order: 1, + })); + return [main, ...ghosts]; + } + + if (focus === 'kappa') { + // Vertical marker at the majority threshold plus the 0.5 crossing point. + const threshold = { + label: 'kappa threshold', + data: [ + {x: kappa, y: 0}, + {x: kappa, y: 1}, + ], + borderColor: 'rgba(41, 41, 41, 0.45)', + borderDash: [6, 4], + borderWidth: 1.5, + fill: false, + tension: 0, + pointRadius: 0, + order: 1, + }; + const crossing = { + label: 'majority crossing', + data: [{x: kappa, y: 0.5}], + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgb(41, 41, 41)', + showLine: false, + pointRadius: 4, + pointStyle: 'rectRot' as const, + order: 2, + }; + return [main, threshold, crossing]; + } + + return [main]; + }, [rho, kappa, focus]); + + const data = useMemo(() => ({datasets}), [datasets]); const options = useMemo( () => ({ responsive: true, maintainAspectRatio: false, - interaction: {mode: 'index' as const, intersect: false}, + interaction: {mode: 'nearest' as const, axis: 'x' as const, intersect: false}, plugins: { legend: {display: false}, tooltip: { callbacks: { - title: (items: {dataIndex: number}[]) => { - const idx = items[0]?.dataIndex ?? 0; - return `Alignment ${(xs[idx] ?? 0).toFixed(2)}`; + title: (items: {parsed: {x: number}}[]) => + `Alignment ${(items[0]?.parsed.x ?? 0).toFixed(2)}`, + label: (ctx: {parsed: {y: number}; dataset: {label?: string}}) => { + const name = ctx.dataset.label ?? 'trust'; + if (name === 'kappa threshold') return `majority threshold at ${kappa.toFixed(2)}`; + if (name === 'majority crossing') return 'trust flips through 0.5 here'; + const prefix = name.startsWith('rho') ? `${name}: ` : ''; + return `${prefix}trust ${ctx.parsed.y.toFixed(4)}`; }, - label: (ctx: {parsed: {y: number}}) => `trust ${ctx.parsed.y.toFixed(4)}`, }, }, }, scales: { x: { + type: 'linear' as const, + min: 0, + max: 1, grid: {color: 'rgba(41, 41, 41, 0.06)'}, ticks: {maxTicksLimit: 11, font: {family: 'FiraCode, monospace', size: 10}}, title: {display: true, text: 'consensus alignment (stake fraction)', font: {size: 11}}, @@ -89,13 +151,13 @@ export function HyperparamConsensusSigmoid({ focus }: { focus?: string }) { }, }, }), - [xs], + [kappa], ); return (
diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-legacy-adjustment.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-legacy-adjustment.tsx new file mode 100644 index 0000000000..3613a647be --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-legacy-adjustment.tsx @@ -0,0 +1,238 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + LogarithmicScale, + PointElement, + LineElement, + Filler, + Tooltip, +} from 'chart.js'; +import type { ChartData } from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register( + CategoryScale, + LinearScale, + LogarithmicScale, + PointElement, + LineElement, + Filler, + Tooltip, +); + +const WINDOW_BLOCKS = 1800; // ~6h at 12s blocks +const BURST_END = 600; // demand for the first ~2h, then quiet +const REGS_PER_INTERVAL_OF_100 = 12; // demand rate during the burst +const TARGET = 2; // legacy setpoint (chain default for target_regs_per_interval) +const SAMPLE_EVERY = 4; +const MIN_BURN = 0.0005; +const MAX_BURN = 100; +const START_BURN = 0.5; +const NEW_MULT = 1.26; // current burn_increase_mult default +const NEW_HALF_LIFE = 360; // current burn_half_life default + +const CAPTIONS: Record = { + adjustment_alpha: + 'The same demand burst (~2h of registrations, then quiet) priced two ways. Then (dotted steps): once per interval the price jumped to an EMA-blended value — adjustment_alpha is the weight on the old price, so higher alpha means slower steps. Now (solid): every registration bumps the price and it decays every block; alpha changes nothing on this curve.', + adjustment_interval: + 'The same demand burst (~2h of registrations, then quiet) priced two ways. Then (dotted steps): the price only moved once per adjustment_interval — drag it to make the steps wider or narrower. Now (solid): the price reacts per registration and decays per block; the interval no longer affects it.', +}; + +function formatTao(value: number): string { + if (value >= 1000) return `τ${value.toFixed(0)}`; + if (value >= 1) return `τ${value.toFixed(2)}`; + return `τ${value.toPrecision(3)}`; +} + +/** Blocks at which a registration lands, evenly spread through the burst. */ +function registrationBlocks(): number[] { + const total = Math.round((BURST_END / 100) * REGS_PER_INTERVAL_OF_100); + const blocks: number[] = []; + for (let i = 0; i < total; i++) { + blocks.push(Math.round(((i + 1) * BURST_END) / total)); + } + return blocks; +} + +export function HyperparamLegacyAdjustment({ focus }: { focus?: string }) { + const [alpha, setAlpha] = useState(0); + const [interval, setInterval_] = useState(100); + + const sim = useMemo(() => { + const clamp = (v: number) => Math.min(Math.max(v, MIN_BURN), MAX_BURN); + const regBlocks = new Set(registrationBlocks()); + + // "Then": price frozen within each interval; at the boundary, + // proposed = price × (regs + target) / (2 × target), blended by alpha. + let thenPrice = START_BURN; + let regsThisInterval = 0; + + // "Now": per-registration ×mult bump, per-block half-life decay. + let nowPrice = START_BURN; + const decay = Math.pow(0.5, 1 / NEW_HALF_LIFE); + + const xs: number[] = [0]; + const thenYs: number[] = [thenPrice]; + const nowYs: number[] = [nowPrice]; + + for (let b = 1; b <= WINDOW_BLOCKS; b++) { + const hasReg = regBlocks.has(b); + + if (hasReg) regsThisInterval++; + if (b % interval === 0) { + const proposed = (thenPrice * (regsThisInterval + TARGET)) / (2 * TARGET); + thenPrice = clamp(alpha * thenPrice + (1 - alpha) * proposed); + regsThisInterval = 0; + } + + nowPrice = clamp(nowPrice * decay); + if (hasReg) nowPrice = clamp(nowPrice * NEW_MULT); + + if (b % SAMPLE_EVERY === 0) { + xs.push(b); + thenYs.push(thenPrice); + nowYs.push(nowPrice); + } + } + + return { xs, thenYs, nowYs }; + }, [alpha, interval]); + + const data = useMemo(() => { + const datasets: ChartData<'line', number[]>['datasets'] = [ + { + label: 'now: continuous bump + decay', + data: sim.nowYs, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + { + label: 'then: interval EMA steps', + data: sim.thenYs, + borderColor: 'rgba(41, 41, 41, 0.45)', + borderDash: [4, 3], + stepped: true, + pointRadius: 0, + borderWidth: 1.25, + fill: false, + }, + ]; + return { + labels: sim.xs.map((b) => `${((b * 12) / 3600).toFixed(1)}h`), + datasets, + }; + }, [sim]); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `${(((sim.xs[idx] ?? 0) * 12) / 3600).toFixed(1)}h in`; + }, + label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => + `${ctx.dataset.label}: ${formatTao(ctx.parsed.y)}`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { maxTicksLimit: 8, font: { family: 'FiraCode, monospace', size: 10 } }, + }, + y: { + type: 'logarithmic' as const, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { + maxTicksLimit: 6, + font: { family: 'FiraCode, monospace', size: 10 }, + callback: (value: string | number) => formatTao(Number(value)), + }, + title: { display: true, text: 'burn (τ, log)', font: { size: 11 } }, + }, + }, + }), + [sim.xs], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx index d33dfaba44..1f8baeedc8 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-liquid-alpha.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { Chart as ChartJS, CategoryScale, @@ -28,22 +28,67 @@ function alphaSigmoid(diff: number, low: number, high: number, steepness: number return Math.min(Math.max(alpha, low), high); } +const BASE_CAPTION = + 'Matches alpha_sigmoid in the epoch code. Deviation is weight − consensus when buying bond, bond − weight when selling. Higher alpha moves bonds faster. Requires yuma3_enabled; when liquid alpha is off, every pair uses the flat 1 − bonds_moving_avg / 1e6.'; + +const FOCUS_CAPTIONS: Record = { + liquid_alpha_enabled: `${BASE_CAPTION} The toggle below flips automatically — watch the sigmoid collapse to the flat line — until you take over.`, + bonds_moving_avg: + 'With liquid alpha off, alpha_sigmoid never runs: every validator–miner pair smooths at the single flat rate 1 − bonds_moving_avg / 1,000,000, the solid line here. Drag the slider to move the line; re-enable liquid alpha to see the flat rate become the dashed fallback under the sigmoid.', + alpha_low: `${BASE_CAPTION} The shaded band marks rates below alpha_low — the curve can never enter it, so alpha_low is the guaranteed floor for in-consensus pairs.`, + alpha_high: `${BASE_CAPTION} The shaded band marks rates above alpha_high — the curve can never enter it, so alpha_high caps how fast even the most deviant pair's bonds move.`, + alpha_sigmoid_steepness: `${BASE_CAPTION} The steepness slider sweeps on its own so you can watch the transition sharpen from a gentle ramp into a near step at deviation 0.5 — grab any control to stop it.`, +}; + export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { - const [enabled, setEnabled] = useState(true); + // For the bonds_moving_avg page, start with liquid alpha off so the flat rate is the chart. + const [enabled, setEnabled] = useState(focus !== 'bonds_moving_avg'); const [alphaLow, setAlphaLow] = useState(0.7); const [alphaHigh, setAlphaHigh] = useState(0.9); - const [steepness, setSteepness] = useState(1000); + const [steepness, setSteepness] = useState(focus === 'alpha_sigmoid_steepness' ? 100 : 1000); const [bondsMovingAvg, setBondsMovingAvg] = useState(0.9); + const [demoRunning, setDemoRunning] = useState( + focus === 'liquid_alpha_enabled' || focus === 'alpha_sigmoid_steepness', + ); + const stopDemo = () => setDemoRunning(false); + + const steepnessDir = useRef(1); + useEffect(() => { + if (!demoRunning) return; + if (focus === 'liquid_alpha_enabled') { + const id = setInterval(() => setEnabled((e) => !e), 2600); + return () => clearInterval(id); + } + if (focus === 'alpha_sigmoid_steepness') { + const id = setInterval(() => { + setSteepness((s) => { + let next = s + steepnessDir.current * 100; + if (next >= 3000) { + steepnessDir.current = -1; + next = 3000; + } else if (next <= 100) { + steepnessDir.current = 1; + next = 100; + } + return next; + }); + }, 100); + return () => clearInterval(id); + } + return undefined; + }, [demoRunning, focus]); // Flat EMA rate used when liquid alpha is off: 1 - bonds_moving_avg / 1e6. const flatAlpha = 1 - bondsMovingAvg; // The chain forbids alpha_low > alpha_high, so the sliders drag each other. const changeLow = (v: number) => { + stopDemo(); setAlphaLow(v); if (v > alphaHigh) setAlphaHigh(v); }; const changeHigh = (v: number) => { + stopDemo(); setAlphaHigh(v); if (v < alphaLow) setAlphaLow(v); }; @@ -54,38 +99,67 @@ export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { return { xs, ys }; }, [enabled, alphaLow, alphaHigh, steepness, flatAlpha]); - const data = useMemo( - () => ({ - labels: curve.xs.map((x) => x.toFixed(2)), - datasets: [ - { - label: enabled ? 'per-pair EMA rate (liquid alpha)' : 'flat EMA rate (bonds_moving_avg)', - data: curve.ys, - borderColor: 'rgb(41, 41, 41)', - backgroundColor: 'rgba(41, 41, 41, 0.08)', - fill: true, - tension: 0, - pointRadius: 0, - borderWidth: 1.5, - }, - ...(enabled - ? [ - { - label: 'flat rate if disabled', - data: curve.xs.map(() => flatAlpha), - borderColor: 'rgba(41, 41, 41, 0.35)', - borderDash: [4, 4], - fill: false, - tension: 0, - pointRadius: 0, - borderWidth: 1, - }, - ] - : []), - ], - }), - [curve, enabled, flatAlpha], - ); + const data = useMemo(() => { + const emphasizeFlat = focus === 'bonds_moving_avg'; + const datasets = [ + { + label: enabled ? 'per-pair EMA rate (liquid alpha)' : 'flat EMA rate (bonds_moving_avg)', + data: curve.ys, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: !enabled && emphasizeFlat ? 2.5 : 1.5, + }, + ...(enabled + ? [ + { + label: 'flat rate if disabled', + data: curve.xs.map(() => flatAlpha), + borderColor: emphasizeFlat ? 'rgba(41, 41, 41, 0.7)' : 'rgba(41, 41, 41, 0.35)', + borderDash: [4, 4], + fill: false, + tension: 0, + pointRadius: 0, + borderWidth: emphasizeFlat ? 2 : 1, + }, + ] + : []), + // Shade the region the curve can never enter on the bound pages. + ...(enabled && focus === 'alpha_low' + ? [ + { + label: 'below alpha_low (unreachable)', + data: curve.xs.map(() => alphaLow), + borderColor: 'rgba(41, 41, 41, 0.5)', + borderDash: [2, 3], + backgroundColor: 'rgba(41, 41, 41, 0.14)', + fill: 'start' as const, + tension: 0, + pointRadius: 0, + borderWidth: 1, + }, + ] + : []), + ...(enabled && focus === 'alpha_high' + ? [ + { + label: 'above alpha_high (unreachable)', + data: curve.xs.map(() => alphaHigh), + borderColor: 'rgba(41, 41, 41, 0.5)', + borderDash: [2, 3], + backgroundColor: 'rgba(41, 41, 41, 0.14)', + fill: 'end' as const, + tension: 0, + pointRadius: 0, + borderWidth: 1, + }, + ] + : []), + ]; + return { labels: curve.xs.map((x) => x.toFixed(2)), datasets }; + }, [curve, enabled, flatAlpha, focus, alphaLow, alphaHigh]); const options = useMemo( () => ({ @@ -124,31 +198,62 @@ export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { const focusClass = (name: string) => (focus === name ? 'border border-line bg-bg p-3' : ''); + const stats: { label: string; value: string; hint: string }[] = + focus === 'bonds_moving_avg' + ? [ + { + label: 'Flat EMA rate', + value: flatAlpha.toFixed(3), + hint: `1 − ${Math.round(bondsMovingAvg * 1_000_000).toLocaleString()} / 1,000,000`, + }, + { + label: 'Bond kept per epoch', + value: bondsMovingAvg.toFixed(3), + hint: 'share of last epoch’s bond that survives', + }, + { + label: 'Epochs to close ~90% of a gap', + value: flatAlpha > 0 ? Math.ceil(Math.log(0.1) / Math.log(1 - flatAlpha)).toString() : '∞', + hint: 'how long conviction takes to pay off', + }, + ] + : [ + { + label: 'In consensus (diff = 0)', + value: curve.ys[0]?.toFixed(3) ?? '—', + hint: + focus === 'alpha_low' + ? 'sits at the alpha_low floor' + : 'EMA rate for weights matching consensus', + }, + { + label: 'Max deviation (diff = 1)', + value: curve.ys[SAMPLE_POINTS]?.toFixed(3) ?? '—', + hint: + focus === 'alpha_high' + ? 'approaches the alpha_high ceiling' + : 'EMA rate at full deviation', + }, + { + label: 'Flat rate when disabled', + value: flatAlpha.toFixed(3), + hint: `1 − ${Math.round(bondsMovingAvg * 1_000_000).toLocaleString()} / 1,000,000`, + }, + ]; + return (
- - - + {stats.map((s) => ( + + ))}
@@ -157,11 +262,17 @@ export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { setEnabled(e.target.checked)} + onChange={(e) => { + stopDemo(); + setEnabled(e.target.checked); + }} className="accent-[var(--bt-fg)]" /> liquid_alpha_enabled {enabled ? 'true' : 'false'} + {focus === 'liquid_alpha_enabled' && demoRunning && ( + (auto-toggling — click to take over) + )}
@@ -172,7 +283,10 @@ export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { max={0.995} step={0.005} display={`${Math.round(bondsMovingAvg * 1_000_000).toLocaleString()} (${bondsMovingAvg.toFixed(3)})`} - onChange={setBondsMovingAvg} + onChange={(v) => { + stopDemo(); + setBondsMovingAvg(v); + }} />
@@ -204,8 +318,13 @@ export function HyperparamLiquidAlpha({ focus }: { focus?: string }) { min={-3000} max={3000} step={50} - display={`${steepness} (slope ${(steepness / 100).toFixed(1)}; negative is root-only)`} - onChange={setSteepness} + display={`${steepness} (slope ${(steepness / 100).toFixed(1)}; negative is root-only)${ + focus === 'alpha_sigmoid_steepness' && demoRunning ? ' — sweeping' : '' + }`} + onChange={(v) => { + stopDemo(); + setSteepness(v); + }} />
diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-max-validators-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-max-validators-chart.tsx new file mode 100644 index 0000000000..5670238411 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-max-validators-chart.tsx @@ -0,0 +1,131 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Tooltip, + Legend, +} from 'chart.js'; +import { Bar } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend); + +// Illustrative stake-weight distribution (α), already sorted descending — +// a typical long tail with a couple of zero-stake registrations at the end. +const STAKES = [ + 9_400, 7_800, 6_500, 5_200, 4_100, 3_300, 2_700, 2_100, 1_600, 1_200, 900, 650, 420, 260, 140, + 60, 0, 0, +]; + +export function HyperparamMaxValidatorsChart() { + const [maxValidators, setMaxValidators] = useState(8); + + // run_epoch.rs: is_topk_nonzero(&stake, max_allowed_validators) — top-k by + // stake weight, but zero-stake neurons never receive a permit. + const permitted = useMemo( + () => STAKES.map((stake, i) => i < maxValidators && stake > 0), + [maxValidators], + ); + const permitCount = permitted.filter(Boolean).length; + const lastPermitted = STAKES.filter((_, i) => permitted[i]).at(-1); + + const data = useMemo( + () => ({ + labels: STAKES.map((_, i) => `#${i + 1}`), + datasets: [ + { + label: 'Stake weight (α)', + data: [...STAKES], + backgroundColor: permitted.map((hasPermit) => + hasPermit ? 'rgba(41, 41, 41, 0.65)' : 'rgba(41, 41, 41, 0.12)', + ), + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + ], + }), + [permitted], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: {mode: 'index' as const, intersect: false}, + plugins: { + legend: {display: false}, + tooltip: { + callbacks: { + title: (items: {dataIndex: number}[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `Neuron ranked #${idx + 1} by stake`; + }, + label: (ctx: {parsed: {y: number}; dataIndex: number}) => { + const status = permitted[ctx.dataIndex] + ? 'validator permit' + : STAKES[ctx.dataIndex] === 0 + ? 'no permit (zero stake)' + : 'no permit — weights ignored'; + return `${ctx.parsed.y.toLocaleString()} α — ${status}`; + }, + }, + }, + }, + scales: { + x: { + grid: {display: false}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'neurons, sorted by stake weight', font: {size: 11}}, + }, + y: { + min: 0, + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'stake weight (α)', font: {size: 11}}, + }, + }, + }), + [permitted], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx index cd0711b198..ffd51d7334 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-owner-cut.tsx @@ -59,6 +59,17 @@ function BarSegment({ ); } +function focusCaption(focus: string | undefined): string { + switch (focus) { + case 'owner_cut_enabled': + return ' Focused on owner_cut_enabled: flip the highlighted toggle off and the owner segment vanishes — the full alpha_out flows to miners and validators, and the forgone cut is never stashed or paid retroactively.'; + case 'owner_cut_auto_lock_enabled': + return ' Focused on owner_cut_auto_lock_enabled: flip the highlighted toggle on and the owner segment turns hatched — the same cut is paid, then immediately conviction-locked on the owner coldkey instead of staying liquid.'; + default: + return ''; + } +} + export function HyperparamOwnerCut({ focus }: { focus?: string }) { const [tempoAlpha, setTempoAlpha] = useState(360); const [ownerCutEnabled, setOwnerCutEnabled] = useState(true); @@ -76,7 +87,7 @@ export function HyperparamOwnerCut({ focus }: { focus?: string }) { return (
{ownerLiquid > 0 && ( diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx index d31ed65914..d57b137b7a 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-pow-difficulty.tsx @@ -34,11 +34,45 @@ function clamp(value: number, lo: number, hi: number): number { return Math.min(Math.max(value, lo), hi); } +// Per-focus starting scenario: which bound the simulated difficulty walk rides, +// and what the panel caption should emphasize. +const SCENARIOS: Record< + string, + { floorLog: number; ceilLog: number; regs: number; target: number; caption: string } +> = { + difficulty: { + floorLog: 7, + ceilLog: 16, + regs: 6, + target: 2, + caption: + 'difficulty is a direct price in compute: hash_meets_difficulty passes with probability about 1 in difficulty, so a nonce costs ~difficulty hash attempts on average. The classic controller rescaled it by (regs + target) / (2 \u00d7 target) each adjustment interval, clamped to [min_difficulty, max_difficulty]. On the current runtime the register extrinsic routes to burned registration, so this controller no longer runs.', + }, + min_difficulty: { + floorLog: 7, + ceilLog: 16, + regs: 0, + target: 2, + caption: + 'This scenario starts with quiet demand (0 registrations vs a target of 2), so the controller decays difficulty every interval \u2014 until it lands on the bold min_difficulty floor and sits there. The floor is the one price the controller could never undercut. Drag the floor to its top stop (or use the button) for the u64::MAX disabled state.', + }, + max_difficulty: { + floorLog: 5, + ceilLog: 10, + regs: 12, + target: 2, + caption: + 'This scenario starts with a registration rush (12 registrations vs a target of 2), so the controller ratchets difficulty up every interval \u2014 until it hits the bold max_difficulty ceiling and pins there. The ceiling capped how expensive a PoW slot could get during a rush. The mainnet default is u64::MAX / 4.', + }, +}; + export function HyperparamPowDifficulty({ focus }: { focus?: string }) { - const [floorLog, setFloorLog] = useState(7); // min_difficulty = 1e7 (chain default) - const [ceilLog, setCeilLog] = useState(16); - const [regsPerInterval, setRegsPerInterval] = useState(6); - const [targetRegs, setTargetRegs] = useState(2); + const scenario = (focus && SCENARIOS[focus]) || SCENARIOS['difficulty']; + + const [floorLog, setFloorLog] = useState(scenario.floorLog); + const [ceilLog, setCeilLog] = useState(scenario.ceilLog); + const [regsPerInterval, setRegsPerInterval] = useState(scenario.regs); + const [targetRegs, setTargetRegs] = useState(scenario.target); const floor = fromLog(floorLog); const ceiling = Math.max(fromLog(ceilLog), floor); @@ -73,6 +107,9 @@ export function HyperparamPowDifficulty({ focus }: { focus?: string }) { : 'falling toward floor' : 'steady at target'; + const floorFocused = focus === 'min_difficulty'; + const ceilFocused = focus === 'max_difficulty'; + const data = useMemo( () => ({ labels: series.map((_, i) => `${i}`), @@ -88,26 +125,26 @@ export function HyperparamPowDifficulty({ focus }: { focus?: string }) { borderWidth: 1.5, }, { - label: 'min_difficulty (floor)', + label: floorFocused ? 'min_difficulty (floor) \u2190 this page' : 'min_difficulty (floor)', data: series.map(() => floor), - borderColor: 'rgba(41, 41, 41, 0.35)', - borderDash: [4, 4], + borderColor: floorFocused ? 'rgb(41, 41, 41)' : 'rgba(41, 41, 41, 0.35)', + borderDash: floorFocused ? [6, 3] : [4, 4], fill: false, pointRadius: 0, - borderWidth: 1, + borderWidth: floorFocused ? 2.5 : 1, }, { - label: 'max_difficulty (ceiling)', + label: ceilFocused ? 'max_difficulty (ceiling) \u2190 this page' : 'max_difficulty (ceiling)', data: series.map(() => ceiling), - borderColor: 'rgba(41, 41, 41, 0.35)', - borderDash: [2, 3], + borderColor: ceilFocused ? 'rgb(41, 41, 41)' : 'rgba(41, 41, 41, 0.35)', + borderDash: ceilFocused ? [6, 3] : [2, 3], fill: false, pointRadius: 0, - borderWidth: 1, + borderWidth: ceilFocused ? 2.5 : 1, }, ], }), - [series, floor, ceiling], + [series, floor, ceiling, floorFocused, ceilFocused], ); const options = useMemo( @@ -146,10 +183,7 @@ export function HyperparamPowDifficulty({ focus }: { focus?: string }) { ); return ( - +
@@ -161,9 +195,13 @@ export function HyperparamPowDifficulty({ focus }: { focus?: string }) { hint={powDisabled ? 'PoW registration effectively disabled' : trend} />
+ +
+ {powDisabled ? ( + + ) : ( + + )} + + {powDisabled + ? 'difficulty is pinned at u64::MAX: no nonce can ever pass the seal check.' + : 'the sentinel state: a floor of u64::MAX pins difficulty at maximum.'} + +
); } diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-pow-toggle-dead-end.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-pow-toggle-dead-end.tsx new file mode 100644 index 0000000000..da4bcb87b9 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-pow-toggle-dead-end.tsx @@ -0,0 +1,59 @@ +'use client'; + +import { useState } from 'react'; +import { ExplainerPanel } from './explainer-panel'; + +export function HyperparamPowToggleDeadEnd() { + const [attempts, setAttempts] = useState(0); + + return ( + +
+
+

Trying to set the flag

+
+

sudo_set_network_pow_registration_allowed({attempts % 2 === 0 ? 'true' : 'false'})

+

  ↓

+

+ Err(POWRegistrationDisabled) +

+ {attempts > 0 && ( +

+ {attempts} attempt{attempts === 1 ? '' : 's'}, {attempts} rejection{attempts === 1 ? '' : 's'} — the + extrinsic writes nothing, ever +

+ )} +
+ +
+ +
+

What registration does meanwhile

+
+

register(block, nonce, work, …)

+

  ↓ work args ignored

+

do_register() — burned path

+

+ network_pow_registration_allowed +
+   ↪ read by nothing on this route +

+
+

+ The stored value (cleared to the default by migration) is still reported in the metagraph as + pow_registration_allowed, but no code path branches on it. +

+
+
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-registration-gate.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-registration-gate.tsx new file mode 100644 index 0000000000..4f4b6af577 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-registration-gate.tsx @@ -0,0 +1,80 @@ +'use client'; + +import { useState } from 'react'; +import { ExplainerPanel, ExplainerStat } from './explainer-panel'; + +const WINDOWS = 12; +const ATTEMPTS_PER_WINDOW = 2; + +// Initial history: gate open, closed for a stretch, reopened. +const INITIAL_GATE = Array.from({ length: WINDOWS }, (_, i) => i < 4 || i >= 8); + +export function HyperparamRegistrationGate() { + const [gate, setGate] = useState(INITIAL_GATE); + + const openWindows = gate.filter(Boolean).length; + const accepted = openWindows * ATTEMPTS_PER_WINDOW; + const rejected = (WINDOWS - openWindows) * ATTEMPTS_PER_WINDOW; + + return ( + +
+

registration_allowed over time (click to toggle)

+

blocks →

+
+ +
+ {gate.map((open, i) => ( + + ))} +
+ +
+ ■ gate open · □ gate closed + {'\u2713'} UID assigned · {'\u2717'} Err(SubNetRegistrationDisabled) +
+ +
+ + + +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-regs-cap-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-regs-cap-chart.tsx new file mode 100644 index 0000000000..064fe3952e --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-regs-cap-chart.tsx @@ -0,0 +1,173 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Filler, + Tooltip, +} from 'chart.js'; +import type { ChartData } from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip); + +const INTERVAL_BLOCKS = 360; // one root epoch (tempo) — the counter resets here +const SAMPLE_EVERY = 4; + +export function HyperparamRegsCapChart() { + const [target, setTarget] = useState(2); + const [attemptsPerInterval, setAttemptsPerInterval] = useState(10); + + const cap = 3 * target; + + const sim = useMemo(() => { + const xs: number[] = []; + const attempted: number[] = []; + const admitted: number[] = []; + let capHitBlock: number | null = null; + + for (let b = 0; b <= INTERVAL_BLOCKS; b += SAMPLE_EVERY) { + // Attempts arrive evenly spread across the interval. + const att = Math.floor((b * attemptsPerInterval) / INTERVAL_BLOCKS); + const adm = Math.min(att, cap); + if (capHitBlock === null && att >= cap && cap > 0) capHitBlock = b; + xs.push(b); + attempted.push(att); + admitted.push(adm); + } + + const totalAttempted = attemptsPerInterval; + const totalAdmitted = Math.min(totalAttempted, cap); + return { xs, attempted, admitted, capHitBlock, rejected: totalAttempted - totalAdmitted }; + }, [attemptsPerInterval, cap]); + + const data = useMemo(() => { + const datasets: ChartData<'line', number[]>['datasets'] = [ + { + label: 'admitted', + data: sim.admitted, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + stepped: true, + pointRadius: 0, + borderWidth: 1.5, + }, + { + label: 'attempted', + data: sim.attempted, + borderColor: 'rgba(41, 41, 41, 0.35)', + borderDash: [3, 3], + stepped: true, + pointRadius: 0, + borderWidth: 1, + fill: false, + }, + { + label: 'cap (3 × target)', + data: sim.xs.map(() => cap), + borderColor: 'rgb(41, 41, 41)', + borderDash: [6, 4], + pointRadius: 0, + borderWidth: 1.5, + fill: false, + }, + ]; + return { + labels: sim.xs.map((b) => `${b}`), + datasets, + }; + }, [sim, cap]); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `block ${sim.xs[idx] ?? 0} of interval`; + }, + label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => + `${ctx.dataset.label}: ${ctx.parsed.y}`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { maxTicksLimit: 8, font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'blocks into interval', font: { size: 11 } }, + }, + y: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + beginAtZero: true, + ticks: { + maxTicksLimit: 6, + precision: 0, + font: { family: 'FiraCode, monospace', size: 10 }, + }, + title: { display: true, text: 'registrations', font: { size: 11 } }, + }, + }, + }), + [sim.xs], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-regs-per-block-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-regs-per-block-chart.tsx new file mode 100644 index 0000000000..caf92864c6 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-regs-per-block-chart.tsx @@ -0,0 +1,141 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Tooltip } from 'chart.js'; +import { Bar } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip); + +// A bursty demand pattern: quiet blocks, then registration rushes. +const ARRIVALS_BASE = [1, 3, 0, 6, 2, 9, 1, 0, 4, 12, 3, 1]; + +export function HyperparamRegsPerBlockChart() { + const [cap, setCap] = useState(3); + const [surge, setSurge] = useState(1); + + const blocks = useMemo(() => { + return ARRIVALS_BASE.map((base) => { + const arriving = Math.round(base * surge); + // RegistrationsThisBlock starts at 0 every block (reset in on_initialize), + // so each block independently admits up to the cap. + const accepted = Math.min(arriving, cap); + return { arriving, accepted, rejected: arriving - accepted }; + }); + }, [cap, surge]); + + const totalAccepted = blocks.reduce((sum, b) => sum + b.accepted, 0); + const totalRejected = blocks.reduce((sum, b) => sum + b.rejected, 0); + const cappedBlocks = blocks.filter((b) => b.rejected > 0).length; + + const data = useMemo( + () => ({ + labels: blocks.map((_, i) => `${i + 1}`), + datasets: [ + { + label: 'accepted (counter fills up to cap)', + data: blocks.map((b) => b.accepted), + backgroundColor: 'rgba(41, 41, 41, 0.85)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + stack: 'regs', + }, + { + label: 'rejected: TooManyRegistrationsThisBlock', + data: blocks.map((b) => b.rejected), + backgroundColor: 'rgba(41, 41, 41, 0.12)', + borderColor: 'rgba(41, 41, 41, 0.4)', + borderWidth: 1, + stack: 'regs', + }, + ], + }), + [blocks], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { display: false }, + tooltip: { + callbacks: { + title: (items: { dataIndex: number }[]) => { + const idx = items[0]?.dataIndex ?? 0; + return `Block ${idx + 1} \u00b7 ${blocks[idx]?.arriving ?? 0} arriving`; + }, + label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => + `${ctx.dataset.label ?? ''}: ${ctx.parsed.y}`, + }, + }, + }, + scales: { + x: { + stacked: true, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'consecutive blocks (counter resets each block)', font: { size: 11 } }, + }, + y: { + stacked: true, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 }, precision: 0 }, + title: { display: true, text: 'registration attempts', font: { size: 11 } }, + }, + }, + }), + [blocks], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ + +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-serving-rate-limit-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-serving-rate-limit-chart.tsx new file mode 100644 index 0000000000..fea6552a2e --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-serving-rate-limit-chart.tsx @@ -0,0 +1,121 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +const TIMELINE_BLOCKS = 260; +const ATTEMPT_BLOCKS = [4, 20, 60, 72, 84, 130, 140, 190, 250]; +const DEFAULT_LIMIT = 50; + +type Attempt = { block: number; accepted: boolean; sinceLast: number | null }; + +// Mirrors axon_passes_rate_limit (pallets/subtensor/src/subnets/serving.rs): +// pass when rate_limit == 0 || last_serve == 0 || current − last >= rate_limit. +function simulate(rateLimit: number): Attempt[] { + let lastServe = 0; + return ATTEMPT_BLOCKS.map((block) => { + const sinceLast = lastServe === 0 ? null : block - lastServe; + const accepted = rateLimit === 0 || lastServe === 0 || block - lastServe >= rateLimit; + if (accepted) lastServe = block; + return { block, accepted, sinceLast }; + }); +} + +function wallClock(blocks: number): string { + const seconds = blocks * 12; + const minutes = Math.floor(seconds / 60); + const rest = seconds % 60; + if (minutes === 0) return `${seconds}s`; + return rest === 0 ? `${minutes}m` : `${minutes}m ${rest}s`; +} + +function attemptTitle(attempt: Attempt): string { + const since = attempt.sinceLast === null ? 'first serve' : `${attempt.sinceLast} blocks since last accepted serve`; + return `block ${attempt.block} — ${attempt.accepted ? 'accepted' : 'rejected (ServingRateLimitExceeded)'}, ${since}`; +} + +export function HyperparamServingRateLimitChart() { + const [rateLimit, setRateLimit] = useState(DEFAULT_LIMIT); + const attempts = useMemo(() => simulate(rateLimit), [rateLimit]); + const acceptedCount = attempts.filter((a) => a.accepted).length; + const pct = (block: number) => (block / TIMELINE_BLOCKS) * 100; + + return ( + +
+ {rateLimit > 0 && + attempts + .filter((a) => a.accepted) + .map((a) => ( +
+ ))} + {attempts.map((a) => + a.accepted ? ( +
+ ) : ( +
+ ), + )} +
+
+ {[0, 60, 120, 180, 240].map((block) => ( + + {block} + + ))} + block +
+ +
+ + + +
+ +
+ +
+ + ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-tempo-timeline.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-tempo-timeline.tsx new file mode 100644 index 0000000000..082e62c06d --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-tempo-timeline.tsx @@ -0,0 +1,161 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Filler, + Tooltip, + Legend, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler, Tooltip, Legend); + +const BLOCK_SECONDS = 12; +const BLOCKS_PER_DAY = 86_400 / BLOCK_SECONDS; +const EPOCHS_SHOWN = 3; + +function formatDuration(seconds: number): string { + if (seconds < 3600) return `${(seconds / 60).toFixed(0)} min`; + if (seconds < 86_400) return `${(seconds / 3600).toFixed(1)} h`; + return `${(seconds / 86_400).toFixed(1)} days`; +} + +export function HyperparamTempoTimeline() { + const [tempo, setTempo] = useState(360); + + // Sawtooth: emission accrues 1 α/block within an epoch and pays out at the + // boundary, mirroring should_run_epoch's `current_block − LastEpochBlock ≥ tempo`. + const sawtooth = useMemo(() => { + const points: {x: number; y: number}[] = []; + for (let e = 0; e < EPOCHS_SHOWN; e++) { + points.push({x: e * tempo, y: 0}); + points.push({x: (e + 1) * tempo, y: tempo}); + } + points.push({x: EPOCHS_SHOWN * tempo, y: 0}); + return points; + }, [tempo]); + + const boundaries = useMemo( + () => + Array.from({length: EPOCHS_SHOWN}, (_, e) => ({x: (e + 1) * tempo, y: tempo})), + [tempo], + ); + + const data = useMemo( + () => ({ + datasets: [ + { + label: 'Pending emission', + data: sawtooth, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgba(41, 41, 41, 0.08)', + fill: true, + tension: 0, + pointRadius: 0, + borderWidth: 1.5, + }, + { + label: 'Epoch fires', + data: boundaries, + borderColor: 'rgb(41, 41, 41)', + backgroundColor: 'rgb(41, 41, 41)', + showLine: false, + pointRadius: 3, + pointStyle: 'rectRot' as const, + }, + ], + }), + [sawtooth, boundaries], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: {mode: 'nearest' as const, intersect: false}, + plugins: { + legend: {display: false}, + tooltip: { + callbacks: { + title: (items: {parsed: {x: number}}[]) => { + const block = items[0]?.parsed.x ?? 0; + return `Block ${block} (${formatDuration(block * BLOCK_SECONDS)} in)`; + }, + label: (ctx: {parsed: {y: number}; datasetIndex: number}) => + ctx.datasetIndex === 1 + ? `epoch fires: ${ctx.parsed.y} α distributed` + : `pending ${ctx.parsed.y.toFixed(0)} α`, + }, + }, + }, + scales: { + x: { + type: 'linear' as const, + min: 0, + max: EPOCHS_SHOWN * tempo, + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: { + maxTicksLimit: 10, + font: {family: 'FiraCode, monospace', size: 10}, + callback: (value: string | number) => String(value), + }, + title: {display: true, text: 'blocks since last epoch reset', font: {size: 11}}, + }, + y: { + min: 0, + grid: {color: 'rgba(41, 41, 41, 0.06)'}, + ticks: {font: {family: 'FiraCode, monospace', size: 10}}, + title: {display: true, text: 'pending emission (α, at 1 α/block)', font: {size: 11}}, + }, + }, + }), + [tempo], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-transfers-enabled-flow.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-transfers-enabled-flow.tsx new file mode 100644 index 0000000000..0d596245d6 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-transfers-enabled-flow.tsx @@ -0,0 +1,142 @@ +'use client'; + +import { useState } from 'react'; +import { ExplainerPanel, ExplainerStat } from './explainer-panel'; + +const TRANSFER_AMOUNT = 25; +const INITIAL_A = 100; +const INITIAL_B = 40; + +function formatAlpha(value: number): string { + return `${value.toFixed(0)} α`; +} + +type LastAction = + | { kind: 'idle' } + | { kind: 'transferred' } + | { kind: 'blocked' } + | { kind: 'moved' }; + +function actionMessage(action: LastAction): string { + switch (action.kind) { + case 'idle': + return 'Try a transfer with the toggle on and off.'; + case 'transferred': + return `transfer_stake succeeded — ${TRANSFER_AMOUNT} α changed coldkeys. Any conviction lock follows the stake proportionally.`; + case 'blocked': + return 'transfer_stake failed with TransferDisallowed — TransferToggle is false on this subnet.'; + case 'moved': + return 'move_stake succeeded — same coldkey, so the flag is never consulted.'; + default: { + const exhaustive: never = action; + return exhaustive; + } + } +} + +export function HyperparamTransfersEnabledFlow() { + const [enabled, setEnabled] = useState(true); + const [stakeA, setStakeA] = useState(INITIAL_A); + const [stakeB, setStakeB] = useState(INITIAL_B); + const [action, setAction] = useState({ kind: 'idle' }); + + // Mirrors the TransferToggle check in stake_utils.rs: transfer_stake fails + // with TransferDisallowed when the toggle is off; same-coldkey moves skip it. + const attemptTransfer = () => { + if (!enabled) { + setAction({ kind: 'blocked' }); + return; + } + if (stakeA < TRANSFER_AMOUNT) return; + setStakeA((v) => v - TRANSFER_AMOUNT); + setStakeB((v) => v + TRANSFER_AMOUNT); + setAction({ kind: 'transferred' }); + }; + + const attemptMove = () => { + setAction({ kind: 'moved' }); + }; + + const reset = () => { + setStakeA(INITIAL_A); + setStakeB(INITIAL_B); + setAction({ kind: 'idle' }); + }; + + const buttonClass = 'border border-line bg-bg px-3 py-1.5 font-mono text-xs hover:bg-panel'; + const maxStake = INITIAL_A + INITIAL_B; + + const coldkeyBox = (label: string, stake: number) => ( +
+

{label}

+

{formatAlpha(stake)}

+
+
+
+
+ ); + + return ( + +
+ {coldkeyBox('coldkey A', stakeA)} +
+ transfer_stake + + → + + + {enabled ? 'allowed' : 'TransferDisallowed'} + +
+ {coldkeyBox('coldkey B', stakeB)} +
+ +

{actionMessage(action)}

+ +
+ + + + +
+ +
+ + +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx index 6e1ded96a0..a65e3df147 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-uid-lifecycle.tsx @@ -93,6 +93,19 @@ function pruneTarget( return bestImmune !== null ? (bestImmune as Candidate).uid : null; } +function focusCaption(focus: string | undefined): string { + switch (focus) { + case 'immunity_period': + return ' Focused on immunity_period: each immune slot shows how many registrations remain before its protection expires and it joins the prunable pool.'; + case 'max_allowed_uids': + return ' Focused on max_allowed_uids: the grid itself is the capacity — empty slots (+) absorb registrations for free, and once the boundary is hit every entrant must evict someone.'; + case 'owner_immune_neuron_limit': + return ' Focused on owner_immune_neuron_limit: O marks the owner hotkeys inside the limit (never pruned, oldest registrations first); o marks owner hotkeys beyond it, which compete like everyone else.'; + default: + return ''; + } +} + function eventMessage(event: SimEvent | null): string { if (event === null) return 'Press a register button to add a neuron.'; switch (event.kind) { @@ -209,18 +222,50 @@ export function HyperparamUidLifecycle({ focus }: { focus?: string }) { return ( -
+
= maxUids + ? ' outline outline-1 outline-offset-2 outline-[var(--bt-fg)]' + : '') + } + > {Array.from({ length: maxUids }, (_, uid) => { const slot = sim.slots[uid]; if (!slot) { - return
; + return ( +
+ {focus === 'max_allowed_uids' ? '+' : ''} +
+ ); } const isOwnerImmune = ownerImmune.has(uid); const isNewImmune = !isOwnerImmune && sim.tick - slot.registeredAt < immunityPeriod; + const immunityLeft = isNewImmune ? immunityPeriod - (sim.tick - slot.registeredAt) : 0; + const isOwnerBeyondLimit = slot.isOwner && !isOwnerImmune; const shade = slot.emission / maxEmission; - const status = isOwnerImmune ? ', owner-immune' : isNewImmune ? ', immune' : ''; + const status = isOwnerImmune + ? ', owner-immune' + : isNewImmune + ? `, immune (${immunityLeft} reg${immunityLeft === 1 ? '' : 's'} left)` + : ''; + // Focus-specific badge: immunity focus counts down the remaining + // protection; owner focus also marks owner hotkeys beyond the limit. + const badge = + focus === 'owner_immune_neuron_limit' && isOwnerBeyondLimit + ? 'o' + : isOwnerImmune + ? 'O' + : isNewImmune + ? focus === 'immunity_period' + ? `I${immunityLeft}` + : 'I' + : null; return (
0.55 ? 'text-white' : ''}>{uid} - {(isOwnerImmune || isNewImmune) && ( + {badge !== null && ( 0.55 ? 'text-white' : '') } > - {isOwnerImmune ? 'O' : 'I'} + {badge} )}
diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rate-limit-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rate-limit-chart.tsx new file mode 100644 index 0000000000..0ae05d1499 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rate-limit-chart.tsx @@ -0,0 +1,169 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + LineElement, + PointElement, + Tooltip, + Legend, +} from 'chart.js'; +import type { ChartData, ChartOptions } from 'chart.js'; +import { Chart } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + LineElement, + PointElement, + Tooltip, + Legend, +); + +/** Blocks at which the validator tries to submit weights. The validator's + * previous accepted submission is at block 0, so every attempt has a + * well-defined gap. */ +const ATTEMPT_BLOCKS = [10, 60, 130, 150, 210, 240, 320, 340]; +const SECONDS_PER_BLOCK = 12; + +interface Attempt { + block: number; + gap: number; + accepted: boolean; +} + +/** Mirrors the chain's check_rate_limit: an attempt passes when + * current_block - last_set >= weights_rate_limit, and an accepted + * submission resets LastUpdate. */ +function simulateAttempts(limit: number): Attempt[] { + let lastAccepted = 0; + return ATTEMPT_BLOCKS.map((block) => { + const gap = block - lastAccepted; + const accepted = gap >= limit; + if (accepted) lastAccepted = block; + return { block, gap, accepted }; + }); +} + +function formatMinutes(blocks: number): string { + const minutes = (blocks * SECONDS_PER_BLOCK) / 60; + return minutes >= 60 + ? `${(minutes / 60).toFixed(1)} h` + : `${minutes.toFixed(0)} min`; +} + +export function HyperparamWeightsRateLimitChart() { + const [limit, setLimit] = useState(100); + + const attempts = useMemo(() => simulateAttempts(limit), [limit]); + const acceptedCount = attempts.filter((a) => a.accepted).length; + + const data = useMemo>( + () => ({ + labels: attempts.map((a) => `block ${a.block}`), + datasets: [ + { + type: 'bar' as const, + label: 'blocks since last accepted', + data: attempts.map((a) => a.gap), + backgroundColor: attempts.map((a) => + a.accepted ? 'rgba(41, 41, 41, 0.75)' : 'rgba(41, 41, 41, 0.12)', + ), + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + { + type: 'line' as const, + label: 'weights_rate_limit', + data: attempts.map(() => limit), + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + borderDash: [4, 4], + pointRadius: 0, + }, + ], + }), + [attempts, limit], + ); + + const options = useMemo>( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { display: false }, + tooltip: { + filter: (item) => item.dataset.type !== 'line', + callbacks: { + label: (ctx) => { + const attempt = attempts[ctx.dataIndex]; + return attempt.accepted + ? `accepted — gap ${attempt.gap} ≥ limit ${limit}` + : `SettingWeightsTooFast — gap ${attempt.gap} < limit ${limit}`; + }, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + }, + y: { + min: 0, + suggestedMax: limit + 40, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'blocks since last accepted', font: { size: 11 } }, + }, + }, + }), + [attempts, limit], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx index fb5b21158c..dff49ea4bc 100644 --- a/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-rules.tsx @@ -42,6 +42,16 @@ function clipToLimit(weights: number[], limit: number): number[] { return clipped.map((w) => w / clippedTotal); } +const CLIPPING_CAPTIONS: Record = { + min_allowed_weights: + 'Drag the raw weights: only nonzero entries count toward the length check, so zeroing a miner can push a submission below min_allowed_weights and get it rejected with WeightVecLengthIsLow.', + max_weights_limit: + 'Drag the raw weights and the limit. The stored max_weights_limit caps the largest normalized share; the SDK clips and renormalizes to fit it, redistributing the excess (the on-chain check is currently pinned open at u16::MAX).', +}; + +const DEFAULT_CLIPPING_CAPTION = + 'Drag the raw weights and the limit. The chain rejects submissions whose largest normalized share exceeds max_weights_limit; the SDK instead clips and renormalizes, redistributing the excess.'; + function ClippingPlayground({ focus }: { focus?: string }) { const [weights, setWeights] = useState([80, 35, 20, 10, 0]); const [limitRaw, setLimitRaw] = useState(19661); // ~0.3 @@ -115,12 +125,14 @@ function ClippingPlayground({ focus }: { focus?: string }) { ); const highlight = (name: string) => - focus === name ? 'border border-line bg-bg p-3' : undefined; + focus === name ? 'border border-[rgb(41,41,41)] bg-bg p-3' : undefined; + const highlightStat = (name: string) => + focus === name ? 'border border-[rgb(41,41,41)]' : undefined; return (
@@ -132,16 +144,20 @@ function ClippingPlayground({ focus }: { focus?: string }) { value={`${(Math.max(...before) * 100).toFixed(1)}% → ${(Math.max(...after) * 100).toFixed(1)}%`} hint={wouldClip ? 'exceeds limit — clipped' : 'within limit — unchanged'} /> - - +
+ +
+
+ +
@@ -213,7 +229,14 @@ const EPOCH_LABEL: Record, string> = { expired: 'expired', }; -function CommitRevealTimeline() { +const TIMELINE_CAPTIONS: Record = { + commit_reveal_period: + 'Slide the period: the reveal is valid in exactly one epoch — commit epoch + commit_reveal_period. Earlier fails with RevealTooEarly; later, the commit is expired and dropped.', + commit_reveal_weights_enabled: + 'With the flag on, this is the only path weights can take: commit hidden, wait, reveal. Plain set_weights is rejected with CommitRevealEnabled; turn the flag off and commits are rejected instead.', +}; + +function CommitRevealTimeline({ focus }: { focus?: string }) { const [period, setPeriod] = useState(1); const delayBlocks = period * TEMPO_BLOCKS; @@ -222,7 +245,10 @@ function CommitRevealTimeline() { return (
{Array.from({length: TIMELINE_EPOCHS}, (_, epoch) => { @@ -257,7 +283,13 @@ function CommitRevealTimeline() { />
-
+
; + return ; } return ; } diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-weights-version-gate.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-version-gate.tsx new file mode 100644 index 0000000000..4f99445540 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-weights-version-gate.tsx @@ -0,0 +1,156 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + LineElement, + PointElement, + Tooltip, + Legend, +} from 'chart.js'; +import type { ChartData, ChartOptions } from 'chart.js'; +import { Chart } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register( + CategoryScale, + LinearScale, + BarElement, + LineElement, + PointElement, + Tooltip, + Legend, +); + +/** A fleet of validators, each stuck on the version key its software sends. + * The key is an opaque u64; these values just illustrate a release history. */ +const VALIDATORS = [ + { label: 'val A', versionKey: 0 }, + { label: 'val B', versionKey: 990 }, + { label: 'val C', versionKey: 1000 }, + { label: 'val D', versionKey: 1010 }, + { label: 'val E', versionKey: 1020 }, + { label: 'val F', versionKey: 1030 }, +]; + +/** Mirrors the chain's check_version_key: passes when the subnet's + * WeightsVersionKey is 0 (gate disabled) or the submitted key is >= it. */ +function passesGate(versionKey: number, required: number): boolean { + return required === 0 || versionKey >= required; +} + +export function HyperparamWeightsVersionGate() { + const [required, setRequired] = useState(1010); + + const accepted = VALIDATORS.filter((v) => passesGate(v.versionKey, required)); + + const data = useMemo>( + () => ({ + labels: VALIDATORS.map((v) => v.label), + datasets: [ + { + type: 'bar' as const, + label: 'submitted version_key', + data: VALIDATORS.map((v) => v.versionKey), + backgroundColor: VALIDATORS.map((v) => + passesGate(v.versionKey, required) + ? 'rgba(41, 41, 41, 0.75)' + : 'rgba(41, 41, 41, 0.12)', + ), + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + { + type: 'line' as const, + label: 'weights_version', + data: VALIDATORS.map(() => required), + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + borderDash: [4, 4], + pointRadius: 0, + }, + ], + }), + [required], + ); + + const options = useMemo>( + () => ({ + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { display: false }, + tooltip: { + filter: (item) => item.dataset.type !== 'line', + callbacks: { + label: (ctx) => { + const validator = VALIDATORS[ctx.dataIndex]; + if (required === 0) return `accepted — gate disabled (weights_version = 0)`; + return passesGate(validator.versionKey, required) + ? `accepted — key ${validator.versionKey} ≥ ${required}` + : `IncorrectWeightVersionKey — key ${validator.versionKey} < ${required}`; + }, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + }, + y: { + min: 0, + max: 1100, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + title: { display: true, text: 'version_key sent', font: { size: 11 } }, + }, + }, + }), + [required], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/docs/hyperparam-yuma3-chart.tsx b/website/apps/bittensor-website/src/components/docs/hyperparam-yuma3-chart.tsx new file mode 100644 index 0000000000..8328c2ab65 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/hyperparam-yuma3-chart.tsx @@ -0,0 +1,155 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + BarElement, + Tooltip, + Legend, +} from 'chart.js'; +import { Bar } from 'react-chartjs-2'; +import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; + +ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend); + +// Two validators, two miners. V1 splits its weight; V2 goes all-in on M1. +const WEIGHTS = [ + [0.5, 0.5], // V1 + [1.0, 0.0], // V2 +]; + +function normalize(v: number[]): number[] { + const sum = v.reduce((a, b) => a + b, 0); + return sum > 0 ? v.map((x) => x / sum) : v; +} + +// Steady state assumed (EMA bonds have converged onto the weights), which isolates +// the structural difference between the two dividend paths in run_epoch.rs. +function dividends(stakes: number[], yuma3: boolean): number[] { + const incentive = normalize( + WEIGHTS[0].map((_, j) => stakes.reduce((acc, s, i) => acc + s * WEIGHTS[i][j], 0)), + ); + + // Classic: bonds are W ∘ S column-normalized, so stake enters the bond matrix. + // Yuma3: bonds are the validator's own weight proportions (get_bonds_fixed_proportion), + // column-normalized, and stake scales the dividend once at the end. + const bond = (i: number, j: number) => (yuma3 ? WEIGHTS[i][j] : WEIGHTS[i][j] * stakes[i]); + const colSums = WEIGHTS[0].map((_, j) => stakes.reduce((acc, _s, i) => acc + bond(i, j), 0)); + const perValidator = stakes.map((_s, i) => + incentive.reduce((acc, inc, j) => acc + (colSums[j] > 0 ? bond(i, j) / colSums[j] : 0) * inc, 0), + ); + + return normalize(yuma3 ? perValidator.map((d, i) => d * stakes[i]) : perValidator); +} + +export function HyperparamYuma3Chart() { + const [bigStake, setBigStake] = useState(0.8); + + const stakes = useMemo(() => [1 - bigStake, bigStake], [bigStake]); + const classic = useMemo(() => dividends(stakes, false), [stakes]); + const yuma3 = useMemo(() => dividends(stakes, true), [stakes]); + + const data = useMemo( + () => ({ + labels: ['V1 (splits 50/50)', 'V2 (all-in on M1)'], + datasets: [ + { + label: 'classic dividends (yuma3 off)', + data: classic, + backgroundColor: 'rgba(41, 41, 41, 0.3)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + { + label: 'Yuma3 dividends (yuma3 on)', + data: yuma3, + backgroundColor: 'rgba(41, 41, 41, 0.85)', + borderColor: 'rgb(41, 41, 41)', + borderWidth: 1, + }, + ], + }), + [classic, yuma3], + ); + + const options = useMemo( + () => ({ + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index' as const, intersect: false }, + plugins: { + legend: { + display: true, + position: 'bottom' as const, + labels: { font: { family: 'FiraCode, monospace', size: 10 }, boxWidth: 12 }, + }, + tooltip: { + callbacks: { + label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => + `${ctx.dataset.label ?? ''}: ${(ctx.parsed.y * 100).toFixed(1)}%`, + }, + }, + }, + scales: { + x: { + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { font: { family: 'FiraCode, monospace', size: 10 } }, + }, + y: { + min: 0, + max: 1, + grid: { color: 'rgba(41, 41, 41, 0.06)' }, + ticks: { + font: { family: 'FiraCode, monospace', size: 10 }, + callback: (v: string | number) => `${Math.round(Number(v) * 100)}%`, + }, + title: { display: true, text: 'share of validator dividends', font: { size: 11 } }, + }, + }, + }), + [], + ); + + return ( + +
+ +
+ +
+ + + +
+ +
+ +
+
+ ); +} diff --git a/website/apps/bittensor-website/src/components/mdx.tsx b/website/apps/bittensor-website/src/components/mdx.tsx index 1aeaac7339..70ee9d3700 100644 --- a/website/apps/bittensor-website/src/components/mdx.tsx +++ b/website/apps/bittensor-website/src/components/mdx.tsx @@ -9,13 +9,29 @@ import { ConvictionModeComparison } from './docs/conviction-mode-comparison'; import { ConvictionSubnetScenario } from './docs/conviction-subnet-scenario'; import { EmissionFlowDiagram } from './docs/emission-flow-diagram'; import { EmissionNetworkSnapshot } from './docs/emission-network-snapshot'; +import { HyperparamActivityCutoffChart } from './docs/hyperparam-activity-cutoff-chart'; +import { HyperparamBondsPenaltyChart } from './docs/hyperparam-bonds-penalty-chart'; +import { HyperparamBondsResetChart } from './docs/hyperparam-bonds-reset-chart'; import { HyperparamBurnController } from './docs/hyperparam-burn-controller'; +import { HyperparamChildkeyTakeRange } from './docs/hyperparam-childkey-take-range'; import { HyperparamConsensusSigmoid } from './docs/hyperparam-consensus-sigmoid'; +import { HyperparamMaxValidatorsChart } from './docs/hyperparam-max-validators-chart'; +import { HyperparamLegacyAdjustment } from './docs/hyperparam-legacy-adjustment'; import { HyperparamLiquidAlpha } from './docs/hyperparam-liquid-alpha'; import { HyperparamOwnerCut } from './docs/hyperparam-owner-cut'; import { HyperparamPowDifficulty } from './docs/hyperparam-pow-difficulty'; +import { HyperparamPowToggleDeadEnd } from './docs/hyperparam-pow-toggle-dead-end'; +import { HyperparamRegistrationGate } from './docs/hyperparam-registration-gate'; +import { HyperparamRegsCapChart } from './docs/hyperparam-regs-cap-chart'; +import { HyperparamRegsPerBlockChart } from './docs/hyperparam-regs-per-block-chart'; +import { HyperparamServingRateLimitChart } from './docs/hyperparam-serving-rate-limit-chart'; +import { HyperparamTempoTimeline } from './docs/hyperparam-tempo-timeline'; +import { HyperparamTransfersEnabledFlow } from './docs/hyperparam-transfers-enabled-flow'; import { HyperparamUidLifecycle } from './docs/hyperparam-uid-lifecycle'; +import { HyperparamWeightsRateLimitChart } from './docs/hyperparam-weights-rate-limit-chart'; import { HyperparamWeightsRules } from './docs/hyperparam-weights-rules'; +import { HyperparamWeightsVersionGate } from './docs/hyperparam-weights-version-gate'; +import { HyperparamYuma3Chart } from './docs/hyperparam-yuma3-chart'; import { RegistrationBurnTimeline } from './docs/registration-burn-timeline'; import { RootProportionExplainer } from './docs/root-proportion-explainer'; import { SubnetEmissionShareChart } from './docs/subnet-emission-share-chart'; @@ -119,13 +135,29 @@ export function getMDXComponents(components?: MDXComponents) { ConvictionModeComparison, EvmAddressDomains, EvmMoneyFlows, + HyperparamActivityCutoffChart, + HyperparamBondsPenaltyChart, + HyperparamBondsResetChart, HyperparamBurnController, + HyperparamChildkeyTakeRange, HyperparamConsensusSigmoid, + HyperparamMaxValidatorsChart, + HyperparamLegacyAdjustment, HyperparamLiquidAlpha, HyperparamOwnerCut, HyperparamPowDifficulty, + HyperparamPowToggleDeadEnd, + HyperparamRegistrationGate, + HyperparamRegsCapChart, + HyperparamRegsPerBlockChart, + HyperparamServingRateLimitChart, + HyperparamTempoTimeline, + HyperparamTransfersEnabledFlow, HyperparamUidLifecycle, + HyperparamWeightsRateLimitChart, HyperparamWeightsRules, + HyperparamWeightsVersionGate, + HyperparamYuma3Chart, ...components, } satisfies MDXComponents; } From 8ab26eb5e7a67f20b46c2f11c5a18771968a5c99 Mon Sep 17 00:00:00 2001 From: unarbos Date: Tue, 14 Jul 2026 10:17:31 -0600 Subject: [PATCH 06/43] add activity_cutoff_factor hyperparameter, expose derived hyperparams, and split error docs into per-error pages Co-authored-by: Cursor --- README.md | 2 +- docs/concepts/meta.json | 2 +- docs/concepts/money.mdx | 4 +- docs/concepts/staking-pools.mdx | 170 +++ docs/errors.mdx | 442 ------- docs/errors/already-exists.mdx | 50 + docs/errors/chain/AccountNotAllowedCommit.mdx | 16 + .../chain/AccountRejectsLockedAlpha.mdx | 16 + docs/errors/chain/ActiveLockExists.mdx | 16 + .../ActivityCutoffFactorMilliOutOfBounds.mdx | 16 + docs/errors/chain/ActivityCutoffTooLow.mdx | 16 + .../chain/AddStakeBurnRateLimitExceeded.mdx | 16 + ...minActionProhibitedDuringWeightsWindow.mdx | 16 + docs/errors/chain/AllNetworksInImmunity.mdx | 16 + docs/errors/chain/AlphaHighTooLow.mdx | 16 + docs/errors/chain/AlphaLowOutOfRange.mdx | 16 + docs/errors/chain/AlreadyApproved.mdx | 16 + docs/errors/chain/AlreadyDeposited.mdx | 16 + docs/errors/chain/AlreadyFinalized.mdx | 16 + docs/errors/chain/AlreadyFinalizing.mdx | 16 + docs/errors/chain/AlreadyNoted.mdx | 16 + docs/errors/chain/AlreadyStored.mdx | 16 + docs/errors/chain/AmountTooLow.mdx | 16 + .../AnnouncedColdkeyHashDoesNotMatch.mdx | 16 + .../AnnouncementDepositInvariantViolated.mdx | 16 + docs/errors/chain/ArithmeticOverflow.mdx | 16 + .../errors/chain/AutoEpochAlreadyImminent.mdx | 16 + docs/errors/chain/BadEncKeyLen.mdx | 16 + docs/errors/chain/BalanceLow.mdx | 16 + docs/errors/chain/BalanceWithdrawalError.mdx | 16 + .../chain/BeneficiaryDoesNotOwnHotkey.mdx | 16 + docs/errors/chain/BlockDurationTooLong.mdx | 16 + docs/errors/chain/BlockDurationTooShort.mdx | 16 + .../chain/BondsMovingAverageMaxReached.mdx | 16 + docs/errors/chain/CallDisabled.mdx | 16 + docs/errors/chain/CallFiltered.mdx | 16 + docs/errors/chain/CallUnavailable.mdx | 16 + .../chain/CanNotSetRootNetworkWeights.mdx | 16 + .../CannotAddSelfAsDelegateDependency.mdx | 16 + docs/errors/chain/CannotAffordLockCost.mdx | 16 + .../chain/CannotBurnOrRecycleOnRootSubnet.mdx | 16 + docs/errors/chain/CannotEndInPast.mdx | 16 + docs/errors/chain/CannotReleaseYet.mdx | 16 + docs/errors/chain/CannotUseSystemAccount.mdx | 16 + docs/errors/chain/CapNotRaised.mdx | 16 + docs/errors/chain/CapRaised.mdx | 16 + docs/errors/chain/CapTooLow.mdx | 16 + docs/errors/chain/ChainIdMismatch.mdx | 16 + docs/errors/chain/ChangePending.mdx | 16 + .../errors/chain/ChildParentInconsistency.mdx | 16 + docs/errors/chain/CodeInUse.mdx | 16 + docs/errors/chain/CodeInfoNotFound.mdx | 16 + docs/errors/chain/CodeNotFound.mdx | 16 + docs/errors/chain/CodeRejected.mdx | 16 + docs/errors/chain/CodeTooLarge.mdx | 16 + .../errors/chain/ColdKeyAlreadyAssociated.mdx | 16 + .../chain/ColdkeySwapAlreadyDisputed.mdx | 16 + docs/errors/chain/ColdkeySwapAnnounced.mdx | 16 + .../chain/ColdkeySwapAnnouncementNotFound.mdx | 16 + .../errors/chain/ColdkeySwapClearTooEarly.mdx | 16 + docs/errors/chain/ColdkeySwapDisputed.mdx | 16 + .../chain/ColdkeySwapReannouncedTooEarly.mdx | 16 + docs/errors/chain/ColdkeySwapTooEarly.mdx | 16 + docs/errors/chain/CommitRevealDisabled.mdx | 16 + docs/errors/chain/CommitRevealEnabled.mdx | 16 + .../errors/chain/CommittingWeightsTooFast.mdx | 16 + docs/errors/chain/ContractNotFound.mdx | 16 + docs/errors/chain/ContractReverted.mdx | 16 + docs/errors/chain/ContractTrapped.mdx | 16 + docs/errors/chain/ContributionPeriodEnded.mdx | 16 + .../chain/ContributionPeriodNotEnded.mdx | 16 + docs/errors/chain/ContributionTooLow.mdx | 16 + docs/errors/chain/CreateOriginNotAllowed.mdx | 16 + docs/errors/chain/CurrencyError.mdx | 16 + docs/errors/chain/DeadAccount.mdx | 16 + docs/errors/chain/DecodingFailed.mdx | 16 + .../chain/DelegateDependencyAlreadyExists.mdx | 16 + .../chain/DelegateDependencyNotFound.mdx | 16 + docs/errors/chain/DelegateTakeTooHigh.mdx | 16 + docs/errors/chain/DelegateTakeTooLow.mdx | 16 + .../chain/DelegateTxRateLimitExceeded.mdx | 16 + docs/errors/chain/DeltaZero.mdx | 16 + .../errors/chain/DepositCannotBeWithdrawn.mdx | 16 + docs/errors/chain/DepositTooLow.mdx | 16 + docs/errors/chain/Deprecated.mdx | 16 + docs/errors/chain/DisabledTemporarily.mdx | 16 + docs/errors/chain/DrandConnectionFailure.mdx | 16 + docs/errors/chain/Duplicate.mdx | 16 + docs/errors/chain/DuplicateChild.mdx | 16 + docs/errors/chain/DuplicateContract.mdx | 16 + docs/errors/chain/DuplicateOffenceReport.mdx | 16 + docs/errors/chain/DuplicateOrderInBatch.mdx | 16 + docs/errors/chain/DuplicateUids.mdx | 16 + .../DynamicTempoBlockedByCommitReveal.mdx | 16 + docs/errors/chain/Entered.mdx | 16 + .../chain/EpochTriggerAlreadyPending.mdx | 16 + .../EvmKeyAssociateRateLimitExceeded.mdx | 16 + .../chain/EvmKeyAssociationLimitExceeded.mdx | 16 + docs/errors/chain/ExistentialDeposit.mdx | 16 + docs/errors/chain/ExistingVestingSchedule.mdx | 16 + docs/errors/chain/Exited.mdx | 16 + .../chain/ExpectedBeneficiaryOrigin.mdx | 16 + docs/errors/chain/Expendability.mdx | 16 + docs/errors/chain/ExpiredWeightCommit.mdx | 16 + .../chain/FailedToExtractRuntimeVersion.mdx | 16 + docs/errors/chain/FailedToSchedule.mdx | 16 + docs/errors/chain/FaucetDisabled.mdx | 16 + docs/errors/chain/FeeOverflow.mdx | 16 + docs/errors/chain/FeeRateTooHigh.mdx | 16 + .../FirstEmissionBlockNumberAlreadySet.mdx | 16 + docs/errors/chain/GasLimitTooHigh.mdx | 16 + docs/errors/chain/GasLimitTooLow.mdx | 16 + docs/errors/chain/GasPriceTooLow.mdx | 16 + docs/errors/chain/HotKeyAccountNotExists.mdx | 16 + docs/errors/chain/HotKeyAlreadyDelegate.mdx | 16 + .../chain/HotKeyAlreadyRegisteredInSubNet.mdx | 16 + .../chain/HotKeyNotRegisteredInNetwork.mdx | 16 + .../chain/HotKeyNotRegisteredInSubNet.mdx | 16 + .../chain/HotKeySetTxRateLimitExceeded.mdx | 16 + .../HotKeySwapOnSubnetIntervalNotPassed.mdx | 16 + .../chain/IncorrectCommitRevealVersion.mdx | 16 + .../chain/IncorrectPartialFillAmount.mdx | 16 + .../chain/IncorrectWeightVersionKey.mdx | 16 + docs/errors/chain/Indeterministic.mdx | 16 + docs/errors/chain/InputForwarded.mdx | 16 + docs/errors/chain/InputLengthsUnequal.mdx | 16 + docs/errors/chain/InsufficientBalance.mdx | 16 + docs/errors/chain/InsufficientInputAmount.mdx | 16 + docs/errors/chain/InsufficientLiquidity.mdx | 16 + .../errors/chain/InsufficientStakeForLock.mdx | 16 + docs/errors/chain/InvalidCallFlags.mdx | 16 + docs/errors/chain/InvalidChainId.mdx | 16 + docs/errors/chain/InvalidChild.mdx | 16 + docs/errors/chain/InvalidChildkeyTake.mdx | 16 + docs/errors/chain/InvalidCrowdloanId.mdx | 16 + docs/errors/chain/InvalidDerivedAccount.mdx | 16 + docs/errors/chain/InvalidDerivedAccountId.mdx | 16 + docs/errors/chain/InvalidDifficulty.mdx | 16 + .../errors/chain/InvalidEquivocationProof.mdx | 16 + .../chain/InvalidFinalizationConfig.mdx | 16 + docs/errors/chain/InvalidIdentity.mdx | 16 + docs/errors/chain/InvalidIpAddress.mdx | 16 + docs/errors/chain/InvalidIpType.mdx | 16 + .../errors/chain/InvalidKeyOwnershipProof.mdx | 16 + docs/errors/chain/InvalidLeaseBeneficiary.mdx | 16 + docs/errors/chain/InvalidLiquidityValue.mdx | 16 + docs/errors/chain/InvalidNonce.mdx | 16 + docs/errors/chain/InvalidNumRootClaim.mdx | 16 + docs/errors/chain/InvalidOrigin.mdx | 16 + docs/errors/chain/InvalidPort.mdx | 16 + .../chain/InvalidRecoveredPublicKey.mdx | 16 + .../chain/InvalidRevealCommitHashNotMatch.mdx | 16 + docs/errors/chain/InvalidRevealRound.mdx | 16 + .../chain/InvalidRootClaimThreshold.mdx | 16 + docs/errors/chain/InvalidRoundNumber.mdx | 16 + docs/errors/chain/InvalidSchedule.mdx | 16 + docs/errors/chain/InvalidSeal.mdx | 16 + docs/errors/chain/InvalidSignature.mdx | 16 + docs/errors/chain/InvalidSpecName.mdx | 16 + docs/errors/chain/InvalidSubnetNumber.mdx | 16 + docs/errors/chain/InvalidTickRange.mdx | 16 + docs/errors/chain/InvalidValue.mdx | 16 + .../chain/InvalidVotingPowerEmaAlpha.mdx | 16 + docs/errors/chain/InvalidWorkBlock.mdx | 16 + docs/errors/chain/IssuanceDeactivated.mdx | 16 + docs/errors/chain/LeaseCannotEndInThePast.mdx | 16 + docs/errors/chain/LeaseDoesNotExist.mdx | 16 + docs/errors/chain/LeaseHasNoEndBlock.mdx | 16 + docs/errors/chain/LeaseHasNotEnded.mdx | 16 + docs/errors/chain/LeaseNetuidNotFound.mdx | 16 + docs/errors/chain/LimitOrdersDisabled.mdx | 16 + docs/errors/chain/LiquidAlphaDisabled.mdx | 16 + docs/errors/chain/LiquidityRestrictions.mdx | 16 + docs/errors/chain/LockHotkeyMismatch.mdx | 16 + docs/errors/chain/LockIdOverFlow.mdx | 16 + .../MaxAllowedUIdsLessThanCurrentUIds.mdx | 16 + ...edUidsGreaterThanDefaultMaxAllowedUids.mdx | 16 + .../MaxAllowedUidsLessThanMinAllowedUids.mdx | 16 + docs/errors/chain/MaxCallDepthReached.mdx | 16 + docs/errors/chain/MaxContributionReached.mdx | 16 + docs/errors/chain/MaxContributorsReached.mdx | 16 + .../chain/MaxDelegateDependenciesReached.mdx | 16 + .../chain/MaxValidatorsLargerThanMaxUIds.mdx | 16 + docs/errors/chain/MaxWeightExceeded.mdx | 16 + docs/errors/chain/MaxWeightTooLow.mdx | 16 + .../chain/MaximumContributionTooLow.mdx | 16 + docs/errors/chain/MechanismDoesNotExist.mdx | 16 + docs/errors/chain/MigrationInProgress.mdx | 16 + .../MinAllowedUidsGreaterThanCurrentUids.mdx | 16 + ...inAllowedUidsGreaterThanMaxAllowedUids.mdx | 16 + .../chain/MinimumContributionTooHigh.mdx | 16 + .../chain/MinimumContributionTooLow.mdx | 16 + docs/errors/chain/MinimumThreshold.mdx | 16 + .../chain/MultiBlockMigrationsOngoing.mdx | 16 + docs/errors/chain/Named.mdx | 16 + .../chain/NeedWaitingMoreBlocksToStarCall.mdx | 16 + .../errors/chain/NegativeSigmoidSteepness.mdx | 16 + .../chain/NetworkDissolveAlreadyQueued.mdx | 16 + .../chain/NetworkTxRateLimitExceeded.mdx | 16 + docs/errors/chain/NeuronNoValidatorPermit.mdx | 16 + docs/errors/chain/NewColdKeyIsHotkey.mdx | 16 + docs/errors/chain/NewHotKeyIsSameWithOld.mdx | 16 + .../chain/NewHotKeyNotCleanForRootSwap.mdx | 16 + docs/errors/chain/NoApprovalsNeeded.mdx | 16 + docs/errors/chain/NoChainExtension.mdx | 16 + docs/errors/chain/NoContribution.mdx | 16 + docs/errors/chain/NoDeposit.mdx | 16 + docs/errors/chain/NoExistingLock.mdx | 16 + docs/errors/chain/NoMigrationPerformed.mdx | 16 + docs/errors/chain/NoNeuronIdAvailable.mdx | 16 + docs/errors/chain/NoPermission.mdx | 16 + docs/errors/chain/NoSelfProxy.mdx | 16 + docs/errors/chain/NoTimepoint.mdx | 16 + docs/errors/chain/NoWeightsCommitFound.mdx | 16 + docs/errors/chain/NonAssociatedColdKey.mdx | 16 + docs/errors/chain/NonDefaultComposite.mdx | 16 + docs/errors/chain/NonZeroRefCount.mdx | 16 + docs/errors/chain/NoneValue.mdx | 16 + docs/errors/chain/NotAllowed.mdx | 16 + docs/errors/chain/NotAuthorized.mdx | 16 + docs/errors/chain/NotConfigured.mdx | 16 + .../chain/NotEnoughAlphaOutToRecycle.mdx | 16 + .../NotEnoughBalanceToPaySwapColdKey.mdx | 16 + .../chain/NotEnoughBalanceToPaySwapHotKey.mdx | 16 + docs/errors/chain/NotEnoughBalanceToStake.mdx | 16 + docs/errors/chain/NotEnoughStake.mdx | 16 + .../chain/NotEnoughStakeToSetChildkeys.mdx | 16 + .../chain/NotEnoughStakeToSetWeights.mdx | 16 + .../errors/chain/NotEnoughStakeToWithdraw.mdx | 16 + docs/errors/chain/NotFound.mdx | 16 + docs/errors/chain/NotNoted.mdx | 16 + docs/errors/chain/NotOwner.mdx | 16 + .../errors/chain/NotPermittedOnRootSubnet.mdx | 16 + docs/errors/chain/NotProxy.mdx | 16 + docs/errors/chain/NotReadyToDissolve.mdx | 16 + docs/errors/chain/NotRequested.mdx | 16 + docs/errors/chain/NotRootSubnet.mdx | 16 + docs/errors/chain/NotSubnetOwner.mdx | 16 + docs/errors/chain/NothingAuthorized.mdx | 16 + docs/errors/chain/OrderAlreadyProcessed.mdx | 16 + docs/errors/chain/OrderCancelled.mdx | 16 + docs/errors/chain/OrderExpired.mdx | 16 + docs/errors/chain/OrderNetUidMismatch.mdx | 16 + docs/errors/chain/OutOfBounds.mdx | 16 + docs/errors/chain/OutOfGas.mdx | 16 + docs/errors/chain/OutOfTransientStorage.mdx | 16 + docs/errors/chain/OutputBufferTooSmall.mdx | 16 + docs/errors/chain/Overflow.mdx | 16 + docs/errors/chain/POWRegistrationDisabled.mdx | 16 + .../chain/PalletHotkeyNotRegistered.mdx | 16 + docs/errors/chain/PartialFillsNotEnabled.mdx | 16 + docs/errors/chain/PauseFailed.mdx | 16 + docs/errors/chain/PaymentOverflow.mdx | 16 + docs/errors/chain/PreLogExists.mdx | 16 + docs/errors/chain/PriceConditionNotMet.mdx | 16 + docs/errors/chain/PriceLimitExceeded.mdx | 16 + docs/errors/chain/ProportionOverflow.mdx | 16 + docs/errors/chain/PulseVerificationError.mdx | 16 + docs/errors/chain/RandomSubjectTooLong.mdx | 16 + docs/errors/chain/ReentranceDenied.mdx | 16 + docs/errors/chain/Reentrancy.mdx | 16 + .../RegistrationNotPermittedOnRootSubnet.mdx | 16 + .../chain/RegistrationPriceLimitExceeded.mdx | 16 + docs/errors/chain/RelayerMissMatch.mdx | 16 + .../chain/RelayerRequiredForPartialFill.mdx | 16 + docs/errors/chain/Requested.mdx | 16 + docs/errors/chain/RequireSudo.mdx | 16 + docs/errors/chain/RescheduleNoChange.mdx | 16 + docs/errors/chain/ReservesOutOfBalance.mdx | 16 + docs/errors/chain/ReservesTooLow.mdx | 16 + docs/errors/chain/ResumeFailed.mdx | 16 + docs/errors/chain/RevealPeriodTooLarge.mdx | 16 + docs/errors/chain/RevealPeriodTooSmall.mdx | 16 + docs/errors/chain/RevealTooEarly.mdx | 16 + docs/errors/chain/RootNetUidNotAllowed.mdx | 16 + docs/errors/chain/RootNetworkDoesNotExist.mdx | 16 + .../chain/SameAutoStakeHotkeyAlreadySet.mdx | 16 + docs/errors/chain/SameNetuid.mdx | 16 + docs/errors/chain/SenderInSignatories.mdx | 16 + .../errors/chain/ServingRateLimitExceeded.mdx | 16 + docs/errors/chain/SettingWeightsTooFast.mdx | 16 + docs/errors/chain/SignatoriesOutOfOrder.mdx | 16 + docs/errors/chain/SlippageTooHigh.mdx | 16 + docs/errors/chain/SpaceLimitExceeded.mdx | 16 + .../chain/SpecVersionNeedsToIncrease.mdx | 16 + docs/errors/chain/StakeTooLowForRoot.mdx | 16 + docs/errors/chain/StakeUnavailable.mdx | 16 + .../errors/chain/StakingRateLimitExceeded.mdx | 16 + docs/errors/chain/StartCallNotReady.mdx | 16 + docs/errors/chain/StateChangeDenied.mdx | 16 + .../chain/StorageDepositLimitExhausted.mdx | 16 + .../chain/StorageDepositNotEnoughFunds.mdx | 16 + docs/errors/chain/StorageOverflow.mdx | 16 + .../chain/SubNetRegistrationDisabled.mdx | 16 + .../chain/SubnetBuybackRateLimitExceeded.mdx | 16 + docs/errors/chain/SubnetDoesNotExist.mdx | 16 + docs/errors/chain/SubnetLimitReached.mdx | 16 + docs/errors/chain/SubnetNotExists.mdx | 16 + docs/errors/chain/SubtokenDisabled.mdx | 16 + docs/errors/chain/SwapInputTooLarge.mdx | 16 + docs/errors/chain/SwapReturnedZero.mdx | 16 + docs/errors/chain/SymbolAlreadyInUse.mdx | 16 + docs/errors/chain/SymbolDoesNotExist.mdx | 16 + docs/errors/chain/TargetBlockNumberInPast.mdx | 16 + docs/errors/chain/TempoOutOfBounds.mdx | 16 + docs/errors/chain/TerminatedInConstructor.mdx | 16 + .../errors/chain/TerminatedWhileReentrant.mdx | 16 + docs/errors/chain/TooBig.mdx | 16 + docs/errors/chain/TooFew.mdx | 16 + docs/errors/chain/TooFewSignatories.mdx | 16 + docs/errors/chain/TooMany.mdx | 16 + docs/errors/chain/TooManyCalls.mdx | 16 + docs/errors/chain/TooManyChildren.mdx | 16 + .../chain/TooManyFieldsInCommitmentInfo.mdx | 16 + docs/errors/chain/TooManyFreezes.mdx | 16 + docs/errors/chain/TooManyHolds.mdx | 16 + .../errors/chain/TooManyPendingExtrinsics.mdx | 16 + .../chain/TooManyRegistrationsThisBlock.mdx | 16 + .../TooManyRegistrationsThisInterval.mdx | 16 + docs/errors/chain/TooManyReserves.mdx | 16 + docs/errors/chain/TooManySignatories.mdx | 16 + docs/errors/chain/TooManyTopics.mdx | 16 + docs/errors/chain/TooManyUIDsPerMechanism.mdx | 16 + .../errors/chain/TooManyUnrevealedCommits.mdx | 16 + docs/errors/chain/TooSoon.mdx | 16 + .../chain/TransactionMustComeFromEOA.mdx | 16 + .../chain/TransactorAccountShouldBeHotKey.mdx | 16 + docs/errors/chain/TransferDisallowed.mdx | 16 + docs/errors/chain/TransferFailed.mdx | 16 + ...TrimmingWouldExceedMaxImmunePercentage.mdx | 16 + .../chain/TxChildkeyTakeRateLimitExceeded.mdx | 16 + docs/errors/chain/TxRateLimitExceeded.mdx | 16 + docs/errors/chain/UidMapCouldNotBeCleared.mdx | 16 + docs/errors/chain/UidVecContainInvalidOne.mdx | 16 + .../chain/UidsLengthExceedUidsInSubNet.mdx | 16 + .../errors/chain/UnableToRecoverPublicKey.mdx | 16 + docs/errors/chain/Unannounced.mdx | 16 + docs/errors/chain/Unauthorized.mdx | 16 + docs/errors/chain/Undefined.mdx | 16 + docs/errors/chain/Underflow.mdx | 16 + docs/errors/chain/UnexpectedTimepoint.mdx | 16 + .../chain/UnexpectedUnreserveLeftover.mdx | 16 + docs/errors/chain/UnlockAmountTooHigh.mdx | 16 + docs/errors/chain/Unproxyable.mdx | 16 + docs/errors/chain/Unreachable.mdx | 16 + docs/errors/chain/UnverifiedPulse.mdx | 16 + docs/errors/chain/ValueNotInBounds.mdx | 16 + docs/errors/chain/ValueTooLarge.mdx | 16 + docs/errors/chain/VestingBalance.mdx | 16 + .../chain/VotingPowerTrackingNotEnabled.mdx | 16 + .../WaitingForDissolvedSubnetCleanup.mdx | 16 + .../errors/chain/WeightExceedsAbsoluteMax.mdx | 16 + docs/errors/chain/WeightVecLengthIsLow.mdx | 16 + docs/errors/chain/WeightVecNotEqualSize.mdx | 16 + docs/errors/chain/WithdrawFailed.mdx | 16 + docs/errors/chain/WrongTimepoint.mdx | 16 + docs/errors/chain/XCMDecodeFailed.mdx | 16 + .../chain/ZeroBalanceAfterWithdrawn.mdx | 16 + docs/errors/chain/ZeroShareInBatch.mdx | 16 + docs/errors/chain/index.mdx | 364 ++++++ docs/errors/chain/meta.json | 359 +++++ docs/errors/disabled.mdx | 40 + docs/errors/expired.mdx | 28 + docs/errors/index.mdx | 29 + docs/errors/insufficient-balance.mdx | 48 + docs/errors/insufficient-liquidity.mdx | 33 + docs/errors/internal.mdx | 41 + docs/errors/invalid-argument.mdx | 158 +++ docs/errors/limit-exceeded.mdx | 57 + docs/errors/meta.json | 25 + docs/errors/not-authorized.mdx | 45 + docs/errors/not-found.mdx | 43 + docs/errors/not-registered.mdx | 27 + docs/errors/policy-violation.mdx | 20 + docs/errors/rate-limited.mdx | 40 + docs/errors/subnet-not-exists.mdx | 27 + docs/errors/subtoken-disabled.mdx | 24 + docs/errors/too-early.mdx | 41 + docs/errors/unit-mismatch.mdx | 22 + docs/errors/unknown.mdx | 20 + docs/guides/meta.json | 2 +- docs/guides/multisig.mdx | 421 ++++++ docs/guides/proxies.mdx | 393 ++++++ docs/guides/staking.mdx | 4 +- docs/guides/subnets.mdx | 4 +- .../activity-cutoff-factor.mdx | 53 + docs/hyperparameters/activity-cutoff.mdx | 17 +- docs/hyperparameters/index.mdx | 8 +- docs/hyperparameters/meta.json | 4 + docs/hyperparameters/subnet-is-active.mdx | 64 + docs/hyperparameters/tempo.mdx | 22 +- .../user-liquidity-enabled.mdx | 41 + docs/hyperparameters/yuma-version.mdx | 39 + docs/internals/contributing.mdx | 2 +- docs/internals/repo-layout.mdx | 2 +- docs/query/index.mdx | 2 +- docs/query/metagraph.mdx | 3 +- docs/query/subnet-hyperparameters.mdx | 7 +- docs/tx/set-hyperparameter.mdx | 4 +- pallets/admin-utils/src/benchmarking.rs | 42 +- pallets/admin-utils/src/lib.rs | 50 +- pallets/admin-utils/src/tests/mod.rs | 132 ++ pallets/admin-utils/src/weights.rs | 51 + pallets/subtensor/src/benchmarks.rs | 33 - .../subtensor/src/coinbase/tempo_control.rs | 37 +- pallets/subtensor/src/lib.rs | 4 +- pallets/subtensor/src/macros/dispatches.rs | 27 +- pallets/subtensor/src/utils/misc.rs | 6 +- pallets/subtensor/src/weights.rs | 94 -- precompiles/src/subnet.rs | 2 +- runtime/src/proxy_filters/call_groups.rs | 5 +- runtime/src/proxy_filters/mod.rs | 4 +- sdk/python/bittensor/_generated/calls.py | 17 +- sdk/python/bittensor/cli/main.py | 18 +- sdk/python/bittensor/cli/metagraph_view.py | 3 +- sdk/python/bittensor/cli/output.py | 86 +- sdk/python/bittensor/cli/query.py | 54 +- sdk/python/bittensor/error_descriptions.py | 5 +- sdk/python/bittensor/hyperparams.py | 34 +- .../bittensor/intents/hyperparameters.py | 7 +- sdk/python/bittensor/namespaces.pyi | 10 +- sdk/python/bittensor/reads/__init__.py | 4 +- sdk/python/bittensor/reads/base.py | 41 +- sdk/python/bittensor/reads/subnets.py | 40 +- sdk/python/bittensor/reads/weights.py | 5 +- sdk/python/bittensor/result.py | 14 + sdk/python/bittensor/settings.py | 12 + sdk/python/codegen/check.py | 7 +- sdk/python/tests/unit/test_reads_table.py | 2 +- website/apps/bittensor-website/README.md | 2 +- .../public/catalog/errors.json | 1149 +++++++++++------ .../public/catalog/intents.json | 2 +- .../public/catalog/reads.json | 6 +- .../bittensor-website/scripts/generate.py | 207 ++- .../releases/v431-upgrade/page.tsx | 5 +- .../wallet/WalletPage.tsx | 19 +- .../src/app/docs/docs.tw.css | 30 + .../src/components/docs/chart-theme.ts | 45 + .../components/docs/conviction-lock-chart.tsx | 79 +- .../docs/conviction-mode-comparison.tsx | 103 +- .../docs/conviction-subnet-scenario.tsx | 310 +++-- .../components/docs/emission-flow-diagram.tsx | 37 +- .../docs/emission-network-snapshot.tsx | 5 +- .../components/docs/evm-address-domains.tsx | 78 +- .../src/components/docs/evm-money-flows.tsx | 14 +- .../src/components/docs/explainer-panel.tsx | 128 +- .../docs/hyperparam-activity-cutoff-chart.tsx | 91 +- .../docs/hyperparam-bonds-penalty-chart.tsx | 21 +- .../docs/hyperparam-bonds-reset-chart.tsx | 27 +- .../docs/hyperparam-burn-controller.tsx | 105 +- .../docs/hyperparam-childkey-take-range.tsx | 135 +- .../docs/hyperparam-consensus-sigmoid.tsx | 102 +- .../docs/hyperparam-legacy-adjustment.tsx | 74 +- .../docs/hyperparam-liquid-alpha.tsx | 116 +- .../docs/hyperparam-max-validators-chart.tsx | 98 +- .../components/docs/hyperparam-owner-cut.tsx | 157 ++- .../docs/hyperparam-pow-difficulty.tsx | 66 +- .../docs/hyperparam-pow-toggle-dead-end.tsx | 22 +- .../docs/hyperparam-registration-gate.tsx | 65 +- .../docs/hyperparam-regs-cap-chart.tsx | 104 +- .../docs/hyperparam-regs-per-block-chart.tsx | 98 +- .../hyperparam-serving-rate-limit-chart.tsx | 70 +- .../docs/hyperparam-tempo-timeline.tsx | 111 +- .../hyperparam-transfers-enabled-flow.tsx | 110 +- .../docs/hyperparam-uid-lifecycle.tsx | 24 +- .../hyperparam-weights-rate-limit-chart.tsx | 17 +- .../docs/hyperparam-weights-rules.tsx | 59 +- .../docs/hyperparam-weights-version-gate.tsx | 17 +- .../docs/hyperparam-yuma3-chart.tsx | 54 +- .../components/docs/mev-shield-timeline.tsx | 258 ++++ .../docs/registration-burn-timeline.tsx | 74 +- .../docs/root-proportion-explainer.tsx | 73 +- .../components/docs/staking-flow-diagram.tsx | 362 ++++++ .../docs/staking-pool-swap-demo.tsx | 325 +++++ .../docs/staking-slippage-limit.tsx | 386 ++++++ .../docs/subnet-emission-share-chart.tsx | 67 +- .../src/components/docs/tao-halving-chart.tsx | 137 +- .../components/docs/yuma-consensus-demo.tsx | 96 +- .../bittensor-website/src/components/mdx.tsx | 8 + 479 files changed, 13579 insertions(+), 1916 deletions(-) create mode 100644 docs/concepts/staking-pools.mdx delete mode 100644 docs/errors.mdx create mode 100644 docs/errors/already-exists.mdx create mode 100644 docs/errors/chain/AccountNotAllowedCommit.mdx create mode 100644 docs/errors/chain/AccountRejectsLockedAlpha.mdx create mode 100644 docs/errors/chain/ActiveLockExists.mdx create mode 100644 docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds.mdx create mode 100644 docs/errors/chain/ActivityCutoffTooLow.mdx create mode 100644 docs/errors/chain/AddStakeBurnRateLimitExceeded.mdx create mode 100644 docs/errors/chain/AdminActionProhibitedDuringWeightsWindow.mdx create mode 100644 docs/errors/chain/AllNetworksInImmunity.mdx create mode 100644 docs/errors/chain/AlphaHighTooLow.mdx create mode 100644 docs/errors/chain/AlphaLowOutOfRange.mdx create mode 100644 docs/errors/chain/AlreadyApproved.mdx create mode 100644 docs/errors/chain/AlreadyDeposited.mdx create mode 100644 docs/errors/chain/AlreadyFinalized.mdx create mode 100644 docs/errors/chain/AlreadyFinalizing.mdx create mode 100644 docs/errors/chain/AlreadyNoted.mdx create mode 100644 docs/errors/chain/AlreadyStored.mdx create mode 100644 docs/errors/chain/AmountTooLow.mdx create mode 100644 docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch.mdx create mode 100644 docs/errors/chain/AnnouncementDepositInvariantViolated.mdx create mode 100644 docs/errors/chain/ArithmeticOverflow.mdx create mode 100644 docs/errors/chain/AutoEpochAlreadyImminent.mdx create mode 100644 docs/errors/chain/BadEncKeyLen.mdx create mode 100644 docs/errors/chain/BalanceLow.mdx create mode 100644 docs/errors/chain/BalanceWithdrawalError.mdx create mode 100644 docs/errors/chain/BeneficiaryDoesNotOwnHotkey.mdx create mode 100644 docs/errors/chain/BlockDurationTooLong.mdx create mode 100644 docs/errors/chain/BlockDurationTooShort.mdx create mode 100644 docs/errors/chain/BondsMovingAverageMaxReached.mdx create mode 100644 docs/errors/chain/CallDisabled.mdx create mode 100644 docs/errors/chain/CallFiltered.mdx create mode 100644 docs/errors/chain/CallUnavailable.mdx create mode 100644 docs/errors/chain/CanNotSetRootNetworkWeights.mdx create mode 100644 docs/errors/chain/CannotAddSelfAsDelegateDependency.mdx create mode 100644 docs/errors/chain/CannotAffordLockCost.mdx create mode 100644 docs/errors/chain/CannotBurnOrRecycleOnRootSubnet.mdx create mode 100644 docs/errors/chain/CannotEndInPast.mdx create mode 100644 docs/errors/chain/CannotReleaseYet.mdx create mode 100644 docs/errors/chain/CannotUseSystemAccount.mdx create mode 100644 docs/errors/chain/CapNotRaised.mdx create mode 100644 docs/errors/chain/CapRaised.mdx create mode 100644 docs/errors/chain/CapTooLow.mdx create mode 100644 docs/errors/chain/ChainIdMismatch.mdx create mode 100644 docs/errors/chain/ChangePending.mdx create mode 100644 docs/errors/chain/ChildParentInconsistency.mdx create mode 100644 docs/errors/chain/CodeInUse.mdx create mode 100644 docs/errors/chain/CodeInfoNotFound.mdx create mode 100644 docs/errors/chain/CodeNotFound.mdx create mode 100644 docs/errors/chain/CodeRejected.mdx create mode 100644 docs/errors/chain/CodeTooLarge.mdx create mode 100644 docs/errors/chain/ColdKeyAlreadyAssociated.mdx create mode 100644 docs/errors/chain/ColdkeySwapAlreadyDisputed.mdx create mode 100644 docs/errors/chain/ColdkeySwapAnnounced.mdx create mode 100644 docs/errors/chain/ColdkeySwapAnnouncementNotFound.mdx create mode 100644 docs/errors/chain/ColdkeySwapClearTooEarly.mdx create mode 100644 docs/errors/chain/ColdkeySwapDisputed.mdx create mode 100644 docs/errors/chain/ColdkeySwapReannouncedTooEarly.mdx create mode 100644 docs/errors/chain/ColdkeySwapTooEarly.mdx create mode 100644 docs/errors/chain/CommitRevealDisabled.mdx create mode 100644 docs/errors/chain/CommitRevealEnabled.mdx create mode 100644 docs/errors/chain/CommittingWeightsTooFast.mdx create mode 100644 docs/errors/chain/ContractNotFound.mdx create mode 100644 docs/errors/chain/ContractReverted.mdx create mode 100644 docs/errors/chain/ContractTrapped.mdx create mode 100644 docs/errors/chain/ContributionPeriodEnded.mdx create mode 100644 docs/errors/chain/ContributionPeriodNotEnded.mdx create mode 100644 docs/errors/chain/ContributionTooLow.mdx create mode 100644 docs/errors/chain/CreateOriginNotAllowed.mdx create mode 100644 docs/errors/chain/CurrencyError.mdx create mode 100644 docs/errors/chain/DeadAccount.mdx create mode 100644 docs/errors/chain/DecodingFailed.mdx create mode 100644 docs/errors/chain/DelegateDependencyAlreadyExists.mdx create mode 100644 docs/errors/chain/DelegateDependencyNotFound.mdx create mode 100644 docs/errors/chain/DelegateTakeTooHigh.mdx create mode 100644 docs/errors/chain/DelegateTakeTooLow.mdx create mode 100644 docs/errors/chain/DelegateTxRateLimitExceeded.mdx create mode 100644 docs/errors/chain/DeltaZero.mdx create mode 100644 docs/errors/chain/DepositCannotBeWithdrawn.mdx create mode 100644 docs/errors/chain/DepositTooLow.mdx create mode 100644 docs/errors/chain/Deprecated.mdx create mode 100644 docs/errors/chain/DisabledTemporarily.mdx create mode 100644 docs/errors/chain/DrandConnectionFailure.mdx create mode 100644 docs/errors/chain/Duplicate.mdx create mode 100644 docs/errors/chain/DuplicateChild.mdx create mode 100644 docs/errors/chain/DuplicateContract.mdx create mode 100644 docs/errors/chain/DuplicateOffenceReport.mdx create mode 100644 docs/errors/chain/DuplicateOrderInBatch.mdx create mode 100644 docs/errors/chain/DuplicateUids.mdx create mode 100644 docs/errors/chain/DynamicTempoBlockedByCommitReveal.mdx create mode 100644 docs/errors/chain/Entered.mdx create mode 100644 docs/errors/chain/EpochTriggerAlreadyPending.mdx create mode 100644 docs/errors/chain/EvmKeyAssociateRateLimitExceeded.mdx create mode 100644 docs/errors/chain/EvmKeyAssociationLimitExceeded.mdx create mode 100644 docs/errors/chain/ExistentialDeposit.mdx create mode 100644 docs/errors/chain/ExistingVestingSchedule.mdx create mode 100644 docs/errors/chain/Exited.mdx create mode 100644 docs/errors/chain/ExpectedBeneficiaryOrigin.mdx create mode 100644 docs/errors/chain/Expendability.mdx create mode 100644 docs/errors/chain/ExpiredWeightCommit.mdx create mode 100644 docs/errors/chain/FailedToExtractRuntimeVersion.mdx create mode 100644 docs/errors/chain/FailedToSchedule.mdx create mode 100644 docs/errors/chain/FaucetDisabled.mdx create mode 100644 docs/errors/chain/FeeOverflow.mdx create mode 100644 docs/errors/chain/FeeRateTooHigh.mdx create mode 100644 docs/errors/chain/FirstEmissionBlockNumberAlreadySet.mdx create mode 100644 docs/errors/chain/GasLimitTooHigh.mdx create mode 100644 docs/errors/chain/GasLimitTooLow.mdx create mode 100644 docs/errors/chain/GasPriceTooLow.mdx create mode 100644 docs/errors/chain/HotKeyAccountNotExists.mdx create mode 100644 docs/errors/chain/HotKeyAlreadyDelegate.mdx create mode 100644 docs/errors/chain/HotKeyAlreadyRegisteredInSubNet.mdx create mode 100644 docs/errors/chain/HotKeyNotRegisteredInNetwork.mdx create mode 100644 docs/errors/chain/HotKeyNotRegisteredInSubNet.mdx create mode 100644 docs/errors/chain/HotKeySetTxRateLimitExceeded.mdx create mode 100644 docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed.mdx create mode 100644 docs/errors/chain/IncorrectCommitRevealVersion.mdx create mode 100644 docs/errors/chain/IncorrectPartialFillAmount.mdx create mode 100644 docs/errors/chain/IncorrectWeightVersionKey.mdx create mode 100644 docs/errors/chain/Indeterministic.mdx create mode 100644 docs/errors/chain/InputForwarded.mdx create mode 100644 docs/errors/chain/InputLengthsUnequal.mdx create mode 100644 docs/errors/chain/InsufficientBalance.mdx create mode 100644 docs/errors/chain/InsufficientInputAmount.mdx create mode 100644 docs/errors/chain/InsufficientLiquidity.mdx create mode 100644 docs/errors/chain/InsufficientStakeForLock.mdx create mode 100644 docs/errors/chain/InvalidCallFlags.mdx create mode 100644 docs/errors/chain/InvalidChainId.mdx create mode 100644 docs/errors/chain/InvalidChild.mdx create mode 100644 docs/errors/chain/InvalidChildkeyTake.mdx create mode 100644 docs/errors/chain/InvalidCrowdloanId.mdx create mode 100644 docs/errors/chain/InvalidDerivedAccount.mdx create mode 100644 docs/errors/chain/InvalidDerivedAccountId.mdx create mode 100644 docs/errors/chain/InvalidDifficulty.mdx create mode 100644 docs/errors/chain/InvalidEquivocationProof.mdx create mode 100644 docs/errors/chain/InvalidFinalizationConfig.mdx create mode 100644 docs/errors/chain/InvalidIdentity.mdx create mode 100644 docs/errors/chain/InvalidIpAddress.mdx create mode 100644 docs/errors/chain/InvalidIpType.mdx create mode 100644 docs/errors/chain/InvalidKeyOwnershipProof.mdx create mode 100644 docs/errors/chain/InvalidLeaseBeneficiary.mdx create mode 100644 docs/errors/chain/InvalidLiquidityValue.mdx create mode 100644 docs/errors/chain/InvalidNonce.mdx create mode 100644 docs/errors/chain/InvalidNumRootClaim.mdx create mode 100644 docs/errors/chain/InvalidOrigin.mdx create mode 100644 docs/errors/chain/InvalidPort.mdx create mode 100644 docs/errors/chain/InvalidRecoveredPublicKey.mdx create mode 100644 docs/errors/chain/InvalidRevealCommitHashNotMatch.mdx create mode 100644 docs/errors/chain/InvalidRevealRound.mdx create mode 100644 docs/errors/chain/InvalidRootClaimThreshold.mdx create mode 100644 docs/errors/chain/InvalidRoundNumber.mdx create mode 100644 docs/errors/chain/InvalidSchedule.mdx create mode 100644 docs/errors/chain/InvalidSeal.mdx create mode 100644 docs/errors/chain/InvalidSignature.mdx create mode 100644 docs/errors/chain/InvalidSpecName.mdx create mode 100644 docs/errors/chain/InvalidSubnetNumber.mdx create mode 100644 docs/errors/chain/InvalidTickRange.mdx create mode 100644 docs/errors/chain/InvalidValue.mdx create mode 100644 docs/errors/chain/InvalidVotingPowerEmaAlpha.mdx create mode 100644 docs/errors/chain/InvalidWorkBlock.mdx create mode 100644 docs/errors/chain/IssuanceDeactivated.mdx create mode 100644 docs/errors/chain/LeaseCannotEndInThePast.mdx create mode 100644 docs/errors/chain/LeaseDoesNotExist.mdx create mode 100644 docs/errors/chain/LeaseHasNoEndBlock.mdx create mode 100644 docs/errors/chain/LeaseHasNotEnded.mdx create mode 100644 docs/errors/chain/LeaseNetuidNotFound.mdx create mode 100644 docs/errors/chain/LimitOrdersDisabled.mdx create mode 100644 docs/errors/chain/LiquidAlphaDisabled.mdx create mode 100644 docs/errors/chain/LiquidityRestrictions.mdx create mode 100644 docs/errors/chain/LockHotkeyMismatch.mdx create mode 100644 docs/errors/chain/LockIdOverFlow.mdx create mode 100644 docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds.mdx create mode 100644 docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids.mdx create mode 100644 docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids.mdx create mode 100644 docs/errors/chain/MaxCallDepthReached.mdx create mode 100644 docs/errors/chain/MaxContributionReached.mdx create mode 100644 docs/errors/chain/MaxContributorsReached.mdx create mode 100644 docs/errors/chain/MaxDelegateDependenciesReached.mdx create mode 100644 docs/errors/chain/MaxValidatorsLargerThanMaxUIds.mdx create mode 100644 docs/errors/chain/MaxWeightExceeded.mdx create mode 100644 docs/errors/chain/MaxWeightTooLow.mdx create mode 100644 docs/errors/chain/MaximumContributionTooLow.mdx create mode 100644 docs/errors/chain/MechanismDoesNotExist.mdx create mode 100644 docs/errors/chain/MigrationInProgress.mdx create mode 100644 docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids.mdx create mode 100644 docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids.mdx create mode 100644 docs/errors/chain/MinimumContributionTooHigh.mdx create mode 100644 docs/errors/chain/MinimumContributionTooLow.mdx create mode 100644 docs/errors/chain/MinimumThreshold.mdx create mode 100644 docs/errors/chain/MultiBlockMigrationsOngoing.mdx create mode 100644 docs/errors/chain/Named.mdx create mode 100644 docs/errors/chain/NeedWaitingMoreBlocksToStarCall.mdx create mode 100644 docs/errors/chain/NegativeSigmoidSteepness.mdx create mode 100644 docs/errors/chain/NetworkDissolveAlreadyQueued.mdx create mode 100644 docs/errors/chain/NetworkTxRateLimitExceeded.mdx create mode 100644 docs/errors/chain/NeuronNoValidatorPermit.mdx create mode 100644 docs/errors/chain/NewColdKeyIsHotkey.mdx create mode 100644 docs/errors/chain/NewHotKeyIsSameWithOld.mdx create mode 100644 docs/errors/chain/NewHotKeyNotCleanForRootSwap.mdx create mode 100644 docs/errors/chain/NoApprovalsNeeded.mdx create mode 100644 docs/errors/chain/NoChainExtension.mdx create mode 100644 docs/errors/chain/NoContribution.mdx create mode 100644 docs/errors/chain/NoDeposit.mdx create mode 100644 docs/errors/chain/NoExistingLock.mdx create mode 100644 docs/errors/chain/NoMigrationPerformed.mdx create mode 100644 docs/errors/chain/NoNeuronIdAvailable.mdx create mode 100644 docs/errors/chain/NoPermission.mdx create mode 100644 docs/errors/chain/NoSelfProxy.mdx create mode 100644 docs/errors/chain/NoTimepoint.mdx create mode 100644 docs/errors/chain/NoWeightsCommitFound.mdx create mode 100644 docs/errors/chain/NonAssociatedColdKey.mdx create mode 100644 docs/errors/chain/NonDefaultComposite.mdx create mode 100644 docs/errors/chain/NonZeroRefCount.mdx create mode 100644 docs/errors/chain/NoneValue.mdx create mode 100644 docs/errors/chain/NotAllowed.mdx create mode 100644 docs/errors/chain/NotAuthorized.mdx create mode 100644 docs/errors/chain/NotConfigured.mdx create mode 100644 docs/errors/chain/NotEnoughAlphaOutToRecycle.mdx create mode 100644 docs/errors/chain/NotEnoughBalanceToPaySwapColdKey.mdx create mode 100644 docs/errors/chain/NotEnoughBalanceToPaySwapHotKey.mdx create mode 100644 docs/errors/chain/NotEnoughBalanceToStake.mdx create mode 100644 docs/errors/chain/NotEnoughStake.mdx create mode 100644 docs/errors/chain/NotEnoughStakeToSetChildkeys.mdx create mode 100644 docs/errors/chain/NotEnoughStakeToSetWeights.mdx create mode 100644 docs/errors/chain/NotEnoughStakeToWithdraw.mdx create mode 100644 docs/errors/chain/NotFound.mdx create mode 100644 docs/errors/chain/NotNoted.mdx create mode 100644 docs/errors/chain/NotOwner.mdx create mode 100644 docs/errors/chain/NotPermittedOnRootSubnet.mdx create mode 100644 docs/errors/chain/NotProxy.mdx create mode 100644 docs/errors/chain/NotReadyToDissolve.mdx create mode 100644 docs/errors/chain/NotRequested.mdx create mode 100644 docs/errors/chain/NotRootSubnet.mdx create mode 100644 docs/errors/chain/NotSubnetOwner.mdx create mode 100644 docs/errors/chain/NothingAuthorized.mdx create mode 100644 docs/errors/chain/OrderAlreadyProcessed.mdx create mode 100644 docs/errors/chain/OrderCancelled.mdx create mode 100644 docs/errors/chain/OrderExpired.mdx create mode 100644 docs/errors/chain/OrderNetUidMismatch.mdx create mode 100644 docs/errors/chain/OutOfBounds.mdx create mode 100644 docs/errors/chain/OutOfGas.mdx create mode 100644 docs/errors/chain/OutOfTransientStorage.mdx create mode 100644 docs/errors/chain/OutputBufferTooSmall.mdx create mode 100644 docs/errors/chain/Overflow.mdx create mode 100644 docs/errors/chain/POWRegistrationDisabled.mdx create mode 100644 docs/errors/chain/PalletHotkeyNotRegistered.mdx create mode 100644 docs/errors/chain/PartialFillsNotEnabled.mdx create mode 100644 docs/errors/chain/PauseFailed.mdx create mode 100644 docs/errors/chain/PaymentOverflow.mdx create mode 100644 docs/errors/chain/PreLogExists.mdx create mode 100644 docs/errors/chain/PriceConditionNotMet.mdx create mode 100644 docs/errors/chain/PriceLimitExceeded.mdx create mode 100644 docs/errors/chain/ProportionOverflow.mdx create mode 100644 docs/errors/chain/PulseVerificationError.mdx create mode 100644 docs/errors/chain/RandomSubjectTooLong.mdx create mode 100644 docs/errors/chain/ReentranceDenied.mdx create mode 100644 docs/errors/chain/Reentrancy.mdx create mode 100644 docs/errors/chain/RegistrationNotPermittedOnRootSubnet.mdx create mode 100644 docs/errors/chain/RegistrationPriceLimitExceeded.mdx create mode 100644 docs/errors/chain/RelayerMissMatch.mdx create mode 100644 docs/errors/chain/RelayerRequiredForPartialFill.mdx create mode 100644 docs/errors/chain/Requested.mdx create mode 100644 docs/errors/chain/RequireSudo.mdx create mode 100644 docs/errors/chain/RescheduleNoChange.mdx create mode 100644 docs/errors/chain/ReservesOutOfBalance.mdx create mode 100644 docs/errors/chain/ReservesTooLow.mdx create mode 100644 docs/errors/chain/ResumeFailed.mdx create mode 100644 docs/errors/chain/RevealPeriodTooLarge.mdx create mode 100644 docs/errors/chain/RevealPeriodTooSmall.mdx create mode 100644 docs/errors/chain/RevealTooEarly.mdx create mode 100644 docs/errors/chain/RootNetUidNotAllowed.mdx create mode 100644 docs/errors/chain/RootNetworkDoesNotExist.mdx create mode 100644 docs/errors/chain/SameAutoStakeHotkeyAlreadySet.mdx create mode 100644 docs/errors/chain/SameNetuid.mdx create mode 100644 docs/errors/chain/SenderInSignatories.mdx create mode 100644 docs/errors/chain/ServingRateLimitExceeded.mdx create mode 100644 docs/errors/chain/SettingWeightsTooFast.mdx create mode 100644 docs/errors/chain/SignatoriesOutOfOrder.mdx create mode 100644 docs/errors/chain/SlippageTooHigh.mdx create mode 100644 docs/errors/chain/SpaceLimitExceeded.mdx create mode 100644 docs/errors/chain/SpecVersionNeedsToIncrease.mdx create mode 100644 docs/errors/chain/StakeTooLowForRoot.mdx create mode 100644 docs/errors/chain/StakeUnavailable.mdx create mode 100644 docs/errors/chain/StakingRateLimitExceeded.mdx create mode 100644 docs/errors/chain/StartCallNotReady.mdx create mode 100644 docs/errors/chain/StateChangeDenied.mdx create mode 100644 docs/errors/chain/StorageDepositLimitExhausted.mdx create mode 100644 docs/errors/chain/StorageDepositNotEnoughFunds.mdx create mode 100644 docs/errors/chain/StorageOverflow.mdx create mode 100644 docs/errors/chain/SubNetRegistrationDisabled.mdx create mode 100644 docs/errors/chain/SubnetBuybackRateLimitExceeded.mdx create mode 100644 docs/errors/chain/SubnetDoesNotExist.mdx create mode 100644 docs/errors/chain/SubnetLimitReached.mdx create mode 100644 docs/errors/chain/SubnetNotExists.mdx create mode 100644 docs/errors/chain/SubtokenDisabled.mdx create mode 100644 docs/errors/chain/SwapInputTooLarge.mdx create mode 100644 docs/errors/chain/SwapReturnedZero.mdx create mode 100644 docs/errors/chain/SymbolAlreadyInUse.mdx create mode 100644 docs/errors/chain/SymbolDoesNotExist.mdx create mode 100644 docs/errors/chain/TargetBlockNumberInPast.mdx create mode 100644 docs/errors/chain/TempoOutOfBounds.mdx create mode 100644 docs/errors/chain/TerminatedInConstructor.mdx create mode 100644 docs/errors/chain/TerminatedWhileReentrant.mdx create mode 100644 docs/errors/chain/TooBig.mdx create mode 100644 docs/errors/chain/TooFew.mdx create mode 100644 docs/errors/chain/TooFewSignatories.mdx create mode 100644 docs/errors/chain/TooMany.mdx create mode 100644 docs/errors/chain/TooManyCalls.mdx create mode 100644 docs/errors/chain/TooManyChildren.mdx create mode 100644 docs/errors/chain/TooManyFieldsInCommitmentInfo.mdx create mode 100644 docs/errors/chain/TooManyFreezes.mdx create mode 100644 docs/errors/chain/TooManyHolds.mdx create mode 100644 docs/errors/chain/TooManyPendingExtrinsics.mdx create mode 100644 docs/errors/chain/TooManyRegistrationsThisBlock.mdx create mode 100644 docs/errors/chain/TooManyRegistrationsThisInterval.mdx create mode 100644 docs/errors/chain/TooManyReserves.mdx create mode 100644 docs/errors/chain/TooManySignatories.mdx create mode 100644 docs/errors/chain/TooManyTopics.mdx create mode 100644 docs/errors/chain/TooManyUIDsPerMechanism.mdx create mode 100644 docs/errors/chain/TooManyUnrevealedCommits.mdx create mode 100644 docs/errors/chain/TooSoon.mdx create mode 100644 docs/errors/chain/TransactionMustComeFromEOA.mdx create mode 100644 docs/errors/chain/TransactorAccountShouldBeHotKey.mdx create mode 100644 docs/errors/chain/TransferDisallowed.mdx create mode 100644 docs/errors/chain/TransferFailed.mdx create mode 100644 docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage.mdx create mode 100644 docs/errors/chain/TxChildkeyTakeRateLimitExceeded.mdx create mode 100644 docs/errors/chain/TxRateLimitExceeded.mdx create mode 100644 docs/errors/chain/UidMapCouldNotBeCleared.mdx create mode 100644 docs/errors/chain/UidVecContainInvalidOne.mdx create mode 100644 docs/errors/chain/UidsLengthExceedUidsInSubNet.mdx create mode 100644 docs/errors/chain/UnableToRecoverPublicKey.mdx create mode 100644 docs/errors/chain/Unannounced.mdx create mode 100644 docs/errors/chain/Unauthorized.mdx create mode 100644 docs/errors/chain/Undefined.mdx create mode 100644 docs/errors/chain/Underflow.mdx create mode 100644 docs/errors/chain/UnexpectedTimepoint.mdx create mode 100644 docs/errors/chain/UnexpectedUnreserveLeftover.mdx create mode 100644 docs/errors/chain/UnlockAmountTooHigh.mdx create mode 100644 docs/errors/chain/Unproxyable.mdx create mode 100644 docs/errors/chain/Unreachable.mdx create mode 100644 docs/errors/chain/UnverifiedPulse.mdx create mode 100644 docs/errors/chain/ValueNotInBounds.mdx create mode 100644 docs/errors/chain/ValueTooLarge.mdx create mode 100644 docs/errors/chain/VestingBalance.mdx create mode 100644 docs/errors/chain/VotingPowerTrackingNotEnabled.mdx create mode 100644 docs/errors/chain/WaitingForDissolvedSubnetCleanup.mdx create mode 100644 docs/errors/chain/WeightExceedsAbsoluteMax.mdx create mode 100644 docs/errors/chain/WeightVecLengthIsLow.mdx create mode 100644 docs/errors/chain/WeightVecNotEqualSize.mdx create mode 100644 docs/errors/chain/WithdrawFailed.mdx create mode 100644 docs/errors/chain/WrongTimepoint.mdx create mode 100644 docs/errors/chain/XCMDecodeFailed.mdx create mode 100644 docs/errors/chain/ZeroBalanceAfterWithdrawn.mdx create mode 100644 docs/errors/chain/ZeroShareInBatch.mdx create mode 100644 docs/errors/chain/index.mdx create mode 100644 docs/errors/chain/meta.json create mode 100644 docs/errors/disabled.mdx create mode 100644 docs/errors/expired.mdx create mode 100644 docs/errors/index.mdx create mode 100644 docs/errors/insufficient-balance.mdx create mode 100644 docs/errors/insufficient-liquidity.mdx create mode 100644 docs/errors/internal.mdx create mode 100644 docs/errors/invalid-argument.mdx create mode 100644 docs/errors/limit-exceeded.mdx create mode 100644 docs/errors/meta.json create mode 100644 docs/errors/not-authorized.mdx create mode 100644 docs/errors/not-found.mdx create mode 100644 docs/errors/not-registered.mdx create mode 100644 docs/errors/policy-violation.mdx create mode 100644 docs/errors/rate-limited.mdx create mode 100644 docs/errors/subnet-not-exists.mdx create mode 100644 docs/errors/subtoken-disabled.mdx create mode 100644 docs/errors/too-early.mdx create mode 100644 docs/errors/unit-mismatch.mdx create mode 100644 docs/errors/unknown.mdx create mode 100644 docs/guides/multisig.mdx create mode 100644 docs/guides/proxies.mdx create mode 100644 docs/hyperparameters/activity-cutoff-factor.mdx create mode 100644 docs/hyperparameters/subnet-is-active.mdx create mode 100644 docs/hyperparameters/user-liquidity-enabled.mdx create mode 100644 docs/hyperparameters/yuma-version.mdx create mode 100644 website/apps/bittensor-website/src/components/docs/chart-theme.ts create mode 100644 website/apps/bittensor-website/src/components/docs/mev-shield-timeline.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/staking-flow-diagram.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/staking-pool-swap-demo.tsx create mode 100644 website/apps/bittensor-website/src/components/docs/staking-slippage-limit.tsx diff --git a/README.md b/README.md index 8f28f98106..a280f52ac2 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ contracts alongside native Substrate extrinsics. | Shared Rust | [`common/`](./common/), [`primitives/`](./primitives/), [`support/`](./support/) | Shared types, math primitives, lints, macros, weight tooling. | | Client core | [`sdk/bittensor-core/`](./sdk/bittensor-core/) | The Rust core for Bittensor clients (keypairs, keyfiles, SCALE codec, extrinsic assembly, RFC-0078 digest, drand timelock, ML-KEM) — built against the same crate revisions as the chain; Python bindings in [`sdk/bittensor-core-py/`](./sdk/bittensor-core-py/). | | Python SDK | [`sdk/python/`](./sdk/python/) | The `bittensor` package and `btcli` CLI. Generated from chain metadata so reads, writes, and docs cannot drift. | -| Documentation | [`docs/`](./docs/) | Source for bittensor.com/docs. `docs/tx/`, `docs/query/`, and `docs/errors.mdx` are generated — do not hand-edit. | +| Documentation | [`docs/`](./docs/) | Source for bittensor.com/docs. `docs/tx/`, `docs/query/`, and `docs/errors/` are generated — do not hand-edit. | | Website | [`website/`](./website/) | Yarn + Turbo monorepo; `apps/bittensor-website` renders marketing pages and these docs. | | Tests | [`ts-tests/`](./ts-tests/), [`clones/`](./clones/), [`eco-tests/`](./eco-tests/) | Moonwall/zombienet integration tests, mainnet-clone regression harness, indexer contract tests. | | Operations | [`chainspecs/`](./chainspecs/), [`scripts/`](./scripts/), [`Dockerfile`](./Dockerfile) | Chain specs, CI/dev scripts, production and localnet Docker images. | diff --git a/docs/concepts/meta.json b/docs/concepts/meta.json index 75f401ca98..01f5780fc0 100644 --- a/docs/concepts/meta.json +++ b/docs/concepts/meta.json @@ -1,4 +1,4 @@ { "title": "Concepts", - "pages": ["network", "emissions", "wallets", "money", "client", "transactions", "advanced"] + "pages": ["network", "emissions", "wallets", "money", "staking-pools", "client", "transactions", "advanced"] } diff --git a/docs/concepts/money.mdx b/docs/concepts/money.mdx index 99ad8fbe5e..d0e03972a8 100644 --- a/docs/concepts/money.mdx +++ b/docs/concepts/money.mdx @@ -49,7 +49,9 @@ slippage. ## Slippage -Staking and unstaking are swaps against a pool, so the trade itself moves the +Staking and unstaking are swaps against a pool +([staking and pools](/docs/concepts/staking-pools) explains the pool +mechanics with interactive charts), so the trade itself moves the price: your order consumes reserves as it fills, and the gap between what the spot price promised and what you actually receive grows with the trade's size relative to the pool's liquidity. Strictly, that self-inflicted gap is diff --git a/docs/concepts/staking-pools.mdx b/docs/concepts/staking-pools.mdx new file mode 100644 index 0000000000..d7302fd8d5 --- /dev/null +++ b/docs/concepts/staking-pools.mdx @@ -0,0 +1,170 @@ +--- +title: Staking and pools +description: The per-subnet balancer pools, what a stake operation actually does, price impact, swap fees, and MEV-shielded submission. +--- + +Staking on a subnet is not a deposit — it is a **swap**. Every subnet has a +liquidity pool holding TAO and the subnet's alpha; staking sells TAO into +that pool for alpha, unstaking sells alpha back for TAO. Everything that +follows — price impact, swap fees, limit orders, MEV — falls out of that one +fact. This page explains the machinery; the +[staking guide](/docs/guides/staking) covers the commands, and +[how money moves](/docs/concepts/money) covers units and valuation. + +## The pool + +Each subnet's pool is a **weighted balancer pool** (a generalization of the +constant-product AMM): two reserves, TAO (`SubnetTAO`) and alpha +(`SubnetAlphaIn`), plus a pair of weights $w_1 + w_2 = 1$. The spot price is + +$$ +p = \frac{w_1 \cdot \text{TAO reserve}}{w_2 \cdot \text{alpha reserve}} +$$ + +With the default equal weights $w_1 = w_2 = 0.5$ this reduces to the +familiar reserve ratio `TAO / alpha`. Unlike Uniswap-style pools, the weights +let the protocol add liquidity *disproportionally* to price without moving +the price — the weights absorb the imbalance instead (they are re-solved on +every injection and bounded so they stay near 0.5 in practice). Only the +protocol adds liquidity this way; user staking always trades against the +pool. + +A swap moves along the weighted invariant +$L = x^{w_1} \cdot y^{w_2}$. Selling TAO into the pool (staking), the alpha +you receive for `Δy` TAO is + +$$ +\Delta x = x \cdot \left(1 - \left(\tfrac{y}{y+\Delta y}\right)^{w_2/w_1}\right) +$$ + +which is why the execution price curves away from spot as the trade grows — +each slice of your order fills at a slightly worse price than the last. + + + +The math lives in `pallets/swap/src/pallet/balancer.rs`; quotes over RPC use +exactly the same path ([`quote-stake`](/docs/query/quote-stake), +[`quote-unstake`](/docs/query/quote-unstake)), so a quote is a faithful +simulation, not an estimate. + +## What a stake operation does + +[`add-stake`](/docs/tx/add-stake) is a coldkey-signed extrinsic that moves +TAO out of your free balance, swaps it through the subnet's pool, and +credits the resulting alpha to the *(hotkey, coldkey, netuid)* stake +position. Step through it: + + + +Points worth pinning down: + +- **The fee comes off the input side first.** Amount × `FeeRate`/65535 + (default 33 ≈ 0.05%, per-subnet) is deducted before the swap and paid to + the block author — TAO when staking, alpha when unstaking. +- **The swap updates both reserves.** Your TAO enters `SubnetTAO`, alpha + leaves the pool's side (`SubnetAlphaIn`) and joins the staked total + (`SubnetAlphaOut`). The price after your trade is the new reserve ratio — + your own trade moved it. +- **The position is alpha, not TAO.** From the moment the swap settles, the + position's TAO value floats with the pool price, and it earns the + validator's staking emissions (minus its take) every epoch. +- **Unstaking is the mirror image** ([`remove-stake`](/docs/tx/remove-stake)): + alpha leaves the position, the fee is taken in alpha, the swap pays out + TAO. There is no unbonding period — the TAO is spendable immediately. + +Moving a position between hotkeys on the same subnet +([`move-stake`](/docs/tx/move-stake)) is *not* a swap — no fee, no price +impact. Cross-subnet moves run two swaps (alpha → TAO → alpha) and pay the +fee once. + +## Price impact, slippage, and limit orders + +Two different things eat your execution price, and they have different +defenses: + +- **Price impact** — self-inflicted: your own order consumes reserves as it + fills. Deterministic, included in every quote. +- **Slippage** — external: other transactions land before yours and move the + price between quote and execution. Not knowable in advance. + +The limit variants ([`add-stake-limit`](/docs/tx/add-stake-limit), +[`remove-stake-limit`](/docs/tx/remove-stake-limit)) defend against both by +bounding the execution price itself: the chain computes exactly how much can +fill before the pool price reaches your limit, fills up to that point, and +either stops there (`allow_partial=true`) or rejects the whole order +(`allow_partial=false`). + + + +To turn a tolerance into a `limit_price`: staking, ceiling = spot × (1 + +tolerance); unstaking, floor = spot × (1 − tolerance). Read spot with +[`alpha-price`](/docs/query/alpha-price). + +## MEV and shielded submission + +A large stake order sitting in the public mempool is legible to everyone — +including a front-runner who can buy alpha before your order executes, let +your price impact reprice the pool, and sell back after. The sandwich's +profit is carved out of your execution price. + +[MEV-shielded submission](/docs/concepts/advanced#mev-shielded-submission) +closes the window: the SDK signs your call as a complete inner extrinsic, +encrypts it to the chain's rotating ML-KEM-768 key, and submits only the +ciphertext. The mempool sees an opaque blob; the block author decrypts it at +block-build time and includes the inner extrinsic in the block it builds. +There is no interval where the order is both public and pending. + + + +```python +await client.submit_shielded( + sub.AddStakeLimit(hotkey_ss58="5F...", netuid=1, amount_tao=5_000, + limit_price_rao=int(spot["price_rao"] * 1.01), + allow_partial=False), + wallet, +) +``` + +Shield *and* bound the price — they protect against different things. +Shielding hides the order from front-runners; the limit caps damage from +whatever moves the price anyway. What is worth shielding follows the same +economics as price impact: a large swap with a loose limit is the prime +target, while small swaps (well under ~1 TAO) and root-network staking (no +pool, nothing to front-run) gain nothing from it. + +## Root staking: the exception + +Staking on the root network (netuid 0) is not a pool swap. TAO stays +TAO-denominated and converts 1:1 — no swap fee, no price impact, no MEV +exposure. The `limit_price` machinery degenerates accordingly: any limit ≥ +1 TAO/TAO fills fully, anything lower fills nothing. See +[root stake and dividends](/docs/guides/staking#root-stake-and-dividends) +for how root positions earn. + +## Where the liquidity comes from + +Nobody LPs these pools. Every block, the coinbase injects each subnet's +share of TAO emission into its pool's TAO reserve, alongside newly issued +alpha into the alpha reserve (`alpha_in ≈ tao_in / price`, capped by the +subnet's root proportion) — see +[emissions](/docs/concepts/emissions). Because the protocol may inject the +two sides disproportionally to price, the balancer weights absorb the +imbalance; this is the reason the pools are weighted at all. Reserves only +grow through injection and trading — stake swaps in TAO, unstake swaps it +back out — and the pool refuses trades that would drain a reserve below a +minimum, and rejects single swaps larger than 1,000× the TAO reserve +(`InsufficientLiquidity`). + +## Reading the pool + +```bash +btcli query alpha-price --netuid 1 --json # spot price now +btcli query quote-stake --netuid 1 --amount-tao 100 --json # simulate entry +btcli query quote-unstake --netuid 1 --amount-alpha 50 --json # simulate exit +``` + +Spot valuation of a position (`alpha × price`, +[`stake-value-for-coldkey`](/docs/query/stake-value-for-coldkey)) marks to +the current reserve ratio and ignores what your own exit would do to it. For +what you would actually receive, quote the exit — the quote runs the real +swap math against the real reserves. diff --git a/docs/errors.mdx b/docs/errors.mdx deleted file mode 100644 index 612468dc37..0000000000 --- a/docs/errors.mdx +++ /dev/null @@ -1,442 +0,0 @@ ---- -title: "Errors" -description: "Every failure carries a machine-readable code and a remediation hint." ---- - -{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} - -A failed `execute` returns an `ExtrinsicResult` whose `error` has a semantic `code` (branch on it) and a `remediation` hint (what to try next). Every chain error name is deliberately classified — a CI gate keeps the mapping complete in both directions. The machine-readable version is at [`/catalog/errors.json`](/catalog/errors.json). - -## Error codes - -### `insufficient_balance` - -Fund the signing account or reduce the amount; check with `btcli wallet balance` - -### `insufficient_liquidity` - -The pool cannot absorb this trade; reduce the amount or split it into smaller steps - -### `rate_limited` - -Wait for the rate-limit window to pass, then retry - -### `not_registered` - -Register the hotkey on this subnet first with `btcli subnets register` - -### `not_authorized` - -Sign with the key or origin that owns the target object, then retry - -### `already_exists` - -The object or state already exists; treat the goal as met or pick a different target - -### `not_found` - -The referenced object is not on-chain; check the identifier - -### `subnet_not_exists` - -Use an existing netuid; `btcli subnets list` shows valid ones - -### `subtoken_disabled` - -The subnet is not active yet; wait for start_call - -### `disabled` - -This call or feature is switched off on this network - -### `too_early` - -The required window has not opened yet; wait some blocks and retry - -### `expired` - -The window has closed; restart the flow with fresh state - -### `limit_exceeded` - -A chain-side capacity limit was hit; reduce the size or count of the request - -### `unit_mismatch` - -Match the Balance netuid to the operation's currency - -### `invalid_argument` - -Check the argument values against the operation schema - -### `policy_violation` - -The action exceeds a configured safety policy - -### `internal` - -A chain-side invariant failed; nothing to fix client-side — report it if it persists - -### `unknown` - -Inspect the message for details - -## Chain error classification - -The exact chain error name (from the extrinsic receipt) maps to a code; the description says what triggered it and where to check: - -| Chain error | Code | Description | -| --- | --- | --- | -| `AccountNotAllowedCommit` | `not_authorized` | Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet. | -| `AccountRejectsLockedAlpha` | `invalid_argument` | Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying. | -| `ActiveLockExists` | `already_exists` | The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first. | -| `ActivityCutoffFactorMilliOutOfBounds` | `invalid_argument` | The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting. | -| `ActivityCutoffTooLow` | `invalid_argument` | An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `. | -| `AddStakeBurnRateLimitExceeded` | `rate_limited` | The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes. | -| `AdminActionProhibitedDuringWeightsWindow` | `too_early` | An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires. | -| `AllNetworksInImmunity` | `too_early` | Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity. | -| `AlphaHighTooLow` | `invalid_argument` | The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid. | -| `AlphaLowOutOfRange` | `invalid_argument` | The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid. | -| `AlreadyApproved` | `already_exists` | The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list. | -| `AlreadyDeposited` | `already_exists` | The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason. | -| `AlreadyFinalized` | `already_exists` | The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`. | -| `AlreadyFinalizing` | `already_exists` | A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying. | -| `AlreadyNoted` | `already_exists` | The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again. | -| `AlreadyStored` | `already_exists` | The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again. | -| `AmountTooLow` | `invalid_argument` | A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount. | -| `AnnouncedColdkeyHashDoesNotMatch` | `invalid_argument` | The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to. | -| `AnnouncementDepositInvariantViolated` | `internal` | Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input. | -| `ArithmeticOverflow` | `internal` | Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts. | -| `AutoEpochAlreadyImminent` | `already_exists` | `trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire. | -| `BadEncKeyLen` | `invalid_argument` | The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing. | -| `BalanceLow` | `insufficient_balance` | The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price. | -| `BalanceWithdrawalError` | `insufficient_balance` | The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up. | -| `BeneficiaryDoesNotOwnHotkey` | `not_authorized` | When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns. | -| `BlockDurationTooLong` | `invalid_argument` | The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`. | -| `BlockDurationTooShort` | `invalid_argument` | The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`. | -| `BondsMovingAverageMaxReached` | `limit_exceeded` | A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root. | -| `CallDisabled` | `disabled` | The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version. | -| `CallFiltered` | `not_authorized` | The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect. | -| `CallUnavailable` | `not_found` | During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet. | -| `CanNotSetRootNetworkWeights` | `invalid_argument` | `set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism. | -| `CannotAddSelfAsDelegateDependency` | `invalid_argument` | A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash. | -| `CannotAffordLockCost` | `insufficient_balance` | The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet. | -| `CannotBurnOrRecycleOnRootSubnet` | `invalid_argument` | `recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn. | -| `CannotEndInPast` | `invalid_argument` | The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater. | -| `CannotReleaseYet` | `too_early` | `release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config. | -| `CannotUseSystemAccount` | `not_authorized` | The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`. | -| `CapNotRaised` | `too_early` | `finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing. | -| `CapRaised` | `limit_exceeded` | A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`. | -| `CapTooLow` | `invalid_argument` | On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry. | -| `ChainIdMismatch` | `invalid_argument` | The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed. | -| `ChangePending` | `already_exists` | A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first. | -| `ChildParentInconsistency` | `invalid_argument` | A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap. | -| `CodeInUse` | `invalid_argument` | `remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal. | -| `CodeInfoNotFound` | `not_found` | No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed. | -| `CodeNotFound` | `not_found` | No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed. | -| `CodeRejected` | `invalid_argument` | The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason. | -| `CodeTooLarge` | `limit_exceeded` | The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract. | -| `ColdKeyAlreadyAssociated` | `already_exists` | The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead. | -| `ColdkeySwapAlreadyDisputed` | `already_exists` | `dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed. | -| `ColdkeySwapAnnounced` | `already_exists` | The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement. | -| `ColdkeySwapAnnouncementNotFound` | `not_found` | `coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first. | -| `ColdkeySwapClearTooEarly` | `too_early` | The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later. | -| `ColdkeySwapDisputed` | `not_authorized` | All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact. | -| `ColdkeySwapReannouncedTooEarly` | `too_early` | `announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later. | -| `ColdkeySwapTooEarly` | `too_early` | `coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then. | -| `CommitRevealDisabled` | `disabled` | A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled. | -| `CommitRevealEnabled` | `disabled` | Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`. | -| `CommittingWeightsTooFast` | `rate_limited` | The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait. | -| `ContractNotFound` | `not_found` | No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated. | -| `ContractReverted` | `internal` | The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value. | -| `ContractTrapped` | `internal` | The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations. | -| `ContributionPeriodEnded` | `expired` | A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized. | -| `ContributionPeriodNotEnded` | `too_early` | The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number. | -| `ContributionTooLow` | `invalid_argument` | The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount. | -| `CreateOriginNotAllowed` | `not_authorized` | A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list. | -| `CurrencyError` | `internal` | A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason. | -| `DeadAccount` | `not_found` | The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs. | -| `DecodingFailed` | `invalid_argument` | Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API. | -| `DelegateDependencyAlreadyExists` | `already_exists` | The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it. | -| `DelegateDependencyNotFound` | `not_found` | `unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info. | -| `DelegateTakeTooHigh` | `invalid_argument` | The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it. | -| `DelegateTakeTooLow` | `invalid_argument` | The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item. | -| `DelegateTxRateLimitExceeded` | `rate_limited` | The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later. | -| `DeltaZero` | `invalid_argument` | The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount. | -| `DepositCannotBeWithdrawn` | `invalid_argument` | The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry. | -| `DepositTooLow` | `invalid_argument` | The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit. | -| `Deprecated` | `disabled` | The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`). | -| `DisabledTemporarily` | `disabled` | The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled. | -| `DrandConnectionFailure` | `internal` | Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints. | -| `Duplicate` | `already_exists` | This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple. | -| `DuplicateChild` | `invalid_argument` | The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid. | -| `DuplicateContract` | `already_exists` | Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address. | -| `DuplicateOffenceReport` | `already_exists` | The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again. | -| `DuplicateOrderInBatch` | `invalid_argument` | Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`. | -| `DuplicateUids` | `invalid_argument` | The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector. | -| `DynamicTempoBlockedByCommitReveal` | `disabled` | `trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs. | -| `Entered` | `already_exists` | Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages. | -| `EpochTriggerAlreadyPending` | `already_exists` | `trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again. | -| `EvmKeyAssociateRateLimitExceeded` | `rate_limited` | `associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later. | -| `EvmKeyAssociationLimitExceeded` | `limit_exceeded` | The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address. | -| `ExistentialDeposit` | `insufficient_balance` | The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant. | -| `ExistingVestingSchedule` | `already_exists` | A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule. | -| `Exited` | `already_exists` | Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting. | -| `ExpectedBeneficiaryOrigin` | `not_authorized` | A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey. | -| `Expendability` | `insufficient_balance` | The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable. | -| `ExpiredWeightCommit` | `expired` | The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time. | -| `FailedToExtractRuntimeVersion` | `invalid_argument` | The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly. | -| `FailedToSchedule` | `internal` | The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated. | -| `FaucetDisabled` | `disabled` | The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead. | -| `FeeOverflow` | `internal` | Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction. | -| `FeeRateTooHigh` | `invalid_argument` | `set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting. | -| `FirstEmissionBlockNumberAlreadySet` | `already_exists` | `start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed. | -| `GasLimitTooHigh` | `invalid_argument` | The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. | -| `GasLimitTooLow` | `invalid_argument` | The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. | -| `GasPriceTooLow` | `invalid_argument` | The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. | -| `HotKeyAccountNotExists` | `not_registered` | The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first. | -| `HotKeyAlreadyDelegate` | `already_exists` | `become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed. | -| `HotKeyAlreadyRegisteredInSubNet` | `already_exists` | A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid. | -| `HotKeyNotRegisteredInNetwork` | `not_registered` | The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first. | -| `HotKeyNotRegisteredInSubNet` | `not_registered` | The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed. | -| `HotKeySetTxRateLimitExceeded` | `rate_limited` | The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks. | -| `HotKeySwapOnSubnetIntervalNotPassed` | `rate_limited` | A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval. | -| `IncorrectCommitRevealVersion` | `invalid_argument` | The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version. | -| `IncorrectPartialFillAmount` | `invalid_argument` | The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`. | -| `IncorrectWeightVersionKey` | `invalid_argument` | The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key. | -| `Indeterministic` | `invalid_argument` | Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically. | -| `InputForwarded` | `invalid_argument` | The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards. | -| `InputLengthsUnequal` | `invalid_argument` | A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length. | -| `InsufficientBalance` | `insufficient_balance` | The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved. | -| `InsufficientInputAmount` | `invalid_argument` | Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output. | -| `InsufficientLiquidity` | `insufficient_liquidity` | The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount. | -| `InsufficientStakeForLock` | `insufficient_balance` | The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first. | -| `InvalidCallFlags` | `invalid_argument` | The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values. | -| `InvalidChainId` | `invalid_argument` | The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction. | -| `InvalidChild` | `invalid_argument` | The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved. | -| `InvalidChildkeyTake` | `invalid_argument` | The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds. | -| `InvalidCrowdloanId` | `not_found` | No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued. | -| `InvalidDerivedAccount` | `invalid_argument` | Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation. | -| `InvalidDerivedAccountId` | `invalid_argument` | Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one). | -| `InvalidDifficulty` | `invalid_argument` | The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block. | -| `InvalidEquivocationProof` | `invalid_argument` | The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set. | -| `InvalidFinalizationConfig` | `invalid_argument` | Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry. | -| `InvalidIdentity` | `invalid_argument` | The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity. | -| `InvalidIpAddress` | `invalid_argument` | The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed. | -| `InvalidIpType` | `invalid_argument` | The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted. | -| `InvalidKeyOwnershipProof` | `invalid_argument` | The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report. | -| `InvalidLeaseBeneficiary` | `invalid_argument` | The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey. | -| `InvalidLiquidityValue` | `invalid_argument` | Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`. | -| `InvalidNonce` | `invalid_argument` | The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`. | -| `InvalidNumRootClaim` | `invalid_argument` | The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number. | -| `InvalidOrigin` | `not_authorized` | The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`. | -| `InvalidPort` | `invalid_argument` | The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port. | -| `InvalidRecoveredPublicKey` | `invalid_argument` | The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format). | -| `InvalidRevealCommitHashNotMatch` | `invalid_argument` | The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid. | -| `InvalidRevealRound` | `expired` | A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number. | -| `InvalidRootClaimThreshold` | `invalid_argument` | The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid. | -| `InvalidRoundNumber` | `invalid_argument` | A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`. | -| `InvalidSchedule` | `invalid_argument` | The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments. | -| `InvalidSeal` | `invalid_argument` | The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit. | -| `InvalidSignature` | `invalid_argument` | Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed. | -| `InvalidSpecName` | `invalid_argument` | The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one. | -| `InvalidSubnetNumber` | `invalid_argument` | A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit. | -| `InvalidTickRange` | `invalid_argument` | Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones. | -| `InvalidValue` | `invalid_argument` | A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`). | -| `InvalidVotingPowerEmaAlpha` | `invalid_argument` | The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid. | -| `InvalidWorkBlock` | `invalid_argument` | The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block. | -| `IssuanceDeactivated` | `disabled` | Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again. | -| `LeaseCannotEndInThePast` | `invalid_argument` | The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease. | -| `LeaseDoesNotExist` | `not_found` | The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated. | -| `LeaseHasNoEndBlock` | `invalid_argument` | The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id. | -| `LeaseHasNotEnded` | `too_early` | The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes. | -| `LeaseNetuidNotFound` | `not_found` | After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete. | -| `LimitOrdersDisabled` | `disabled` | Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet. | -| `LiquidAlphaDisabled` | `disabled` | Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first. | -| `LiquidityRestrictions` | `insufficient_balance` | The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal. | -| `LockHotkeyMismatch` | `invalid_argument` | The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first. | -| `LockIdOverFlow` | `limit_exceeded` | The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem. | -| `MaxAllowedUIdsLessThanCurrentUIds` | `invalid_argument` | `sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid. | -| `MaxAllowedUidsGreaterThanDefaultMaxAllowedUids` | `invalid_argument` | `sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value. | -| `MaxAllowedUidsLessThanMinAllowedUids` | `invalid_argument` | `sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid. | -| `MaxCallDepthReached` | `limit_exceeded` | A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth. | -| `MaxContributionReached` | `limit_exceeded` | The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`. | -| `MaxContributorsReached` | `limit_exceeded` | The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant. | -| `MaxDelegateDependenciesReached` | `limit_exceeded` | `lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first. | -| `MaxValidatorsLargerThanMaxUIds` | `invalid_argument` | `sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid. | -| `MaxWeightExceeded` | `limit_exceeded` | After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting. | -| `MaxWeightTooLow` | `invalid_argument` | The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`. | -| `MaximumContributionTooLow` | `invalid_argument` | The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry. | -| `MechanismDoesNotExist` | `subnet_not_exists` | The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet. | -| `MigrationInProgress` | `too_early` | A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it. | -| `MinAllowedUidsGreaterThanCurrentUids` | `invalid_argument` | `sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid. | -| `MinAllowedUidsGreaterThanMaxAllowedUids` | `invalid_argument` | `sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid. | -| `MinimumContributionTooHigh` | `invalid_argument` | The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`. | -| `MinimumContributionTooLow` | `invalid_argument` | The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value. | -| `MinimumThreshold` | `invalid_argument` | The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case. | -| `MultiBlockMigrationsOngoing` | `too_early` | Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade. | -| `Named` | `invalid_argument` | An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map. | -| `NeedWaitingMoreBlocksToStarCall` | `too_early` | The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens. | -| `NegativeSigmoidSteepness` | `invalid_argument` | A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root. | -| `NetworkDissolveAlreadyQueued` | `already_exists` | The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request. | -| `NetworkTxRateLimitExceeded` | `rate_limited` | The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks. | -| `NeuronNoValidatorPermit` | `not_authorized` | The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator. | -| `NewColdKeyIsHotkey` | `invalid_argument` | The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey. | -| `NewHotKeyIsSameWithOld` | `invalid_argument` | swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey. | -| `NewHotKeyNotCleanForRootSwap` | `invalid_argument` | The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey. | -| `NoApprovalsNeeded` | `invalid_argument` | The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it. | -| `NoChainExtension` | `disabled` | The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against. | -| `NoContribution` | `not_found` | The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question. | -| `NoDeposit` | `not_found` | No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block. | -| `NoExistingLock` | `not_found` | move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey. | -| `NoMigrationPerformed` | `invalid_argument` | A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument. | -| `NoNeuronIdAvailable` | `limit_exceeded` | Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire. | -| `NoPermission` | `not_authorized` | The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments. | -| `NoSelfProxy` | `invalid_argument` | An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account. | -| `NoTimepoint` | `invalid_argument` | No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`. | -| `NoWeightsCommitFound` | `not_found` | A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window. | -| `NonAssociatedColdKey` | `not_authorized` | The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it. | -| `NonDefaultComposite` | `invalid_argument` | The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way. | -| `NonZeroRefCount` | `invalid_argument` | The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first. | -| `NoneValue` | `not_found` | Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization. | -| `NotAllowed` | `not_authorized` | Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value. | -| `NotAuthorized` | `not_authorized` | The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`. | -| `NotConfigured` | `disabled` | The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants. | -| `NotEnoughAlphaOutToRecycle` | `insufficient_liquidity` | A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount. | -| `NotEnoughBalanceToPaySwapColdKey` | `insufficient_balance` | The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap. | -| `NotEnoughBalanceToPaySwapHotKey` | `insufficient_balance` | The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying. | -| `NotEnoughBalanceToStake` | `insufficient_balance` | The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid). | -| `NotEnoughStake` | `insufficient_balance` | The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs. | -| `NotEnoughStakeToSetChildkeys` | `insufficient_balance` | Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value. | -| `NotEnoughStakeToSetWeights` | `insufficient_balance` | Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`. | -| `NotEnoughStakeToWithdraw` | `insufficient_balance` | An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage). | -| `NotFound` | `not_found` | The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state. | -| `NotNoted` | `not_found` | The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored. | -| `NotOwner` | `not_authorized` | Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash. | -| `NotPermittedOnRootSubnet` | `invalid_argument` | An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0. | -| `NotProxy` | `not_authorized` | The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call. | -| `NotReadyToDissolve` | `too_early` | `dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record. | -| `NotRequested` | `not_found` | The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`. | -| `NotRootSubnet` | `invalid_argument` | A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0. | -| `NotSubnetOwner` | `not_authorized` | The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`). | -| `NothingAuthorized` | `not_found` | No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code. | -| `OrderAlreadyProcessed` | `already_exists` | The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`. | -| `OrderCancelled` | `expired` | The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order. | -| `OrderExpired` | `expired` | The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value. | -| `OrderNetUidMismatch` | `invalid_argument` | An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out. | -| `OutOfBounds` | `invalid_argument` | A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug. | -| `OutOfGas` | `limit_exceeded` | The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight. | -| `OutOfTransientStorage` | `limit_exceeded` | A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit. | -| `OutputBufferTooSmall` | `invalid_argument` | The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug. | -| `Overflow` | `internal` | A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values. | -| `POWRegistrationDisabled` | `disabled` | `sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled. | -| `PalletHotkeyNotRegistered` | `not_registered` | Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs. | -| `PartialFillsNotEnabled` | `disabled` | A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing. | -| `PauseFailed` | `invalid_argument` | A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause. | -| `PaymentOverflow` | `internal` | Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction. | -| `PreLogExists` | `invalid_argument` | An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it. | -| `PriceConditionNotMet` | `too_early` | The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field. | -| `PriceLimitExceeded` | `insufficient_liquidity` | The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting. | -| `ProportionOverflow` | `invalid_argument` | The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX. | -| `PulseVerificationError` | `invalid_argument` | BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key). | -| `RandomSubjectTooLong` | `limit_exceeded` | The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section. | -| `ReentranceDenied` | `invalid_argument` | A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag. | -| `Reentrancy` | `internal` | EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call. | -| `RegistrationNotPermittedOnRootSubnet` | `invalid_argument` | A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership. | -| `RegistrationPriceLimitExceeded` | `limit_exceeded` | `burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay. | -| `RelayerMissMatch` | `invalid_argument` | The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload. | -| `RelayerRequiredForPartialFill` | `invalid_argument` | A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount. | -| `Requested` | `invalid_argument` | The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed. | -| `RequireSudo` | `not_authorized` | The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item. | -| `RescheduleNoChange` | `invalid_argument` | The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block. | -| `ReservesOutOfBalance` | `insufficient_liquidity` | Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry. | -| `ReservesTooLow` | `insufficient_liquidity` | The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size. | -| `ResumeFailed` | `invalid_argument` | A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume. | -| `RevealPeriodTooLarge` | `invalid_argument` | `set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | -| `RevealPeriodTooSmall` | `invalid_argument` | `set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | -| `RevealTooEarly` | `too_early` | A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch. | -| `RootNetUidNotAllowed` | `invalid_argument` | The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet. | -| `RootNetworkDoesNotExist` | `subnet_not_exists` | Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`. | -| `SameAutoStakeHotkeyAlreadySet` | `already_exists` | The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted. | -| `SameNetuid` | `invalid_argument` | A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ. | -| `SenderInSignatories` | `invalid_argument` | The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting. | -| `ServingRateLimitExceeded` | `rate_limited` | `serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait. | -| `SettingWeightsTooFast` | `rate_limited` | The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks. | -| `SignatoriesOutOfOrder` | `invalid_argument` | The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting. | -| `SlippageTooHigh` | `insufficient_liquidity` | A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution. | -| `SpaceLimitExceeded` | `rate_limited` | The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage. | -| `SpecVersionNeedsToIncrease` | `invalid_argument` | The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain. | -| `StakeTooLowForRoot` | `insufficient_balance` | `root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`). | -| `StakeUnavailable` | `insufficient_balance` | An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked. | -| `StakingRateLimitExceeded` | `rate_limited` | Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block. | -| `StartCallNotReady` | `too_early` | `start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder. | -| `StateChangeDenied` | `not_authorized` | The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context. | -| `StorageDepositLimitExhausted` | `limit_exceeded` | The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`. | -| `StorageDepositNotEnoughFunds` | `insufficient_balance` | The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit. | -| `StorageOverflow` | `internal` | Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit. | -| `SubNetRegistrationDisabled` | `disabled` | Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid. | -| `SubnetBuybackRateLimitExceeded` | `rate_limited` | A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback. | -| `SubnetDoesNotExist` | `subnet_not_exists` | The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters. | -| `SubnetLimitReached` | `limit_exceeded` | `register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable. | -| `SubnetNotExists` | `subnet_not_exists` | The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved. | -| `SubtokenDisabled` | `subtoken_disabled` | The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved. | -| `SwapInputTooLarge` | `insufficient_liquidity` | The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed. | -| `SwapReturnedZero` | `insufficient_liquidity` | The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit. | -| `SymbolAlreadyInUse` | `already_exists` | The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken. | -| `SymbolDoesNotExist` | `not_found` | The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry. | -| `TargetBlockNumberInPast` | `invalid_argument` | The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block. | -| `TempoOutOfBounds` | `invalid_argument` | `set_tempo` was given a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range. Check the tempo argument against those chain constants and pick a value inside the bounds. | -| `TerminatedInConstructor` | `internal` | The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls. | -| `TerminatedWhileReentrant` | `invalid_argument` | `seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. | -| `TooBig` | `limit_exceeded` | The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it. | -| `TooFew` | `invalid_argument` | The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. | -| `TooFewSignatories` | `invalid_argument` | The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. | -| `TooMany` | `limit_exceeded` | A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`. | -| `TooManyCalls` | `limit_exceeded` | The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions. | -| `TooManyChildren` | `limit_exceeded` | `set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries. | -| `TooManyFieldsInCommitmentInfo` | `limit_exceeded` | The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit. | -| `TooManyFreezes` | `limit_exceeded` | The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first. | -| `TooManyHolds` | `limit_exceeded` | The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another. | -| `TooManyPendingExtrinsics` | `limit_exceeded` | `store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire. | -| `TooManyRegistrationsThisBlock` | `rate_limited` | Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block. | -| `TooManyRegistrationsThisInterval` | `rate_limited` | Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start. | -| `TooManyReserves` | `limit_exceeded` | The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another. | -| `TooManySignatories` | `limit_exceeded` | The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant. | -| `TooManyTopics` | `limit_exceeded` | The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit. | -| `TooManyUIDsPerMechanism` | `limit_exceeded` | Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit. | -| `TooManyUnrevealedCommits` | `limit_exceeded` | `commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again. | -| `TooSoon` | `rate_limited` | A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change. | -| `TransactionMustComeFromEOA` | `not_authorized` | Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead. | -| `TransactorAccountShouldBeHotKey` | `not_authorized` | The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin. | -| `TransferDisallowed` | `disabled` | A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first. | -| `TransferFailed` | `insufficient_balance` | A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit. | -| `TrimmingWouldExceedMaxImmunePercentage` | `limit_exceeded` | Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target. | -| `TxChildkeyTakeRateLimitExceeded` | `rate_limited` | `set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder. | -| `TxRateLimitExceeded` | `rate_limited` | An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass. | -| `UidMapCouldNotBeCleared` | `internal` | During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it. | -| `UidVecContainInvalidOne` | `invalid_argument` | The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`). | -| `UidsLengthExceedUidsInSubNet` | `limit_exceeded` | The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector. | -| `UnableToRecoverPublicKey` | `invalid_argument` | While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key. | -| `Unannounced` | `too_early` | The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`. | -| `Unauthorized` | `not_authorized` | In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`. | -| `Undefined` | `internal` | Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs. | -| `Underflow` | `internal` | A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`. | -| `UnexpectedTimepoint` | `invalid_argument` | A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry. | -| `UnexpectedUnreserveLeftover` | `internal` | While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`. | -| `UnlockAmountTooHigh` | `insufficient_balance` | An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount. | -| `Unproxyable` | `not_authorized` | The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call. | -| `Unreachable` | `internal` | `announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring. | -| `UnverifiedPulse` | `invalid_argument` | Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`. | -| `ValueNotInBounds` | `invalid_argument` | An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds. | -| `ValueTooLarge` | `limit_exceeded` | A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant. | -| `VestingBalance` | `insufficient_balance` | The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs. | -| `VotingPowerTrackingNotEnabled` | `disabled` | Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic. | -| `WaitingForDissolvedSubnetCleanup` | `too_early` | The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes. | -| `WeightExceedsAbsoluteMax` | `limit_exceeded` | `set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant. | -| `WeightVecLengthIsLow` | `invalid_argument` | The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid. | -| `WeightVecNotEqualSize` | `invalid_argument` | The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID. | -| `WithdrawFailed` | `insufficient_balance` | Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance. | -| `WrongTimepoint` | `invalid_argument` | The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint. | -| `XCMDecodeFailed` | `invalid_argument` | The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports. | -| `ZeroBalanceAfterWithdrawn` | `insufficient_balance` | Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn. | -| `ZeroShareInBatch` | `invalid_argument` | An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch. | diff --git a/docs/errors/already-exists.mdx b/docs/errors/already-exists.mdx new file mode 100644 index 0000000000..0073d3c33b --- /dev/null +++ b/docs/errors/already-exists.mdx @@ -0,0 +1,50 @@ +--- +title: "already_exists" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The state the call would create already exists: the hotkey is already registered on the subnet, an announcement or commit is already pending, the identity/symbol is already taken, or the approval was already given. + +This is often good news — the goal may already be met, so check the current state before retrying. if you meant to create something new, pick a different identifier or wait for the pending object to clear. + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `already_exists`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`ActiveLockExists`](/docs/errors/chain/ActiveLockExists) | The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first. | +| [`AlreadyApproved`](/docs/errors/chain/AlreadyApproved) | The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list. | +| [`AlreadyDeposited`](/docs/errors/chain/AlreadyDeposited) | The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason. | +| [`AlreadyFinalized`](/docs/errors/chain/AlreadyFinalized) | The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`. | +| [`AlreadyFinalizing`](/docs/errors/chain/AlreadyFinalizing) | A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying. | +| [`AlreadyNoted`](/docs/errors/chain/AlreadyNoted) | The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again. | +| [`AlreadyStored`](/docs/errors/chain/AlreadyStored) | The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again. | +| [`AutoEpochAlreadyImminent`](/docs/errors/chain/AutoEpochAlreadyImminent) | `trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire. | +| [`ChangePending`](/docs/errors/chain/ChangePending) | A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first. | +| [`ColdKeyAlreadyAssociated`](/docs/errors/chain/ColdKeyAlreadyAssociated) | The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead. | +| [`ColdkeySwapAlreadyDisputed`](/docs/errors/chain/ColdkeySwapAlreadyDisputed) | `dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed. | +| [`ColdkeySwapAnnounced`](/docs/errors/chain/ColdkeySwapAnnounced) | The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement. | +| [`DelegateDependencyAlreadyExists`](/docs/errors/chain/DelegateDependencyAlreadyExists) | The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it. | +| [`Duplicate`](/docs/errors/chain/Duplicate) | This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple. | +| [`DuplicateContract`](/docs/errors/chain/DuplicateContract) | Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address. | +| [`DuplicateOffenceReport`](/docs/errors/chain/DuplicateOffenceReport) | The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again. | +| [`Entered`](/docs/errors/chain/Entered) | Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages. | +| [`EpochTriggerAlreadyPending`](/docs/errors/chain/EpochTriggerAlreadyPending) | `trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again. | +| [`ExistingVestingSchedule`](/docs/errors/chain/ExistingVestingSchedule) | A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule. | +| [`Exited`](/docs/errors/chain/Exited) | Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting. | +| [`FirstEmissionBlockNumberAlreadySet`](/docs/errors/chain/FirstEmissionBlockNumberAlreadySet) | `start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed. | +| [`HotKeyAlreadyDelegate`](/docs/errors/chain/HotKeyAlreadyDelegate) | `become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed. | +| [`HotKeyAlreadyRegisteredInSubNet`](/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet) | A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid. | +| [`NetworkDissolveAlreadyQueued`](/docs/errors/chain/NetworkDissolveAlreadyQueued) | The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request. | +| [`OrderAlreadyProcessed`](/docs/errors/chain/OrderAlreadyProcessed) | The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`. | +| [`SameAutoStakeHotkeyAlreadySet`](/docs/errors/chain/SameAutoStakeHotkeyAlreadySet) | The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted. | +| [`SymbolAlreadyInUse`](/docs/errors/chain/SymbolAlreadyInUse) | The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken. | + +The same explanation is available in the terminal: `btcli explain already_exists` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/chain/AccountNotAllowedCommit.mdx b/docs/errors/chain/AccountNotAllowedCommit.mdx new file mode 100644 index 0000000000..56c0aefa72 --- /dev/null +++ b/docs/errors/chain/AccountNotAllowedCommit.mdx @@ -0,0 +1,16 @@ +--- +title: "AccountNotAllowedCommit" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet. + +Declared by the `Commitments` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain AccountNotAllowedCommit`. diff --git a/docs/errors/chain/AccountRejectsLockedAlpha.mdx b/docs/errors/chain/AccountRejectsLockedAlpha.mdx new file mode 100644 index 0000000000..ec1b3042a2 --- /dev/null +++ b/docs/errors/chain/AccountRejectsLockedAlpha.mdx @@ -0,0 +1,16 @@ +--- +title: "AccountRejectsLockedAlpha" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain AccountRejectsLockedAlpha`. diff --git a/docs/errors/chain/ActiveLockExists.mdx b/docs/errors/chain/ActiveLockExists.mdx new file mode 100644 index 0000000000..659a93687b --- /dev/null +++ b/docs/errors/chain/ActiveLockExists.mdx @@ -0,0 +1,16 @@ +--- +title: "ActiveLockExists" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain ActiveLockExists`. diff --git a/docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds.mdx b/docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds.mdx new file mode 100644 index 0000000000..050ca06b28 --- /dev/null +++ b/docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds.mdx @@ -0,0 +1,16 @@ +--- +title: "ActivityCutoffFactorMilliOutOfBounds" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ActivityCutoffFactorMilliOutOfBounds`. diff --git a/docs/errors/chain/ActivityCutoffTooLow.mdx b/docs/errors/chain/ActivityCutoffTooLow.mdx new file mode 100644 index 0000000000..da2faf6ebe --- /dev/null +++ b/docs/errors/chain/ActivityCutoffTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "ActivityCutoffTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ActivityCutoffTooLow`. diff --git a/docs/errors/chain/AddStakeBurnRateLimitExceeded.mdx b/docs/errors/chain/AddStakeBurnRateLimitExceeded.mdx new file mode 100644 index 0000000000..a8b56bf290 --- /dev/null +++ b/docs/errors/chain/AddStakeBurnRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "AddStakeBurnRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain AddStakeBurnRateLimitExceeded`. diff --git a/docs/errors/chain/AdminActionProhibitedDuringWeightsWindow.mdx b/docs/errors/chain/AdminActionProhibitedDuringWeightsWindow.mdx new file mode 100644 index 0000000000..adf62f8f11 --- /dev/null +++ b/docs/errors/chain/AdminActionProhibitedDuringWeightsWindow.mdx @@ -0,0 +1,16 @@ +--- +title: "AdminActionProhibitedDuringWeightsWindow" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain AdminActionProhibitedDuringWeightsWindow`. diff --git a/docs/errors/chain/AllNetworksInImmunity.mdx b/docs/errors/chain/AllNetworksInImmunity.mdx new file mode 100644 index 0000000000..2f36d1c6d7 --- /dev/null +++ b/docs/errors/chain/AllNetworksInImmunity.mdx @@ -0,0 +1,16 @@ +--- +title: "AllNetworksInImmunity" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain AllNetworksInImmunity`. diff --git a/docs/errors/chain/AlphaHighTooLow.mdx b/docs/errors/chain/AlphaHighTooLow.mdx new file mode 100644 index 0000000000..96edb9a4fa --- /dev/null +++ b/docs/errors/chain/AlphaHighTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "AlphaHighTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain AlphaHighTooLow`. diff --git a/docs/errors/chain/AlphaLowOutOfRange.mdx b/docs/errors/chain/AlphaLowOutOfRange.mdx new file mode 100644 index 0000000000..9a8fbb62be --- /dev/null +++ b/docs/errors/chain/AlphaLowOutOfRange.mdx @@ -0,0 +1,16 @@ +--- +title: "AlphaLowOutOfRange" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain AlphaLowOutOfRange`. diff --git a/docs/errors/chain/AlreadyApproved.mdx b/docs/errors/chain/AlreadyApproved.mdx new file mode 100644 index 0000000000..034262353b --- /dev/null +++ b/docs/errors/chain/AlreadyApproved.mdx @@ -0,0 +1,16 @@ +--- +title: "AlreadyApproved" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AlreadyApproved`. diff --git a/docs/errors/chain/AlreadyDeposited.mdx b/docs/errors/chain/AlreadyDeposited.mdx new file mode 100644 index 0000000000..c768a7e019 --- /dev/null +++ b/docs/errors/chain/AlreadyDeposited.mdx @@ -0,0 +1,16 @@ +--- +title: "AlreadyDeposited" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AlreadyDeposited`. diff --git a/docs/errors/chain/AlreadyFinalized.mdx b/docs/errors/chain/AlreadyFinalized.mdx new file mode 100644 index 0000000000..41551a0ec4 --- /dev/null +++ b/docs/errors/chain/AlreadyFinalized.mdx @@ -0,0 +1,16 @@ +--- +title: "AlreadyFinalized" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AlreadyFinalized`. diff --git a/docs/errors/chain/AlreadyFinalizing.mdx b/docs/errors/chain/AlreadyFinalizing.mdx new file mode 100644 index 0000000000..36e22406c4 --- /dev/null +++ b/docs/errors/chain/AlreadyFinalizing.mdx @@ -0,0 +1,16 @@ +--- +title: "AlreadyFinalizing" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AlreadyFinalizing`. diff --git a/docs/errors/chain/AlreadyNoted.mdx b/docs/errors/chain/AlreadyNoted.mdx new file mode 100644 index 0000000000..b8057c48db --- /dev/null +++ b/docs/errors/chain/AlreadyNoted.mdx @@ -0,0 +1,16 @@ +--- +title: "AlreadyNoted" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AlreadyNoted`. diff --git a/docs/errors/chain/AlreadyStored.mdx b/docs/errors/chain/AlreadyStored.mdx new file mode 100644 index 0000000000..2d18086103 --- /dev/null +++ b/docs/errors/chain/AlreadyStored.mdx @@ -0,0 +1,16 @@ +--- +title: "AlreadyStored" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AlreadyStored`. diff --git a/docs/errors/chain/AmountTooLow.mdx b/docs/errors/chain/AmountTooLow.mdx new file mode 100644 index 0000000000..d9127f4f25 --- /dev/null +++ b/docs/errors/chain/AmountTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "AmountTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain AmountTooLow`. diff --git a/docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch.mdx b/docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch.mdx new file mode 100644 index 0000000000..94c274e2ce --- /dev/null +++ b/docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch.mdx @@ -0,0 +1,16 @@ +--- +title: "AnnouncedColdkeyHashDoesNotMatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain AnnouncedColdkeyHashDoesNotMatch`. diff --git a/docs/errors/chain/AnnouncementDepositInvariantViolated.mdx b/docs/errors/chain/AnnouncementDepositInvariantViolated.mdx new file mode 100644 index 0000000000..3ae5236d6e --- /dev/null +++ b/docs/errors/chain/AnnouncementDepositInvariantViolated.mdx @@ -0,0 +1,16 @@ +--- +title: "AnnouncementDepositInvariantViolated" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain AnnouncementDepositInvariantViolated`. diff --git a/docs/errors/chain/ArithmeticOverflow.mdx b/docs/errors/chain/ArithmeticOverflow.mdx new file mode 100644 index 0000000000..0d40cf1a75 --- /dev/null +++ b/docs/errors/chain/ArithmeticOverflow.mdx @@ -0,0 +1,16 @@ +--- +title: "ArithmeticOverflow" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain ArithmeticOverflow`. diff --git a/docs/errors/chain/AutoEpochAlreadyImminent.mdx b/docs/errors/chain/AutoEpochAlreadyImminent.mdx new file mode 100644 index 0000000000..b4c9e046fe --- /dev/null +++ b/docs/errors/chain/AutoEpochAlreadyImminent.mdx @@ -0,0 +1,16 @@ +--- +title: "AutoEpochAlreadyImminent" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain AutoEpochAlreadyImminent`. diff --git a/docs/errors/chain/BadEncKeyLen.mdx b/docs/errors/chain/BadEncKeyLen.mdx new file mode 100644 index 0000000000..bb4992c96c --- /dev/null +++ b/docs/errors/chain/BadEncKeyLen.mdx @@ -0,0 +1,16 @@ +--- +title: "BadEncKeyLen" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing. + +Declared by the `MevShield` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain BadEncKeyLen`. diff --git a/docs/errors/chain/BalanceLow.mdx b/docs/errors/chain/BalanceLow.mdx new file mode 100644 index 0000000000..b9157e3f51 --- /dev/null +++ b/docs/errors/chain/BalanceLow.mdx @@ -0,0 +1,16 @@ +--- +title: "BalanceLow" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price. + +Declared by the `EVM` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain BalanceLow`. diff --git a/docs/errors/chain/BalanceWithdrawalError.mdx b/docs/errors/chain/BalanceWithdrawalError.mdx new file mode 100644 index 0000000000..7ddc407dfc --- /dev/null +++ b/docs/errors/chain/BalanceWithdrawalError.mdx @@ -0,0 +1,16 @@ +--- +title: "BalanceWithdrawalError" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain BalanceWithdrawalError`. diff --git a/docs/errors/chain/BeneficiaryDoesNotOwnHotkey.mdx b/docs/errors/chain/BeneficiaryDoesNotOwnHotkey.mdx new file mode 100644 index 0000000000..325e63f27f --- /dev/null +++ b/docs/errors/chain/BeneficiaryDoesNotOwnHotkey.mdx @@ -0,0 +1,16 @@ +--- +title: "BeneficiaryDoesNotOwnHotkey" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain BeneficiaryDoesNotOwnHotkey`. diff --git a/docs/errors/chain/BlockDurationTooLong.mdx b/docs/errors/chain/BlockDurationTooLong.mdx new file mode 100644 index 0000000000..8d8864ef45 --- /dev/null +++ b/docs/errors/chain/BlockDurationTooLong.mdx @@ -0,0 +1,16 @@ +--- +title: "BlockDurationTooLong" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain BlockDurationTooLong`. diff --git a/docs/errors/chain/BlockDurationTooShort.mdx b/docs/errors/chain/BlockDurationTooShort.mdx new file mode 100644 index 0000000000..a672feeab6 --- /dev/null +++ b/docs/errors/chain/BlockDurationTooShort.mdx @@ -0,0 +1,16 @@ +--- +title: "BlockDurationTooShort" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain BlockDurationTooShort`. diff --git a/docs/errors/chain/BondsMovingAverageMaxReached.mdx b/docs/errors/chain/BondsMovingAverageMaxReached.mdx new file mode 100644 index 0000000000..1eec0c8e63 --- /dev/null +++ b/docs/errors/chain/BondsMovingAverageMaxReached.mdx @@ -0,0 +1,16 @@ +--- +title: "BondsMovingAverageMaxReached" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain BondsMovingAverageMaxReached`. diff --git a/docs/errors/chain/CallDisabled.mdx b/docs/errors/chain/CallDisabled.mdx new file mode 100644 index 0000000000..1cd26e77a6 --- /dev/null +++ b/docs/errors/chain/CallDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "CallDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain CallDisabled`. diff --git a/docs/errors/chain/CallFiltered.mdx b/docs/errors/chain/CallFiltered.mdx new file mode 100644 index 0000000000..2eae02ae59 --- /dev/null +++ b/docs/errors/chain/CallFiltered.mdx @@ -0,0 +1,16 @@ +--- +title: "CallFiltered" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect. + +Declared by the `System` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain CallFiltered`. diff --git a/docs/errors/chain/CallUnavailable.mdx b/docs/errors/chain/CallUnavailable.mdx new file mode 100644 index 0000000000..1b862efd18 --- /dev/null +++ b/docs/errors/chain/CallUnavailable.mdx @@ -0,0 +1,16 @@ +--- +title: "CallUnavailable" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain CallUnavailable`. diff --git a/docs/errors/chain/CanNotSetRootNetworkWeights.mdx b/docs/errors/chain/CanNotSetRootNetworkWeights.mdx new file mode 100644 index 0000000000..154248049d --- /dev/null +++ b/docs/errors/chain/CanNotSetRootNetworkWeights.mdx @@ -0,0 +1,16 @@ +--- +title: "CanNotSetRootNetworkWeights" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CanNotSetRootNetworkWeights`. diff --git a/docs/errors/chain/CannotAddSelfAsDelegateDependency.mdx b/docs/errors/chain/CannotAddSelfAsDelegateDependency.mdx new file mode 100644 index 0000000000..5283401b9f --- /dev/null +++ b/docs/errors/chain/CannotAddSelfAsDelegateDependency.mdx @@ -0,0 +1,16 @@ +--- +title: "CannotAddSelfAsDelegateDependency" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CannotAddSelfAsDelegateDependency`. diff --git a/docs/errors/chain/CannotAffordLockCost.mdx b/docs/errors/chain/CannotAffordLockCost.mdx new file mode 100644 index 0000000000..985fc240b6 --- /dev/null +++ b/docs/errors/chain/CannotAffordLockCost.mdx @@ -0,0 +1,16 @@ +--- +title: "CannotAffordLockCost" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain CannotAffordLockCost`. diff --git a/docs/errors/chain/CannotBurnOrRecycleOnRootSubnet.mdx b/docs/errors/chain/CannotBurnOrRecycleOnRootSubnet.mdx new file mode 100644 index 0000000000..7e86f9b560 --- /dev/null +++ b/docs/errors/chain/CannotBurnOrRecycleOnRootSubnet.mdx @@ -0,0 +1,16 @@ +--- +title: "CannotBurnOrRecycleOnRootSubnet" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CannotBurnOrRecycleOnRootSubnet`. diff --git a/docs/errors/chain/CannotEndInPast.mdx b/docs/errors/chain/CannotEndInPast.mdx new file mode 100644 index 0000000000..c001b5e819 --- /dev/null +++ b/docs/errors/chain/CannotEndInPast.mdx @@ -0,0 +1,16 @@ +--- +title: "CannotEndInPast" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CannotEndInPast`. diff --git a/docs/errors/chain/CannotReleaseYet.mdx b/docs/errors/chain/CannotReleaseYet.mdx new file mode 100644 index 0000000000..e033f8c6ad --- /dev/null +++ b/docs/errors/chain/CannotReleaseYet.mdx @@ -0,0 +1,16 @@ +--- +title: "CannotReleaseYet" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain CannotReleaseYet`. diff --git a/docs/errors/chain/CannotUseSystemAccount.mdx b/docs/errors/chain/CannotUseSystemAccount.mdx new file mode 100644 index 0000000000..d16ae1a8c3 --- /dev/null +++ b/docs/errors/chain/CannotUseSystemAccount.mdx @@ -0,0 +1,16 @@ +--- +title: "CannotUseSystemAccount" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain CannotUseSystemAccount`. diff --git a/docs/errors/chain/CapNotRaised.mdx b/docs/errors/chain/CapNotRaised.mdx new file mode 100644 index 0000000000..7c38c3e9e4 --- /dev/null +++ b/docs/errors/chain/CapNotRaised.mdx @@ -0,0 +1,16 @@ +--- +title: "CapNotRaised" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain CapNotRaised`. diff --git a/docs/errors/chain/CapRaised.mdx b/docs/errors/chain/CapRaised.mdx new file mode 100644 index 0000000000..410c9f055b --- /dev/null +++ b/docs/errors/chain/CapRaised.mdx @@ -0,0 +1,16 @@ +--- +title: "CapRaised" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain CapRaised`. diff --git a/docs/errors/chain/CapTooLow.mdx b/docs/errors/chain/CapTooLow.mdx new file mode 100644 index 0000000000..42d0c51bfe --- /dev/null +++ b/docs/errors/chain/CapTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "CapTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CapTooLow`. diff --git a/docs/errors/chain/ChainIdMismatch.mdx b/docs/errors/chain/ChainIdMismatch.mdx new file mode 100644 index 0000000000..da5f9b7fa6 --- /dev/null +++ b/docs/errors/chain/ChainIdMismatch.mdx @@ -0,0 +1,16 @@ +--- +title: "ChainIdMismatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ChainIdMismatch`. diff --git a/docs/errors/chain/ChangePending.mdx b/docs/errors/chain/ChangePending.mdx new file mode 100644 index 0000000000..08a1550ee5 --- /dev/null +++ b/docs/errors/chain/ChangePending.mdx @@ -0,0 +1,16 @@ +--- +title: "ChangePending" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain ChangePending`. diff --git a/docs/errors/chain/ChildParentInconsistency.mdx b/docs/errors/chain/ChildParentInconsistency.mdx new file mode 100644 index 0000000000..f8a09f790e --- /dev/null +++ b/docs/errors/chain/ChildParentInconsistency.mdx @@ -0,0 +1,16 @@ +--- +title: "ChildParentInconsistency" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ChildParentInconsistency`. diff --git a/docs/errors/chain/CodeInUse.mdx b/docs/errors/chain/CodeInUse.mdx new file mode 100644 index 0000000000..a060517b50 --- /dev/null +++ b/docs/errors/chain/CodeInUse.mdx @@ -0,0 +1,16 @@ +--- +title: "CodeInUse" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CodeInUse`. diff --git a/docs/errors/chain/CodeInfoNotFound.mdx b/docs/errors/chain/CodeInfoNotFound.mdx new file mode 100644 index 0000000000..f7f2beeb4d --- /dev/null +++ b/docs/errors/chain/CodeInfoNotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "CodeInfoNotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain CodeInfoNotFound`. diff --git a/docs/errors/chain/CodeNotFound.mdx b/docs/errors/chain/CodeNotFound.mdx new file mode 100644 index 0000000000..0f0203e9a2 --- /dev/null +++ b/docs/errors/chain/CodeNotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "CodeNotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain CodeNotFound`. diff --git a/docs/errors/chain/CodeRejected.mdx b/docs/errors/chain/CodeRejected.mdx new file mode 100644 index 0000000000..2e8cc00e24 --- /dev/null +++ b/docs/errors/chain/CodeRejected.mdx @@ -0,0 +1,16 @@ +--- +title: "CodeRejected" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain CodeRejected`. diff --git a/docs/errors/chain/CodeTooLarge.mdx b/docs/errors/chain/CodeTooLarge.mdx new file mode 100644 index 0000000000..25aef781d7 --- /dev/null +++ b/docs/errors/chain/CodeTooLarge.mdx @@ -0,0 +1,16 @@ +--- +title: "CodeTooLarge" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain CodeTooLarge`. diff --git a/docs/errors/chain/ColdKeyAlreadyAssociated.mdx b/docs/errors/chain/ColdKeyAlreadyAssociated.mdx new file mode 100644 index 0000000000..c44c420974 --- /dev/null +++ b/docs/errors/chain/ColdKeyAlreadyAssociated.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdKeyAlreadyAssociated" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain ColdKeyAlreadyAssociated`. diff --git a/docs/errors/chain/ColdkeySwapAlreadyDisputed.mdx b/docs/errors/chain/ColdkeySwapAlreadyDisputed.mdx new file mode 100644 index 0000000000..9ae9d775e7 --- /dev/null +++ b/docs/errors/chain/ColdkeySwapAlreadyDisputed.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapAlreadyDisputed" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain ColdkeySwapAlreadyDisputed`. diff --git a/docs/errors/chain/ColdkeySwapAnnounced.mdx b/docs/errors/chain/ColdkeySwapAnnounced.mdx new file mode 100644 index 0000000000..132a542099 --- /dev/null +++ b/docs/errors/chain/ColdkeySwapAnnounced.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapAnnounced" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain ColdkeySwapAnnounced`. diff --git a/docs/errors/chain/ColdkeySwapAnnouncementNotFound.mdx b/docs/errors/chain/ColdkeySwapAnnouncementNotFound.mdx new file mode 100644 index 0000000000..aa075341ae --- /dev/null +++ b/docs/errors/chain/ColdkeySwapAnnouncementNotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapAnnouncementNotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain ColdkeySwapAnnouncementNotFound`. diff --git a/docs/errors/chain/ColdkeySwapClearTooEarly.mdx b/docs/errors/chain/ColdkeySwapClearTooEarly.mdx new file mode 100644 index 0000000000..d73693ad7f --- /dev/null +++ b/docs/errors/chain/ColdkeySwapClearTooEarly.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapClearTooEarly" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain ColdkeySwapClearTooEarly`. diff --git a/docs/errors/chain/ColdkeySwapDisputed.mdx b/docs/errors/chain/ColdkeySwapDisputed.mdx new file mode 100644 index 0000000000..262ecc40de --- /dev/null +++ b/docs/errors/chain/ColdkeySwapDisputed.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapDisputed" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain ColdkeySwapDisputed`. diff --git a/docs/errors/chain/ColdkeySwapReannouncedTooEarly.mdx b/docs/errors/chain/ColdkeySwapReannouncedTooEarly.mdx new file mode 100644 index 0000000000..49082e3169 --- /dev/null +++ b/docs/errors/chain/ColdkeySwapReannouncedTooEarly.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapReannouncedTooEarly" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain ColdkeySwapReannouncedTooEarly`. diff --git a/docs/errors/chain/ColdkeySwapTooEarly.mdx b/docs/errors/chain/ColdkeySwapTooEarly.mdx new file mode 100644 index 0000000000..5ee6a08a80 --- /dev/null +++ b/docs/errors/chain/ColdkeySwapTooEarly.mdx @@ -0,0 +1,16 @@ +--- +title: "ColdkeySwapTooEarly" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain ColdkeySwapTooEarly`. diff --git a/docs/errors/chain/CommitRevealDisabled.mdx b/docs/errors/chain/CommitRevealDisabled.mdx new file mode 100644 index 0000000000..7bf5494549 --- /dev/null +++ b/docs/errors/chain/CommitRevealDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "CommitRevealDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain CommitRevealDisabled`. diff --git a/docs/errors/chain/CommitRevealEnabled.mdx b/docs/errors/chain/CommitRevealEnabled.mdx new file mode 100644 index 0000000000..4be0f9155d --- /dev/null +++ b/docs/errors/chain/CommitRevealEnabled.mdx @@ -0,0 +1,16 @@ +--- +title: "CommitRevealEnabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain CommitRevealEnabled`. diff --git a/docs/errors/chain/CommittingWeightsTooFast.mdx b/docs/errors/chain/CommittingWeightsTooFast.mdx new file mode 100644 index 0000000000..1cb21ee9f6 --- /dev/null +++ b/docs/errors/chain/CommittingWeightsTooFast.mdx @@ -0,0 +1,16 @@ +--- +title: "CommittingWeightsTooFast" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain CommittingWeightsTooFast`. diff --git a/docs/errors/chain/ContractNotFound.mdx b/docs/errors/chain/ContractNotFound.mdx new file mode 100644 index 0000000000..eb4cdc871f --- /dev/null +++ b/docs/errors/chain/ContractNotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "ContractNotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain ContractNotFound`. diff --git a/docs/errors/chain/ContractReverted.mdx b/docs/errors/chain/ContractReverted.mdx new file mode 100644 index 0000000000..28b38df8a7 --- /dev/null +++ b/docs/errors/chain/ContractReverted.mdx @@ -0,0 +1,16 @@ +--- +title: "ContractReverted" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain ContractReverted`. diff --git a/docs/errors/chain/ContractTrapped.mdx b/docs/errors/chain/ContractTrapped.mdx new file mode 100644 index 0000000000..fc3d43b42f --- /dev/null +++ b/docs/errors/chain/ContractTrapped.mdx @@ -0,0 +1,16 @@ +--- +title: "ContractTrapped" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain ContractTrapped`. diff --git a/docs/errors/chain/ContributionPeriodEnded.mdx b/docs/errors/chain/ContributionPeriodEnded.mdx new file mode 100644 index 0000000000..cb35f6541d --- /dev/null +++ b/docs/errors/chain/ContributionPeriodEnded.mdx @@ -0,0 +1,16 @@ +--- +title: "ContributionPeriodEnded" +description: "The window has closed; restart the flow with fresh state" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`expired`](/docs/errors/expired). + +## Remediation + +The window has closed; restart the flow with fresh state + +The same explanation is available in the terminal: `btcli explain ContributionPeriodEnded`. diff --git a/docs/errors/chain/ContributionPeriodNotEnded.mdx b/docs/errors/chain/ContributionPeriodNotEnded.mdx new file mode 100644 index 0000000000..586770b91f --- /dev/null +++ b/docs/errors/chain/ContributionPeriodNotEnded.mdx @@ -0,0 +1,16 @@ +--- +title: "ContributionPeriodNotEnded" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain ContributionPeriodNotEnded`. diff --git a/docs/errors/chain/ContributionTooLow.mdx b/docs/errors/chain/ContributionTooLow.mdx new file mode 100644 index 0000000000..4fd32764e7 --- /dev/null +++ b/docs/errors/chain/ContributionTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "ContributionTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ContributionTooLow`. diff --git a/docs/errors/chain/CreateOriginNotAllowed.mdx b/docs/errors/chain/CreateOriginNotAllowed.mdx new file mode 100644 index 0000000000..adf8af5863 --- /dev/null +++ b/docs/errors/chain/CreateOriginNotAllowed.mdx @@ -0,0 +1,16 @@ +--- +title: "CreateOriginNotAllowed" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list. + +Declared by the `EVM` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain CreateOriginNotAllowed`. diff --git a/docs/errors/chain/CurrencyError.mdx b/docs/errors/chain/CurrencyError.mdx new file mode 100644 index 0000000000..696b38ae8e --- /dev/null +++ b/docs/errors/chain/CurrencyError.mdx @@ -0,0 +1,16 @@ +--- +title: "CurrencyError" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain CurrencyError`. diff --git a/docs/errors/chain/DeadAccount.mdx b/docs/errors/chain/DeadAccount.mdx new file mode 100644 index 0000000000..881159875f --- /dev/null +++ b/docs/errors/chain/DeadAccount.mdx @@ -0,0 +1,16 @@ +--- +title: "DeadAccount" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs. + +Declared by the `Balances` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain DeadAccount`. diff --git a/docs/errors/chain/DecodingFailed.mdx b/docs/errors/chain/DecodingFailed.mdx new file mode 100644 index 0000000000..6d5ca01254 --- /dev/null +++ b/docs/errors/chain/DecodingFailed.mdx @@ -0,0 +1,16 @@ +--- +title: "DecodingFailed" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DecodingFailed`. diff --git a/docs/errors/chain/DelegateDependencyAlreadyExists.mdx b/docs/errors/chain/DelegateDependencyAlreadyExists.mdx new file mode 100644 index 0000000000..a1b7251c81 --- /dev/null +++ b/docs/errors/chain/DelegateDependencyAlreadyExists.mdx @@ -0,0 +1,16 @@ +--- +title: "DelegateDependencyAlreadyExists" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain DelegateDependencyAlreadyExists`. diff --git a/docs/errors/chain/DelegateDependencyNotFound.mdx b/docs/errors/chain/DelegateDependencyNotFound.mdx new file mode 100644 index 0000000000..30730734c3 --- /dev/null +++ b/docs/errors/chain/DelegateDependencyNotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "DelegateDependencyNotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain DelegateDependencyNotFound`. diff --git a/docs/errors/chain/DelegateTakeTooHigh.mdx b/docs/errors/chain/DelegateTakeTooHigh.mdx new file mode 100644 index 0000000000..f7ce0560c5 --- /dev/null +++ b/docs/errors/chain/DelegateTakeTooHigh.mdx @@ -0,0 +1,16 @@ +--- +title: "DelegateTakeTooHigh" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DelegateTakeTooHigh`. diff --git a/docs/errors/chain/DelegateTakeTooLow.mdx b/docs/errors/chain/DelegateTakeTooLow.mdx new file mode 100644 index 0000000000..c06052e67b --- /dev/null +++ b/docs/errors/chain/DelegateTakeTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "DelegateTakeTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DelegateTakeTooLow`. diff --git a/docs/errors/chain/DelegateTxRateLimitExceeded.mdx b/docs/errors/chain/DelegateTxRateLimitExceeded.mdx new file mode 100644 index 0000000000..dec9c4a386 --- /dev/null +++ b/docs/errors/chain/DelegateTxRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "DelegateTxRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain DelegateTxRateLimitExceeded`. diff --git a/docs/errors/chain/DeltaZero.mdx b/docs/errors/chain/DeltaZero.mdx new file mode 100644 index 0000000000..b0d89dc42e --- /dev/null +++ b/docs/errors/chain/DeltaZero.mdx @@ -0,0 +1,16 @@ +--- +title: "DeltaZero" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount. + +Declared by the `Balances` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DeltaZero`. diff --git a/docs/errors/chain/DepositCannotBeWithdrawn.mdx b/docs/errors/chain/DepositCannotBeWithdrawn.mdx new file mode 100644 index 0000000000..c261a3b135 --- /dev/null +++ b/docs/errors/chain/DepositCannotBeWithdrawn.mdx @@ -0,0 +1,16 @@ +--- +title: "DepositCannotBeWithdrawn" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DepositCannotBeWithdrawn`. diff --git a/docs/errors/chain/DepositTooLow.mdx b/docs/errors/chain/DepositTooLow.mdx new file mode 100644 index 0000000000..9e9704b8f4 --- /dev/null +++ b/docs/errors/chain/DepositTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "DepositTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DepositTooLow`. diff --git a/docs/errors/chain/Deprecated.mdx b/docs/errors/chain/Deprecated.mdx new file mode 100644 index 0000000000..c4c996c552 --- /dev/null +++ b/docs/errors/chain/Deprecated.mdx @@ -0,0 +1,16 @@ +--- +title: "Deprecated" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`). + +Declared by the `SubtensorModule`, `AdminUtils`, `Swap` pallets; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain Deprecated`. diff --git a/docs/errors/chain/DisabledTemporarily.mdx b/docs/errors/chain/DisabledTemporarily.mdx new file mode 100644 index 0000000000..20844764ae --- /dev/null +++ b/docs/errors/chain/DisabledTemporarily.mdx @@ -0,0 +1,16 @@ +--- +title: "DisabledTemporarily" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain DisabledTemporarily`. diff --git a/docs/errors/chain/DrandConnectionFailure.mdx b/docs/errors/chain/DrandConnectionFailure.mdx new file mode 100644 index 0000000000..d019806c92 --- /dev/null +++ b/docs/errors/chain/DrandConnectionFailure.mdx @@ -0,0 +1,16 @@ +--- +title: "DrandConnectionFailure" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints. + +Declared by the `Drand` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain DrandConnectionFailure`. diff --git a/docs/errors/chain/Duplicate.mdx b/docs/errors/chain/Duplicate.mdx new file mode 100644 index 0000000000..2d5d848543 --- /dev/null +++ b/docs/errors/chain/Duplicate.mdx @@ -0,0 +1,16 @@ +--- +title: "Duplicate" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain Duplicate`. diff --git a/docs/errors/chain/DuplicateChild.mdx b/docs/errors/chain/DuplicateChild.mdx new file mode 100644 index 0000000000..e91949fd7e --- /dev/null +++ b/docs/errors/chain/DuplicateChild.mdx @@ -0,0 +1,16 @@ +--- +title: "DuplicateChild" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DuplicateChild`. diff --git a/docs/errors/chain/DuplicateContract.mdx b/docs/errors/chain/DuplicateContract.mdx new file mode 100644 index 0000000000..8668139ba9 --- /dev/null +++ b/docs/errors/chain/DuplicateContract.mdx @@ -0,0 +1,16 @@ +--- +title: "DuplicateContract" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain DuplicateContract`. diff --git a/docs/errors/chain/DuplicateOffenceReport.mdx b/docs/errors/chain/DuplicateOffenceReport.mdx new file mode 100644 index 0000000000..1c58051903 --- /dev/null +++ b/docs/errors/chain/DuplicateOffenceReport.mdx @@ -0,0 +1,16 @@ +--- +title: "DuplicateOffenceReport" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain DuplicateOffenceReport`. diff --git a/docs/errors/chain/DuplicateOrderInBatch.mdx b/docs/errors/chain/DuplicateOrderInBatch.mdx new file mode 100644 index 0000000000..23a428049a --- /dev/null +++ b/docs/errors/chain/DuplicateOrderInBatch.mdx @@ -0,0 +1,16 @@ +--- +title: "DuplicateOrderInBatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DuplicateOrderInBatch`. diff --git a/docs/errors/chain/DuplicateUids.mdx b/docs/errors/chain/DuplicateUids.mdx new file mode 100644 index 0000000000..40dd3e3551 --- /dev/null +++ b/docs/errors/chain/DuplicateUids.mdx @@ -0,0 +1,16 @@ +--- +title: "DuplicateUids" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain DuplicateUids`. diff --git a/docs/errors/chain/DynamicTempoBlockedByCommitReveal.mdx b/docs/errors/chain/DynamicTempoBlockedByCommitReveal.mdx new file mode 100644 index 0000000000..e1b6b3d3ad --- /dev/null +++ b/docs/errors/chain/DynamicTempoBlockedByCommitReveal.mdx @@ -0,0 +1,16 @@ +--- +title: "DynamicTempoBlockedByCommitReveal" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain DynamicTempoBlockedByCommitReveal`. diff --git a/docs/errors/chain/Entered.mdx b/docs/errors/chain/Entered.mdx new file mode 100644 index 0000000000..e0c43c38f3 --- /dev/null +++ b/docs/errors/chain/Entered.mdx @@ -0,0 +1,16 @@ +--- +title: "Entered" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain Entered`. diff --git a/docs/errors/chain/EpochTriggerAlreadyPending.mdx b/docs/errors/chain/EpochTriggerAlreadyPending.mdx new file mode 100644 index 0000000000..dc263157ba --- /dev/null +++ b/docs/errors/chain/EpochTriggerAlreadyPending.mdx @@ -0,0 +1,16 @@ +--- +title: "EpochTriggerAlreadyPending" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain EpochTriggerAlreadyPending`. diff --git a/docs/errors/chain/EvmKeyAssociateRateLimitExceeded.mdx b/docs/errors/chain/EvmKeyAssociateRateLimitExceeded.mdx new file mode 100644 index 0000000000..d0a6d56516 --- /dev/null +++ b/docs/errors/chain/EvmKeyAssociateRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "EvmKeyAssociateRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain EvmKeyAssociateRateLimitExceeded`. diff --git a/docs/errors/chain/EvmKeyAssociationLimitExceeded.mdx b/docs/errors/chain/EvmKeyAssociationLimitExceeded.mdx new file mode 100644 index 0000000000..90ea21aa1a --- /dev/null +++ b/docs/errors/chain/EvmKeyAssociationLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "EvmKeyAssociationLimitExceeded" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain EvmKeyAssociationLimitExceeded`. diff --git a/docs/errors/chain/ExistentialDeposit.mdx b/docs/errors/chain/ExistentialDeposit.mdx new file mode 100644 index 0000000000..ce2ff8b815 --- /dev/null +++ b/docs/errors/chain/ExistentialDeposit.mdx @@ -0,0 +1,16 @@ +--- +title: "ExistentialDeposit" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant. + +Declared by the `Balances` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain ExistentialDeposit`. diff --git a/docs/errors/chain/ExistingVestingSchedule.mdx b/docs/errors/chain/ExistingVestingSchedule.mdx new file mode 100644 index 0000000000..716e4ee2bb --- /dev/null +++ b/docs/errors/chain/ExistingVestingSchedule.mdx @@ -0,0 +1,16 @@ +--- +title: "ExistingVestingSchedule" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule. + +Declared by the `Balances` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain ExistingVestingSchedule`. diff --git a/docs/errors/chain/Exited.mdx b/docs/errors/chain/Exited.mdx new file mode 100644 index 0000000000..f9fec25ddb --- /dev/null +++ b/docs/errors/chain/Exited.mdx @@ -0,0 +1,16 @@ +--- +title: "Exited" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain Exited`. diff --git a/docs/errors/chain/ExpectedBeneficiaryOrigin.mdx b/docs/errors/chain/ExpectedBeneficiaryOrigin.mdx new file mode 100644 index 0000000000..19ba805ff8 --- /dev/null +++ b/docs/errors/chain/ExpectedBeneficiaryOrigin.mdx @@ -0,0 +1,16 @@ +--- +title: "ExpectedBeneficiaryOrigin" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain ExpectedBeneficiaryOrigin`. diff --git a/docs/errors/chain/Expendability.mdx b/docs/errors/chain/Expendability.mdx new file mode 100644 index 0000000000..f91df7da73 --- /dev/null +++ b/docs/errors/chain/Expendability.mdx @@ -0,0 +1,16 @@ +--- +title: "Expendability" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable. + +Declared by the `Balances` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain Expendability`. diff --git a/docs/errors/chain/ExpiredWeightCommit.mdx b/docs/errors/chain/ExpiredWeightCommit.mdx new file mode 100644 index 0000000000..2c4a832286 --- /dev/null +++ b/docs/errors/chain/ExpiredWeightCommit.mdx @@ -0,0 +1,16 @@ +--- +title: "ExpiredWeightCommit" +description: "The window has closed; restart the flow with fresh state" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`expired`](/docs/errors/expired). + +## Remediation + +The window has closed; restart the flow with fresh state + +The same explanation is available in the terminal: `btcli explain ExpiredWeightCommit`. diff --git a/docs/errors/chain/FailedToExtractRuntimeVersion.mdx b/docs/errors/chain/FailedToExtractRuntimeVersion.mdx new file mode 100644 index 0000000000..0c7880c1ac --- /dev/null +++ b/docs/errors/chain/FailedToExtractRuntimeVersion.mdx @@ -0,0 +1,16 @@ +--- +title: "FailedToExtractRuntimeVersion" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly. + +Declared by the `System` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain FailedToExtractRuntimeVersion`. diff --git a/docs/errors/chain/FailedToSchedule.mdx b/docs/errors/chain/FailedToSchedule.mdx new file mode 100644 index 0000000000..ca43f6db51 --- /dev/null +++ b/docs/errors/chain/FailedToSchedule.mdx @@ -0,0 +1,16 @@ +--- +title: "FailedToSchedule" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated. + +Declared by the `Scheduler` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain FailedToSchedule`. diff --git a/docs/errors/chain/FaucetDisabled.mdx b/docs/errors/chain/FaucetDisabled.mdx new file mode 100644 index 0000000000..e57f1e4e62 --- /dev/null +++ b/docs/errors/chain/FaucetDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "FaucetDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain FaucetDisabled`. diff --git a/docs/errors/chain/FeeOverflow.mdx b/docs/errors/chain/FeeOverflow.mdx new file mode 100644 index 0000000000..e587723f04 --- /dev/null +++ b/docs/errors/chain/FeeOverflow.mdx @@ -0,0 +1,16 @@ +--- +title: "FeeOverflow" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction. + +Declared by the `EVM` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain FeeOverflow`. diff --git a/docs/errors/chain/FeeRateTooHigh.mdx b/docs/errors/chain/FeeRateTooHigh.mdx new file mode 100644 index 0000000000..413cbff6b5 --- /dev/null +++ b/docs/errors/chain/FeeRateTooHigh.mdx @@ -0,0 +1,16 @@ +--- +title: "FeeRateTooHigh" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting. + +Declared by the `Swap` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain FeeRateTooHigh`. diff --git a/docs/errors/chain/FirstEmissionBlockNumberAlreadySet.mdx b/docs/errors/chain/FirstEmissionBlockNumberAlreadySet.mdx new file mode 100644 index 0000000000..ca6603ae37 --- /dev/null +++ b/docs/errors/chain/FirstEmissionBlockNumberAlreadySet.mdx @@ -0,0 +1,16 @@ +--- +title: "FirstEmissionBlockNumberAlreadySet" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain FirstEmissionBlockNumberAlreadySet`. diff --git a/docs/errors/chain/GasLimitTooHigh.mdx b/docs/errors/chain/GasLimitTooHigh.mdx new file mode 100644 index 0000000000..0edeb2da09 --- /dev/null +++ b/docs/errors/chain/GasLimitTooHigh.mdx @@ -0,0 +1,16 @@ +--- +title: "GasLimitTooHigh" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. + +Declared by the `EVM` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain GasLimitTooHigh`. diff --git a/docs/errors/chain/GasLimitTooLow.mdx b/docs/errors/chain/GasLimitTooLow.mdx new file mode 100644 index 0000000000..d7b78cdde8 --- /dev/null +++ b/docs/errors/chain/GasLimitTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "GasLimitTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. + +Declared by the `EVM` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain GasLimitTooLow`. diff --git a/docs/errors/chain/GasPriceTooLow.mdx b/docs/errors/chain/GasPriceTooLow.mdx new file mode 100644 index 0000000000..65f18faa16 --- /dev/null +++ b/docs/errors/chain/GasPriceTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "GasPriceTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. + +Declared by the `EVM` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain GasPriceTooLow`. diff --git a/docs/errors/chain/HotKeyAccountNotExists.mdx b/docs/errors/chain/HotKeyAccountNotExists.mdx new file mode 100644 index 0000000000..7a90261894 --- /dev/null +++ b/docs/errors/chain/HotKeyAccountNotExists.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeyAccountNotExists" +description: "Register the hotkey on this subnet first with `btcli subnets register`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_registered`](/docs/errors/not-registered). + +## Remediation + +Register the hotkey on this subnet first with `btcli subnets register` + +The same explanation is available in the terminal: `btcli explain HotKeyAccountNotExists`. diff --git a/docs/errors/chain/HotKeyAlreadyDelegate.mdx b/docs/errors/chain/HotKeyAlreadyDelegate.mdx new file mode 100644 index 0000000000..e17f1cc3d7 --- /dev/null +++ b/docs/errors/chain/HotKeyAlreadyDelegate.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeyAlreadyDelegate" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain HotKeyAlreadyDelegate`. diff --git a/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet.mdx b/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet.mdx new file mode 100644 index 0000000000..69feed2b61 --- /dev/null +++ b/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeyAlreadyRegisteredInSubNet" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain HotKeyAlreadyRegisteredInSubNet`. diff --git a/docs/errors/chain/HotKeyNotRegisteredInNetwork.mdx b/docs/errors/chain/HotKeyNotRegisteredInNetwork.mdx new file mode 100644 index 0000000000..1b2b66ed9d --- /dev/null +++ b/docs/errors/chain/HotKeyNotRegisteredInNetwork.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeyNotRegisteredInNetwork" +description: "Register the hotkey on this subnet first with `btcli subnets register`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_registered`](/docs/errors/not-registered). + +## Remediation + +Register the hotkey on this subnet first with `btcli subnets register` + +The same explanation is available in the terminal: `btcli explain HotKeyNotRegisteredInNetwork`. diff --git a/docs/errors/chain/HotKeyNotRegisteredInSubNet.mdx b/docs/errors/chain/HotKeyNotRegisteredInSubNet.mdx new file mode 100644 index 0000000000..9d84c336f0 --- /dev/null +++ b/docs/errors/chain/HotKeyNotRegisteredInSubNet.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeyNotRegisteredInSubNet" +description: "Register the hotkey on this subnet first with `btcli subnets register`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_registered`](/docs/errors/not-registered). + +## Remediation + +Register the hotkey on this subnet first with `btcli subnets register` + +The same explanation is available in the terminal: `btcli explain HotKeyNotRegisteredInSubNet`. diff --git a/docs/errors/chain/HotKeySetTxRateLimitExceeded.mdx b/docs/errors/chain/HotKeySetTxRateLimitExceeded.mdx new file mode 100644 index 0000000000..c3e0445532 --- /dev/null +++ b/docs/errors/chain/HotKeySetTxRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeySetTxRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain HotKeySetTxRateLimitExceeded`. diff --git a/docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed.mdx b/docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed.mdx new file mode 100644 index 0000000000..d20b570e19 --- /dev/null +++ b/docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed.mdx @@ -0,0 +1,16 @@ +--- +title: "HotKeySwapOnSubnetIntervalNotPassed" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain HotKeySwapOnSubnetIntervalNotPassed`. diff --git a/docs/errors/chain/IncorrectCommitRevealVersion.mdx b/docs/errors/chain/IncorrectCommitRevealVersion.mdx new file mode 100644 index 0000000000..9b1775d86a --- /dev/null +++ b/docs/errors/chain/IncorrectCommitRevealVersion.mdx @@ -0,0 +1,16 @@ +--- +title: "IncorrectCommitRevealVersion" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain IncorrectCommitRevealVersion`. diff --git a/docs/errors/chain/IncorrectPartialFillAmount.mdx b/docs/errors/chain/IncorrectPartialFillAmount.mdx new file mode 100644 index 0000000000..761d71ce80 --- /dev/null +++ b/docs/errors/chain/IncorrectPartialFillAmount.mdx @@ -0,0 +1,16 @@ +--- +title: "IncorrectPartialFillAmount" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain IncorrectPartialFillAmount`. diff --git a/docs/errors/chain/IncorrectWeightVersionKey.mdx b/docs/errors/chain/IncorrectWeightVersionKey.mdx new file mode 100644 index 0000000000..270e5925ba --- /dev/null +++ b/docs/errors/chain/IncorrectWeightVersionKey.mdx @@ -0,0 +1,16 @@ +--- +title: "IncorrectWeightVersionKey" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain IncorrectWeightVersionKey`. diff --git a/docs/errors/chain/Indeterministic.mdx b/docs/errors/chain/Indeterministic.mdx new file mode 100644 index 0000000000..0f9bebfd0b --- /dev/null +++ b/docs/errors/chain/Indeterministic.mdx @@ -0,0 +1,16 @@ +--- +title: "Indeterministic" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain Indeterministic`. diff --git a/docs/errors/chain/InputForwarded.mdx b/docs/errors/chain/InputForwarded.mdx new file mode 100644 index 0000000000..f46852848e --- /dev/null +++ b/docs/errors/chain/InputForwarded.mdx @@ -0,0 +1,16 @@ +--- +title: "InputForwarded" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InputForwarded`. diff --git a/docs/errors/chain/InputLengthsUnequal.mdx b/docs/errors/chain/InputLengthsUnequal.mdx new file mode 100644 index 0000000000..d3bf1fd8c0 --- /dev/null +++ b/docs/errors/chain/InputLengthsUnequal.mdx @@ -0,0 +1,16 @@ +--- +title: "InputLengthsUnequal" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InputLengthsUnequal`. diff --git a/docs/errors/chain/InsufficientBalance.mdx b/docs/errors/chain/InsufficientBalance.mdx new file mode 100644 index 0000000000..7607defcf0 --- /dev/null +++ b/docs/errors/chain/InsufficientBalance.mdx @@ -0,0 +1,16 @@ +--- +title: "InsufficientBalance" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved. + +Declared by the `Balances`, `SubtensorModule`, `Crowdloan`, `Swap` pallets; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain InsufficientBalance`. diff --git a/docs/errors/chain/InsufficientInputAmount.mdx b/docs/errors/chain/InsufficientInputAmount.mdx new file mode 100644 index 0000000000..4cc52cde8d --- /dev/null +++ b/docs/errors/chain/InsufficientInputAmount.mdx @@ -0,0 +1,16 @@ +--- +title: "InsufficientInputAmount" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output. + +Declared by the `Swap` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InsufficientInputAmount`. diff --git a/docs/errors/chain/InsufficientLiquidity.mdx b/docs/errors/chain/InsufficientLiquidity.mdx new file mode 100644 index 0000000000..ac57b95931 --- /dev/null +++ b/docs/errors/chain/InsufficientLiquidity.mdx @@ -0,0 +1,16 @@ +--- +title: "InsufficientLiquidity" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount. + +Declared by the `SubtensorModule`, `Swap` pallets; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain InsufficientLiquidity`. diff --git a/docs/errors/chain/InsufficientStakeForLock.mdx b/docs/errors/chain/InsufficientStakeForLock.mdx new file mode 100644 index 0000000000..4b5b0f4a89 --- /dev/null +++ b/docs/errors/chain/InsufficientStakeForLock.mdx @@ -0,0 +1,16 @@ +--- +title: "InsufficientStakeForLock" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain InsufficientStakeForLock`. diff --git a/docs/errors/chain/InvalidCallFlags.mdx b/docs/errors/chain/InvalidCallFlags.mdx new file mode 100644 index 0000000000..a4cacd9bdb --- /dev/null +++ b/docs/errors/chain/InvalidCallFlags.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidCallFlags" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidCallFlags`. diff --git a/docs/errors/chain/InvalidChainId.mdx b/docs/errors/chain/InvalidChainId.mdx new file mode 100644 index 0000000000..be1e1d5b30 --- /dev/null +++ b/docs/errors/chain/InvalidChainId.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidChainId" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction. + +Declared by the `EVM` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidChainId`. diff --git a/docs/errors/chain/InvalidChild.mdx b/docs/errors/chain/InvalidChild.mdx new file mode 100644 index 0000000000..880bfe3715 --- /dev/null +++ b/docs/errors/chain/InvalidChild.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidChild" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidChild`. diff --git a/docs/errors/chain/InvalidChildkeyTake.mdx b/docs/errors/chain/InvalidChildkeyTake.mdx new file mode 100644 index 0000000000..e628fd3182 --- /dev/null +++ b/docs/errors/chain/InvalidChildkeyTake.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidChildkeyTake" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidChildkeyTake`. diff --git a/docs/errors/chain/InvalidCrowdloanId.mdx b/docs/errors/chain/InvalidCrowdloanId.mdx new file mode 100644 index 0000000000..e252afa8cc --- /dev/null +++ b/docs/errors/chain/InvalidCrowdloanId.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidCrowdloanId" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain InvalidCrowdloanId`. diff --git a/docs/errors/chain/InvalidDerivedAccount.mdx b/docs/errors/chain/InvalidDerivedAccount.mdx new file mode 100644 index 0000000000..bc002ff950 --- /dev/null +++ b/docs/errors/chain/InvalidDerivedAccount.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidDerivedAccount" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation. + +Declared by the `Utility` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidDerivedAccount`. diff --git a/docs/errors/chain/InvalidDerivedAccountId.mdx b/docs/errors/chain/InvalidDerivedAccountId.mdx new file mode 100644 index 0000000000..592c96950c --- /dev/null +++ b/docs/errors/chain/InvalidDerivedAccountId.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidDerivedAccountId" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one). + +Declared by the `Proxy` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidDerivedAccountId`. diff --git a/docs/errors/chain/InvalidDifficulty.mdx b/docs/errors/chain/InvalidDifficulty.mdx new file mode 100644 index 0000000000..47c51a7e08 --- /dev/null +++ b/docs/errors/chain/InvalidDifficulty.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidDifficulty" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidDifficulty`. diff --git a/docs/errors/chain/InvalidEquivocationProof.mdx b/docs/errors/chain/InvalidEquivocationProof.mdx new file mode 100644 index 0000000000..adacb9f124 --- /dev/null +++ b/docs/errors/chain/InvalidEquivocationProof.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidEquivocationProof" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidEquivocationProof`. diff --git a/docs/errors/chain/InvalidFinalizationConfig.mdx b/docs/errors/chain/InvalidFinalizationConfig.mdx new file mode 100644 index 0000000000..0fcc94d9b7 --- /dev/null +++ b/docs/errors/chain/InvalidFinalizationConfig.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidFinalizationConfig" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidFinalizationConfig`. diff --git a/docs/errors/chain/InvalidIdentity.mdx b/docs/errors/chain/InvalidIdentity.mdx new file mode 100644 index 0000000000..9d8695ba05 --- /dev/null +++ b/docs/errors/chain/InvalidIdentity.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidIdentity" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidIdentity`. diff --git a/docs/errors/chain/InvalidIpAddress.mdx b/docs/errors/chain/InvalidIpAddress.mdx new file mode 100644 index 0000000000..152d03a958 --- /dev/null +++ b/docs/errors/chain/InvalidIpAddress.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidIpAddress" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidIpAddress`. diff --git a/docs/errors/chain/InvalidIpType.mdx b/docs/errors/chain/InvalidIpType.mdx new file mode 100644 index 0000000000..7bd5c5f07f --- /dev/null +++ b/docs/errors/chain/InvalidIpType.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidIpType" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidIpType`. diff --git a/docs/errors/chain/InvalidKeyOwnershipProof.mdx b/docs/errors/chain/InvalidKeyOwnershipProof.mdx new file mode 100644 index 0000000000..531cca9466 --- /dev/null +++ b/docs/errors/chain/InvalidKeyOwnershipProof.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidKeyOwnershipProof" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidKeyOwnershipProof`. diff --git a/docs/errors/chain/InvalidLeaseBeneficiary.mdx b/docs/errors/chain/InvalidLeaseBeneficiary.mdx new file mode 100644 index 0000000000..9da16ffc75 --- /dev/null +++ b/docs/errors/chain/InvalidLeaseBeneficiary.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidLeaseBeneficiary" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidLeaseBeneficiary`. diff --git a/docs/errors/chain/InvalidLiquidityValue.mdx b/docs/errors/chain/InvalidLiquidityValue.mdx new file mode 100644 index 0000000000..522b60fbf9 --- /dev/null +++ b/docs/errors/chain/InvalidLiquidityValue.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidLiquidityValue" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`. + +Declared by the `Swap` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidLiquidityValue`. diff --git a/docs/errors/chain/InvalidNonce.mdx b/docs/errors/chain/InvalidNonce.mdx new file mode 100644 index 0000000000..f14136488f --- /dev/null +++ b/docs/errors/chain/InvalidNonce.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidNonce" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`. + +Declared by the `EVM` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidNonce`. diff --git a/docs/errors/chain/InvalidNumRootClaim.mdx b/docs/errors/chain/InvalidNumRootClaim.mdx new file mode 100644 index 0000000000..733f4d6bea --- /dev/null +++ b/docs/errors/chain/InvalidNumRootClaim.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidNumRootClaim" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidNumRootClaim`. diff --git a/docs/errors/chain/InvalidOrigin.mdx b/docs/errors/chain/InvalidOrigin.mdx new file mode 100644 index 0000000000..27afca91e4 --- /dev/null +++ b/docs/errors/chain/InvalidOrigin.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidOrigin" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain InvalidOrigin`. diff --git a/docs/errors/chain/InvalidPort.mdx b/docs/errors/chain/InvalidPort.mdx new file mode 100644 index 0000000000..83d797c9d6 --- /dev/null +++ b/docs/errors/chain/InvalidPort.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidPort" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidPort`. diff --git a/docs/errors/chain/InvalidRecoveredPublicKey.mdx b/docs/errors/chain/InvalidRecoveredPublicKey.mdx new file mode 100644 index 0000000000..b4d38911bf --- /dev/null +++ b/docs/errors/chain/InvalidRecoveredPublicKey.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidRecoveredPublicKey" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format). + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidRecoveredPublicKey`. diff --git a/docs/errors/chain/InvalidRevealCommitHashNotMatch.mdx b/docs/errors/chain/InvalidRevealCommitHashNotMatch.mdx new file mode 100644 index 0000000000..6e8be71860 --- /dev/null +++ b/docs/errors/chain/InvalidRevealCommitHashNotMatch.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidRevealCommitHashNotMatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidRevealCommitHashNotMatch`. diff --git a/docs/errors/chain/InvalidRevealRound.mdx b/docs/errors/chain/InvalidRevealRound.mdx new file mode 100644 index 0000000000..aaa06d1f51 --- /dev/null +++ b/docs/errors/chain/InvalidRevealRound.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidRevealRound" +description: "The window has closed; restart the flow with fresh state" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`expired`](/docs/errors/expired). + +## Remediation + +The window has closed; restart the flow with fresh state + +The same explanation is available in the terminal: `btcli explain InvalidRevealRound`. diff --git a/docs/errors/chain/InvalidRootClaimThreshold.mdx b/docs/errors/chain/InvalidRootClaimThreshold.mdx new file mode 100644 index 0000000000..cadd782755 --- /dev/null +++ b/docs/errors/chain/InvalidRootClaimThreshold.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidRootClaimThreshold" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidRootClaimThreshold`. diff --git a/docs/errors/chain/InvalidRoundNumber.mdx b/docs/errors/chain/InvalidRoundNumber.mdx new file mode 100644 index 0000000000..b1d3ad195a --- /dev/null +++ b/docs/errors/chain/InvalidRoundNumber.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidRoundNumber" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`. + +Declared by the `Drand` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidRoundNumber`. diff --git a/docs/errors/chain/InvalidSchedule.mdx b/docs/errors/chain/InvalidSchedule.mdx new file mode 100644 index 0000000000..2752dc9710 --- /dev/null +++ b/docs/errors/chain/InvalidSchedule.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidSchedule" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidSchedule`. diff --git a/docs/errors/chain/InvalidSeal.mdx b/docs/errors/chain/InvalidSeal.mdx new file mode 100644 index 0000000000..beded35ebf --- /dev/null +++ b/docs/errors/chain/InvalidSeal.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidSeal" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidSeal`. diff --git a/docs/errors/chain/InvalidSignature.mdx b/docs/errors/chain/InvalidSignature.mdx new file mode 100644 index 0000000000..fc140c6410 --- /dev/null +++ b/docs/errors/chain/InvalidSignature.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidSignature" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed. + +Declared by the `Ethereum`, `EVM`, `LimitOrders` pallets; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidSignature`. diff --git a/docs/errors/chain/InvalidSpecName.mdx b/docs/errors/chain/InvalidSpecName.mdx new file mode 100644 index 0000000000..6ac1b678de --- /dev/null +++ b/docs/errors/chain/InvalidSpecName.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidSpecName" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one. + +Declared by the `System` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidSpecName`. diff --git a/docs/errors/chain/InvalidSubnetNumber.mdx b/docs/errors/chain/InvalidSubnetNumber.mdx new file mode 100644 index 0000000000..82d543f566 --- /dev/null +++ b/docs/errors/chain/InvalidSubnetNumber.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidSubnetNumber" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidSubnetNumber`. diff --git a/docs/errors/chain/InvalidTickRange.mdx b/docs/errors/chain/InvalidTickRange.mdx new file mode 100644 index 0000000000..54aca7d231 --- /dev/null +++ b/docs/errors/chain/InvalidTickRange.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidTickRange" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones. + +Declared by the `Swap` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidTickRange`. diff --git a/docs/errors/chain/InvalidValue.mdx b/docs/errors/chain/InvalidValue.mdx new file mode 100644 index 0000000000..ff4c125fe7 --- /dev/null +++ b/docs/errors/chain/InvalidValue.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidValue" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`). + +Declared by the `SubtensorModule`, `AdminUtils` pallets; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidValue`. diff --git a/docs/errors/chain/InvalidVotingPowerEmaAlpha.mdx b/docs/errors/chain/InvalidVotingPowerEmaAlpha.mdx new file mode 100644 index 0000000000..4b83453e4b --- /dev/null +++ b/docs/errors/chain/InvalidVotingPowerEmaAlpha.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidVotingPowerEmaAlpha" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidVotingPowerEmaAlpha`. diff --git a/docs/errors/chain/InvalidWorkBlock.mdx b/docs/errors/chain/InvalidWorkBlock.mdx new file mode 100644 index 0000000000..46b146722d --- /dev/null +++ b/docs/errors/chain/InvalidWorkBlock.mdx @@ -0,0 +1,16 @@ +--- +title: "InvalidWorkBlock" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain InvalidWorkBlock`. diff --git a/docs/errors/chain/IssuanceDeactivated.mdx b/docs/errors/chain/IssuanceDeactivated.mdx new file mode 100644 index 0000000000..baebf10240 --- /dev/null +++ b/docs/errors/chain/IssuanceDeactivated.mdx @@ -0,0 +1,16 @@ +--- +title: "IssuanceDeactivated" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again. + +Declared by the `Balances` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain IssuanceDeactivated`. diff --git a/docs/errors/chain/LeaseCannotEndInThePast.mdx b/docs/errors/chain/LeaseCannotEndInThePast.mdx new file mode 100644 index 0000000000..6d24f23977 --- /dev/null +++ b/docs/errors/chain/LeaseCannotEndInThePast.mdx @@ -0,0 +1,16 @@ +--- +title: "LeaseCannotEndInThePast" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain LeaseCannotEndInThePast`. diff --git a/docs/errors/chain/LeaseDoesNotExist.mdx b/docs/errors/chain/LeaseDoesNotExist.mdx new file mode 100644 index 0000000000..0235974c43 --- /dev/null +++ b/docs/errors/chain/LeaseDoesNotExist.mdx @@ -0,0 +1,16 @@ +--- +title: "LeaseDoesNotExist" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain LeaseDoesNotExist`. diff --git a/docs/errors/chain/LeaseHasNoEndBlock.mdx b/docs/errors/chain/LeaseHasNoEndBlock.mdx new file mode 100644 index 0000000000..1c6704d0ba --- /dev/null +++ b/docs/errors/chain/LeaseHasNoEndBlock.mdx @@ -0,0 +1,16 @@ +--- +title: "LeaseHasNoEndBlock" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain LeaseHasNoEndBlock`. diff --git a/docs/errors/chain/LeaseHasNotEnded.mdx b/docs/errors/chain/LeaseHasNotEnded.mdx new file mode 100644 index 0000000000..6021e59bf9 --- /dev/null +++ b/docs/errors/chain/LeaseHasNotEnded.mdx @@ -0,0 +1,16 @@ +--- +title: "LeaseHasNotEnded" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain LeaseHasNotEnded`. diff --git a/docs/errors/chain/LeaseNetuidNotFound.mdx b/docs/errors/chain/LeaseNetuidNotFound.mdx new file mode 100644 index 0000000000..4a2ce6263f --- /dev/null +++ b/docs/errors/chain/LeaseNetuidNotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "LeaseNetuidNotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain LeaseNetuidNotFound`. diff --git a/docs/errors/chain/LimitOrdersDisabled.mdx b/docs/errors/chain/LimitOrdersDisabled.mdx new file mode 100644 index 0000000000..a677ec9431 --- /dev/null +++ b/docs/errors/chain/LimitOrdersDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "LimitOrdersDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain LimitOrdersDisabled`. diff --git a/docs/errors/chain/LiquidAlphaDisabled.mdx b/docs/errors/chain/LiquidAlphaDisabled.mdx new file mode 100644 index 0000000000..f0b9b1f7cc --- /dev/null +++ b/docs/errors/chain/LiquidAlphaDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "LiquidAlphaDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain LiquidAlphaDisabled`. diff --git a/docs/errors/chain/LiquidityRestrictions.mdx b/docs/errors/chain/LiquidityRestrictions.mdx new file mode 100644 index 0000000000..05375872bb --- /dev/null +++ b/docs/errors/chain/LiquidityRestrictions.mdx @@ -0,0 +1,16 @@ +--- +title: "LiquidityRestrictions" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal. + +Declared by the `Balances` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain LiquidityRestrictions`. diff --git a/docs/errors/chain/LockHotkeyMismatch.mdx b/docs/errors/chain/LockHotkeyMismatch.mdx new file mode 100644 index 0000000000..bff2493ad8 --- /dev/null +++ b/docs/errors/chain/LockHotkeyMismatch.mdx @@ -0,0 +1,16 @@ +--- +title: "LockHotkeyMismatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain LockHotkeyMismatch`. diff --git a/docs/errors/chain/LockIdOverFlow.mdx b/docs/errors/chain/LockIdOverFlow.mdx new file mode 100644 index 0000000000..c18128b3f8 --- /dev/null +++ b/docs/errors/chain/LockIdOverFlow.mdx @@ -0,0 +1,16 @@ +--- +title: "LockIdOverFlow" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain LockIdOverFlow`. diff --git a/docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds.mdx b/docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds.mdx new file mode 100644 index 0000000000..d3d2c0ad30 --- /dev/null +++ b/docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxAllowedUIdsLessThanCurrentUIds" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MaxAllowedUIdsLessThanCurrentUIds`. diff --git a/docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids.mdx b/docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids.mdx new file mode 100644 index 0000000000..7c3d6182e6 --- /dev/null +++ b/docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxAllowedUidsGreaterThanDefaultMaxAllowedUids" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MaxAllowedUidsGreaterThanDefaultMaxAllowedUids`. diff --git a/docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids.mdx b/docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids.mdx new file mode 100644 index 0000000000..81aa372953 --- /dev/null +++ b/docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxAllowedUidsLessThanMinAllowedUids" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MaxAllowedUidsLessThanMinAllowedUids`. diff --git a/docs/errors/chain/MaxCallDepthReached.mdx b/docs/errors/chain/MaxCallDepthReached.mdx new file mode 100644 index 0000000000..112ae50e61 --- /dev/null +++ b/docs/errors/chain/MaxCallDepthReached.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxCallDepthReached" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain MaxCallDepthReached`. diff --git a/docs/errors/chain/MaxContributionReached.mdx b/docs/errors/chain/MaxContributionReached.mdx new file mode 100644 index 0000000000..72184bed9f --- /dev/null +++ b/docs/errors/chain/MaxContributionReached.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxContributionReached" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain MaxContributionReached`. diff --git a/docs/errors/chain/MaxContributorsReached.mdx b/docs/errors/chain/MaxContributorsReached.mdx new file mode 100644 index 0000000000..7714a6c325 --- /dev/null +++ b/docs/errors/chain/MaxContributorsReached.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxContributorsReached" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain MaxContributorsReached`. diff --git a/docs/errors/chain/MaxDelegateDependenciesReached.mdx b/docs/errors/chain/MaxDelegateDependenciesReached.mdx new file mode 100644 index 0000000000..2349819bd8 --- /dev/null +++ b/docs/errors/chain/MaxDelegateDependenciesReached.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxDelegateDependenciesReached" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain MaxDelegateDependenciesReached`. diff --git a/docs/errors/chain/MaxValidatorsLargerThanMaxUIds.mdx b/docs/errors/chain/MaxValidatorsLargerThanMaxUIds.mdx new file mode 100644 index 0000000000..b83009ea12 --- /dev/null +++ b/docs/errors/chain/MaxValidatorsLargerThanMaxUIds.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxValidatorsLargerThanMaxUIds" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MaxValidatorsLargerThanMaxUIds`. diff --git a/docs/errors/chain/MaxWeightExceeded.mdx b/docs/errors/chain/MaxWeightExceeded.mdx new file mode 100644 index 0000000000..df5e81802b --- /dev/null +++ b/docs/errors/chain/MaxWeightExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxWeightExceeded" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain MaxWeightExceeded`. diff --git a/docs/errors/chain/MaxWeightTooLow.mdx b/docs/errors/chain/MaxWeightTooLow.mdx new file mode 100644 index 0000000000..c5d4b90f1c --- /dev/null +++ b/docs/errors/chain/MaxWeightTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "MaxWeightTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MaxWeightTooLow`. diff --git a/docs/errors/chain/MaximumContributionTooLow.mdx b/docs/errors/chain/MaximumContributionTooLow.mdx new file mode 100644 index 0000000000..2a5f8cd6ca --- /dev/null +++ b/docs/errors/chain/MaximumContributionTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "MaximumContributionTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MaximumContributionTooLow`. diff --git a/docs/errors/chain/MechanismDoesNotExist.mdx b/docs/errors/chain/MechanismDoesNotExist.mdx new file mode 100644 index 0000000000..53565cc8f7 --- /dev/null +++ b/docs/errors/chain/MechanismDoesNotExist.mdx @@ -0,0 +1,16 @@ +--- +title: "MechanismDoesNotExist" +description: "Use an existing netuid; `btcli subnets list` shows valid ones" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet. + +Declared by the `SubtensorModule`, `Swap` pallets; it classifies to the semantic code [`subnet_not_exists`](/docs/errors/subnet-not-exists). + +## Remediation + +Use an existing netuid; `btcli subnets list` shows valid ones + +The same explanation is available in the terminal: `btcli explain MechanismDoesNotExist`. diff --git a/docs/errors/chain/MigrationInProgress.mdx b/docs/errors/chain/MigrationInProgress.mdx new file mode 100644 index 0000000000..3b706fb332 --- /dev/null +++ b/docs/errors/chain/MigrationInProgress.mdx @@ -0,0 +1,16 @@ +--- +title: "MigrationInProgress" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain MigrationInProgress`. diff --git a/docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids.mdx b/docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids.mdx new file mode 100644 index 0000000000..78569183d9 --- /dev/null +++ b/docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids.mdx @@ -0,0 +1,16 @@ +--- +title: "MinAllowedUidsGreaterThanCurrentUids" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MinAllowedUidsGreaterThanCurrentUids`. diff --git a/docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids.mdx b/docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids.mdx new file mode 100644 index 0000000000..62b3b2c95d --- /dev/null +++ b/docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids.mdx @@ -0,0 +1,16 @@ +--- +title: "MinAllowedUidsGreaterThanMaxAllowedUids" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MinAllowedUidsGreaterThanMaxAllowedUids`. diff --git a/docs/errors/chain/MinimumContributionTooHigh.mdx b/docs/errors/chain/MinimumContributionTooHigh.mdx new file mode 100644 index 0000000000..4061bc16ba --- /dev/null +++ b/docs/errors/chain/MinimumContributionTooHigh.mdx @@ -0,0 +1,16 @@ +--- +title: "MinimumContributionTooHigh" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MinimumContributionTooHigh`. diff --git a/docs/errors/chain/MinimumContributionTooLow.mdx b/docs/errors/chain/MinimumContributionTooLow.mdx new file mode 100644 index 0000000000..399e35f8e8 --- /dev/null +++ b/docs/errors/chain/MinimumContributionTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "MinimumContributionTooLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MinimumContributionTooLow`. diff --git a/docs/errors/chain/MinimumThreshold.mdx b/docs/errors/chain/MinimumThreshold.mdx new file mode 100644 index 0000000000..48fda10bd1 --- /dev/null +++ b/docs/errors/chain/MinimumThreshold.mdx @@ -0,0 +1,16 @@ +--- +title: "MinimumThreshold" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain MinimumThreshold`. diff --git a/docs/errors/chain/MultiBlockMigrationsOngoing.mdx b/docs/errors/chain/MultiBlockMigrationsOngoing.mdx new file mode 100644 index 0000000000..c5e0886874 --- /dev/null +++ b/docs/errors/chain/MultiBlockMigrationsOngoing.mdx @@ -0,0 +1,16 @@ +--- +title: "MultiBlockMigrationsOngoing" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade. + +Declared by the `System` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain MultiBlockMigrationsOngoing`. diff --git a/docs/errors/chain/Named.mdx b/docs/errors/chain/Named.mdx new file mode 100644 index 0000000000..64cb2b0705 --- /dev/null +++ b/docs/errors/chain/Named.mdx @@ -0,0 +1,16 @@ +--- +title: "Named" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map. + +Declared by the `Scheduler` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain Named`. diff --git a/docs/errors/chain/NeedWaitingMoreBlocksToStarCall.mdx b/docs/errors/chain/NeedWaitingMoreBlocksToStarCall.mdx new file mode 100644 index 0000000000..811da4d0a9 --- /dev/null +++ b/docs/errors/chain/NeedWaitingMoreBlocksToStarCall.mdx @@ -0,0 +1,16 @@ +--- +title: "NeedWaitingMoreBlocksToStarCall" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain NeedWaitingMoreBlocksToStarCall`. diff --git a/docs/errors/chain/NegativeSigmoidSteepness.mdx b/docs/errors/chain/NegativeSigmoidSteepness.mdx new file mode 100644 index 0000000000..cc1073b2d0 --- /dev/null +++ b/docs/errors/chain/NegativeSigmoidSteepness.mdx @@ -0,0 +1,16 @@ +--- +title: "NegativeSigmoidSteepness" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NegativeSigmoidSteepness`. diff --git a/docs/errors/chain/NetworkDissolveAlreadyQueued.mdx b/docs/errors/chain/NetworkDissolveAlreadyQueued.mdx new file mode 100644 index 0000000000..e2e8ec31b9 --- /dev/null +++ b/docs/errors/chain/NetworkDissolveAlreadyQueued.mdx @@ -0,0 +1,16 @@ +--- +title: "NetworkDissolveAlreadyQueued" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain NetworkDissolveAlreadyQueued`. diff --git a/docs/errors/chain/NetworkTxRateLimitExceeded.mdx b/docs/errors/chain/NetworkTxRateLimitExceeded.mdx new file mode 100644 index 0000000000..5b955bab66 --- /dev/null +++ b/docs/errors/chain/NetworkTxRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "NetworkTxRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain NetworkTxRateLimitExceeded`. diff --git a/docs/errors/chain/NeuronNoValidatorPermit.mdx b/docs/errors/chain/NeuronNoValidatorPermit.mdx new file mode 100644 index 0000000000..80d4d53d9a --- /dev/null +++ b/docs/errors/chain/NeuronNoValidatorPermit.mdx @@ -0,0 +1,16 @@ +--- +title: "NeuronNoValidatorPermit" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NeuronNoValidatorPermit`. diff --git a/docs/errors/chain/NewColdKeyIsHotkey.mdx b/docs/errors/chain/NewColdKeyIsHotkey.mdx new file mode 100644 index 0000000000..d5df62f7a5 --- /dev/null +++ b/docs/errors/chain/NewColdKeyIsHotkey.mdx @@ -0,0 +1,16 @@ +--- +title: "NewColdKeyIsHotkey" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NewColdKeyIsHotkey`. diff --git a/docs/errors/chain/NewHotKeyIsSameWithOld.mdx b/docs/errors/chain/NewHotKeyIsSameWithOld.mdx new file mode 100644 index 0000000000..43f0846e4d --- /dev/null +++ b/docs/errors/chain/NewHotKeyIsSameWithOld.mdx @@ -0,0 +1,16 @@ +--- +title: "NewHotKeyIsSameWithOld" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NewHotKeyIsSameWithOld`. diff --git a/docs/errors/chain/NewHotKeyNotCleanForRootSwap.mdx b/docs/errors/chain/NewHotKeyNotCleanForRootSwap.mdx new file mode 100644 index 0000000000..50112aa888 --- /dev/null +++ b/docs/errors/chain/NewHotKeyNotCleanForRootSwap.mdx @@ -0,0 +1,16 @@ +--- +title: "NewHotKeyNotCleanForRootSwap" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NewHotKeyNotCleanForRootSwap`. diff --git a/docs/errors/chain/NoApprovalsNeeded.mdx b/docs/errors/chain/NoApprovalsNeeded.mdx new file mode 100644 index 0000000000..ca07f59780 --- /dev/null +++ b/docs/errors/chain/NoApprovalsNeeded.mdx @@ -0,0 +1,16 @@ +--- +title: "NoApprovalsNeeded" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NoApprovalsNeeded`. diff --git a/docs/errors/chain/NoChainExtension.mdx b/docs/errors/chain/NoChainExtension.mdx new file mode 100644 index 0000000000..e69efba9a6 --- /dev/null +++ b/docs/errors/chain/NoChainExtension.mdx @@ -0,0 +1,16 @@ +--- +title: "NoChainExtension" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain NoChainExtension`. diff --git a/docs/errors/chain/NoContribution.mdx b/docs/errors/chain/NoContribution.mdx new file mode 100644 index 0000000000..ad2f46d691 --- /dev/null +++ b/docs/errors/chain/NoContribution.mdx @@ -0,0 +1,16 @@ +--- +title: "NoContribution" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NoContribution`. diff --git a/docs/errors/chain/NoDeposit.mdx b/docs/errors/chain/NoDeposit.mdx new file mode 100644 index 0000000000..336ccb3de2 --- /dev/null +++ b/docs/errors/chain/NoDeposit.mdx @@ -0,0 +1,16 @@ +--- +title: "NoDeposit" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NoDeposit`. diff --git a/docs/errors/chain/NoExistingLock.mdx b/docs/errors/chain/NoExistingLock.mdx new file mode 100644 index 0000000000..c983b30806 --- /dev/null +++ b/docs/errors/chain/NoExistingLock.mdx @@ -0,0 +1,16 @@ +--- +title: "NoExistingLock" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NoExistingLock`. diff --git a/docs/errors/chain/NoMigrationPerformed.mdx b/docs/errors/chain/NoMigrationPerformed.mdx new file mode 100644 index 0000000000..397377b6f7 --- /dev/null +++ b/docs/errors/chain/NoMigrationPerformed.mdx @@ -0,0 +1,16 @@ +--- +title: "NoMigrationPerformed" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NoMigrationPerformed`. diff --git a/docs/errors/chain/NoNeuronIdAvailable.mdx b/docs/errors/chain/NoNeuronIdAvailable.mdx new file mode 100644 index 0000000000..99f645af62 --- /dev/null +++ b/docs/errors/chain/NoNeuronIdAvailable.mdx @@ -0,0 +1,16 @@ +--- +title: "NoNeuronIdAvailable" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain NoNeuronIdAvailable`. diff --git a/docs/errors/chain/NoPermission.mdx b/docs/errors/chain/NoPermission.mdx new file mode 100644 index 0000000000..764b348ee5 --- /dev/null +++ b/docs/errors/chain/NoPermission.mdx @@ -0,0 +1,16 @@ +--- +title: "NoPermission" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NoPermission`. diff --git a/docs/errors/chain/NoSelfProxy.mdx b/docs/errors/chain/NoSelfProxy.mdx new file mode 100644 index 0000000000..fdf7db45e3 --- /dev/null +++ b/docs/errors/chain/NoSelfProxy.mdx @@ -0,0 +1,16 @@ +--- +title: "NoSelfProxy" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NoSelfProxy`. diff --git a/docs/errors/chain/NoTimepoint.mdx b/docs/errors/chain/NoTimepoint.mdx new file mode 100644 index 0000000000..fba597bc00 --- /dev/null +++ b/docs/errors/chain/NoTimepoint.mdx @@ -0,0 +1,16 @@ +--- +title: "NoTimepoint" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NoTimepoint`. diff --git a/docs/errors/chain/NoWeightsCommitFound.mdx b/docs/errors/chain/NoWeightsCommitFound.mdx new file mode 100644 index 0000000000..d3c7b673f7 --- /dev/null +++ b/docs/errors/chain/NoWeightsCommitFound.mdx @@ -0,0 +1,16 @@ +--- +title: "NoWeightsCommitFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NoWeightsCommitFound`. diff --git a/docs/errors/chain/NonAssociatedColdKey.mdx b/docs/errors/chain/NonAssociatedColdKey.mdx new file mode 100644 index 0000000000..4f7879d640 --- /dev/null +++ b/docs/errors/chain/NonAssociatedColdKey.mdx @@ -0,0 +1,16 @@ +--- +title: "NonAssociatedColdKey" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NonAssociatedColdKey`. diff --git a/docs/errors/chain/NonDefaultComposite.mdx b/docs/errors/chain/NonDefaultComposite.mdx new file mode 100644 index 0000000000..b966fc6694 --- /dev/null +++ b/docs/errors/chain/NonDefaultComposite.mdx @@ -0,0 +1,16 @@ +--- +title: "NonDefaultComposite" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way. + +Declared by the `System` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NonDefaultComposite`. diff --git a/docs/errors/chain/NonZeroRefCount.mdx b/docs/errors/chain/NonZeroRefCount.mdx new file mode 100644 index 0000000000..a7feeb3b4e --- /dev/null +++ b/docs/errors/chain/NonZeroRefCount.mdx @@ -0,0 +1,16 @@ +--- +title: "NonZeroRefCount" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first. + +Declared by the `System` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NonZeroRefCount`. diff --git a/docs/errors/chain/NoneValue.mdx b/docs/errors/chain/NoneValue.mdx new file mode 100644 index 0000000000..cfd89f2997 --- /dev/null +++ b/docs/errors/chain/NoneValue.mdx @@ -0,0 +1,16 @@ +--- +title: "NoneValue" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization. + +Declared by the `Drand` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NoneValue`. diff --git a/docs/errors/chain/NotAllowed.mdx b/docs/errors/chain/NotAllowed.mdx new file mode 100644 index 0000000000..b751f85f5f --- /dev/null +++ b/docs/errors/chain/NotAllowed.mdx @@ -0,0 +1,16 @@ +--- +title: "NotAllowed" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value. + +Declared by the `EVM` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NotAllowed`. diff --git a/docs/errors/chain/NotAuthorized.mdx b/docs/errors/chain/NotAuthorized.mdx new file mode 100644 index 0000000000..4211102069 --- /dev/null +++ b/docs/errors/chain/NotAuthorized.mdx @@ -0,0 +1,16 @@ +--- +title: "NotAuthorized" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NotAuthorized`. diff --git a/docs/errors/chain/NotConfigured.mdx b/docs/errors/chain/NotConfigured.mdx new file mode 100644 index 0000000000..0499181f50 --- /dev/null +++ b/docs/errors/chain/NotConfigured.mdx @@ -0,0 +1,16 @@ +--- +title: "NotConfigured" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants. + +Declared by the `SafeMode` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain NotConfigured`. diff --git a/docs/errors/chain/NotEnoughAlphaOutToRecycle.mdx b/docs/errors/chain/NotEnoughAlphaOutToRecycle.mdx new file mode 100644 index 0000000000..a3a2d29208 --- /dev/null +++ b/docs/errors/chain/NotEnoughAlphaOutToRecycle.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughAlphaOutToRecycle" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain NotEnoughAlphaOutToRecycle`. diff --git a/docs/errors/chain/NotEnoughBalanceToPaySwapColdKey.mdx b/docs/errors/chain/NotEnoughBalanceToPaySwapColdKey.mdx new file mode 100644 index 0000000000..b34d2ce3b7 --- /dev/null +++ b/docs/errors/chain/NotEnoughBalanceToPaySwapColdKey.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughBalanceToPaySwapColdKey" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughBalanceToPaySwapColdKey`. diff --git a/docs/errors/chain/NotEnoughBalanceToPaySwapHotKey.mdx b/docs/errors/chain/NotEnoughBalanceToPaySwapHotKey.mdx new file mode 100644 index 0000000000..f42ae346b1 --- /dev/null +++ b/docs/errors/chain/NotEnoughBalanceToPaySwapHotKey.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughBalanceToPaySwapHotKey" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughBalanceToPaySwapHotKey`. diff --git a/docs/errors/chain/NotEnoughBalanceToStake.mdx b/docs/errors/chain/NotEnoughBalanceToStake.mdx new file mode 100644 index 0000000000..0c1addbb78 --- /dev/null +++ b/docs/errors/chain/NotEnoughBalanceToStake.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughBalanceToStake" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid). + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughBalanceToStake`. diff --git a/docs/errors/chain/NotEnoughStake.mdx b/docs/errors/chain/NotEnoughStake.mdx new file mode 100644 index 0000000000..b713f7d2a3 --- /dev/null +++ b/docs/errors/chain/NotEnoughStake.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughStake" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughStake`. diff --git a/docs/errors/chain/NotEnoughStakeToSetChildkeys.mdx b/docs/errors/chain/NotEnoughStakeToSetChildkeys.mdx new file mode 100644 index 0000000000..0def334719 --- /dev/null +++ b/docs/errors/chain/NotEnoughStakeToSetChildkeys.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughStakeToSetChildkeys" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughStakeToSetChildkeys`. diff --git a/docs/errors/chain/NotEnoughStakeToSetWeights.mdx b/docs/errors/chain/NotEnoughStakeToSetWeights.mdx new file mode 100644 index 0000000000..28f9524b44 --- /dev/null +++ b/docs/errors/chain/NotEnoughStakeToSetWeights.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughStakeToSetWeights" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughStakeToSetWeights`. diff --git a/docs/errors/chain/NotEnoughStakeToWithdraw.mdx b/docs/errors/chain/NotEnoughStakeToWithdraw.mdx new file mode 100644 index 0000000000..3aa6f65433 --- /dev/null +++ b/docs/errors/chain/NotEnoughStakeToWithdraw.mdx @@ -0,0 +1,16 @@ +--- +title: "NotEnoughStakeToWithdraw" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage). + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain NotEnoughStakeToWithdraw`. diff --git a/docs/errors/chain/NotFound.mdx b/docs/errors/chain/NotFound.mdx new file mode 100644 index 0000000000..ac7e3b04ed --- /dev/null +++ b/docs/errors/chain/NotFound.mdx @@ -0,0 +1,16 @@ +--- +title: "NotFound" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state. + +Declared by the `Multisig`, `Scheduler`, `Proxy` pallets; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NotFound`. diff --git a/docs/errors/chain/NotNoted.mdx b/docs/errors/chain/NotNoted.mdx new file mode 100644 index 0000000000..f4976e0034 --- /dev/null +++ b/docs/errors/chain/NotNoted.mdx @@ -0,0 +1,16 @@ +--- +title: "NotNoted" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NotNoted`. diff --git a/docs/errors/chain/NotOwner.mdx b/docs/errors/chain/NotOwner.mdx new file mode 100644 index 0000000000..854299cf46 --- /dev/null +++ b/docs/errors/chain/NotOwner.mdx @@ -0,0 +1,16 @@ +--- +title: "NotOwner" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NotOwner`. diff --git a/docs/errors/chain/NotPermittedOnRootSubnet.mdx b/docs/errors/chain/NotPermittedOnRootSubnet.mdx new file mode 100644 index 0000000000..deff9e6315 --- /dev/null +++ b/docs/errors/chain/NotPermittedOnRootSubnet.mdx @@ -0,0 +1,16 @@ +--- +title: "NotPermittedOnRootSubnet" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NotPermittedOnRootSubnet`. diff --git a/docs/errors/chain/NotProxy.mdx b/docs/errors/chain/NotProxy.mdx new file mode 100644 index 0000000000..b4623d1558 --- /dev/null +++ b/docs/errors/chain/NotProxy.mdx @@ -0,0 +1,16 @@ +--- +title: "NotProxy" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NotProxy`. diff --git a/docs/errors/chain/NotReadyToDissolve.mdx b/docs/errors/chain/NotReadyToDissolve.mdx new file mode 100644 index 0000000000..f4812783f4 --- /dev/null +++ b/docs/errors/chain/NotReadyToDissolve.mdx @@ -0,0 +1,16 @@ +--- +title: "NotReadyToDissolve" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain NotReadyToDissolve`. diff --git a/docs/errors/chain/NotRequested.mdx b/docs/errors/chain/NotRequested.mdx new file mode 100644 index 0000000000..63ca765640 --- /dev/null +++ b/docs/errors/chain/NotRequested.mdx @@ -0,0 +1,16 @@ +--- +title: "NotRequested" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NotRequested`. diff --git a/docs/errors/chain/NotRootSubnet.mdx b/docs/errors/chain/NotRootSubnet.mdx new file mode 100644 index 0000000000..c2b1d09953 --- /dev/null +++ b/docs/errors/chain/NotRootSubnet.mdx @@ -0,0 +1,16 @@ +--- +title: "NotRootSubnet" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain NotRootSubnet`. diff --git a/docs/errors/chain/NotSubnetOwner.mdx b/docs/errors/chain/NotSubnetOwner.mdx new file mode 100644 index 0000000000..bf96251a0f --- /dev/null +++ b/docs/errors/chain/NotSubnetOwner.mdx @@ -0,0 +1,16 @@ +--- +title: "NotSubnetOwner" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`). + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain NotSubnetOwner`. diff --git a/docs/errors/chain/NothingAuthorized.mdx b/docs/errors/chain/NothingAuthorized.mdx new file mode 100644 index 0000000000..6723c9efcf --- /dev/null +++ b/docs/errors/chain/NothingAuthorized.mdx @@ -0,0 +1,16 @@ +--- +title: "NothingAuthorized" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code. + +Declared by the `System` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain NothingAuthorized`. diff --git a/docs/errors/chain/OrderAlreadyProcessed.mdx b/docs/errors/chain/OrderAlreadyProcessed.mdx new file mode 100644 index 0000000000..e99f3e9227 --- /dev/null +++ b/docs/errors/chain/OrderAlreadyProcessed.mdx @@ -0,0 +1,16 @@ +--- +title: "OrderAlreadyProcessed" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain OrderAlreadyProcessed`. diff --git a/docs/errors/chain/OrderCancelled.mdx b/docs/errors/chain/OrderCancelled.mdx new file mode 100644 index 0000000000..462e0835ce --- /dev/null +++ b/docs/errors/chain/OrderCancelled.mdx @@ -0,0 +1,16 @@ +--- +title: "OrderCancelled" +description: "The window has closed; restart the flow with fresh state" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`expired`](/docs/errors/expired). + +## Remediation + +The window has closed; restart the flow with fresh state + +The same explanation is available in the terminal: `btcli explain OrderCancelled`. diff --git a/docs/errors/chain/OrderExpired.mdx b/docs/errors/chain/OrderExpired.mdx new file mode 100644 index 0000000000..4cb8446d6d --- /dev/null +++ b/docs/errors/chain/OrderExpired.mdx @@ -0,0 +1,16 @@ +--- +title: "OrderExpired" +description: "The window has closed; restart the flow with fresh state" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`expired`](/docs/errors/expired). + +## Remediation + +The window has closed; restart the flow with fresh state + +The same explanation is available in the terminal: `btcli explain OrderExpired`. diff --git a/docs/errors/chain/OrderNetUidMismatch.mdx b/docs/errors/chain/OrderNetUidMismatch.mdx new file mode 100644 index 0000000000..e7c1de1135 --- /dev/null +++ b/docs/errors/chain/OrderNetUidMismatch.mdx @@ -0,0 +1,16 @@ +--- +title: "OrderNetUidMismatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain OrderNetUidMismatch`. diff --git a/docs/errors/chain/OutOfBounds.mdx b/docs/errors/chain/OutOfBounds.mdx new file mode 100644 index 0000000000..27fa332952 --- /dev/null +++ b/docs/errors/chain/OutOfBounds.mdx @@ -0,0 +1,16 @@ +--- +title: "OutOfBounds" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain OutOfBounds`. diff --git a/docs/errors/chain/OutOfGas.mdx b/docs/errors/chain/OutOfGas.mdx new file mode 100644 index 0000000000..b24f7f2a10 --- /dev/null +++ b/docs/errors/chain/OutOfGas.mdx @@ -0,0 +1,16 @@ +--- +title: "OutOfGas" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain OutOfGas`. diff --git a/docs/errors/chain/OutOfTransientStorage.mdx b/docs/errors/chain/OutOfTransientStorage.mdx new file mode 100644 index 0000000000..02b5715c74 --- /dev/null +++ b/docs/errors/chain/OutOfTransientStorage.mdx @@ -0,0 +1,16 @@ +--- +title: "OutOfTransientStorage" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain OutOfTransientStorage`. diff --git a/docs/errors/chain/OutputBufferTooSmall.mdx b/docs/errors/chain/OutputBufferTooSmall.mdx new file mode 100644 index 0000000000..dc07f37446 --- /dev/null +++ b/docs/errors/chain/OutputBufferTooSmall.mdx @@ -0,0 +1,16 @@ +--- +title: "OutputBufferTooSmall" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain OutputBufferTooSmall`. diff --git a/docs/errors/chain/Overflow.mdx b/docs/errors/chain/Overflow.mdx new file mode 100644 index 0000000000..b114fb529f --- /dev/null +++ b/docs/errors/chain/Overflow.mdx @@ -0,0 +1,16 @@ +--- +title: "Overflow" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values. + +Declared by the `SubtensorModule`, `Crowdloan` pallets; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain Overflow`. diff --git a/docs/errors/chain/POWRegistrationDisabled.mdx b/docs/errors/chain/POWRegistrationDisabled.mdx new file mode 100644 index 0000000000..ab3faf1cf7 --- /dev/null +++ b/docs/errors/chain/POWRegistrationDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "POWRegistrationDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain POWRegistrationDisabled`. diff --git a/docs/errors/chain/PalletHotkeyNotRegistered.mdx b/docs/errors/chain/PalletHotkeyNotRegistered.mdx new file mode 100644 index 0000000000..8d018762c2 --- /dev/null +++ b/docs/errors/chain/PalletHotkeyNotRegistered.mdx @@ -0,0 +1,16 @@ +--- +title: "PalletHotkeyNotRegistered" +description: "Register the hotkey on this subnet first with `btcli subnets register`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`not_registered`](/docs/errors/not-registered). + +## Remediation + +Register the hotkey on this subnet first with `btcli subnets register` + +The same explanation is available in the terminal: `btcli explain PalletHotkeyNotRegistered`. diff --git a/docs/errors/chain/PartialFillsNotEnabled.mdx b/docs/errors/chain/PartialFillsNotEnabled.mdx new file mode 100644 index 0000000000..ebb4d97b54 --- /dev/null +++ b/docs/errors/chain/PartialFillsNotEnabled.mdx @@ -0,0 +1,16 @@ +--- +title: "PartialFillsNotEnabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain PartialFillsNotEnabled`. diff --git a/docs/errors/chain/PauseFailed.mdx b/docs/errors/chain/PauseFailed.mdx new file mode 100644 index 0000000000..33fc2c60df --- /dev/null +++ b/docs/errors/chain/PauseFailed.mdx @@ -0,0 +1,16 @@ +--- +title: "PauseFailed" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain PauseFailed`. diff --git a/docs/errors/chain/PaymentOverflow.mdx b/docs/errors/chain/PaymentOverflow.mdx new file mode 100644 index 0000000000..3e62ba1829 --- /dev/null +++ b/docs/errors/chain/PaymentOverflow.mdx @@ -0,0 +1,16 @@ +--- +title: "PaymentOverflow" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction. + +Declared by the `EVM` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain PaymentOverflow`. diff --git a/docs/errors/chain/PreLogExists.mdx b/docs/errors/chain/PreLogExists.mdx new file mode 100644 index 0000000000..ec6b6fc4b6 --- /dev/null +++ b/docs/errors/chain/PreLogExists.mdx @@ -0,0 +1,16 @@ +--- +title: "PreLogExists" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it. + +Declared by the `Ethereum` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain PreLogExists`. diff --git a/docs/errors/chain/PriceConditionNotMet.mdx b/docs/errors/chain/PriceConditionNotMet.mdx new file mode 100644 index 0000000000..2f99ab42ae --- /dev/null +++ b/docs/errors/chain/PriceConditionNotMet.mdx @@ -0,0 +1,16 @@ +--- +title: "PriceConditionNotMet" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain PriceConditionNotMet`. diff --git a/docs/errors/chain/PriceLimitExceeded.mdx b/docs/errors/chain/PriceLimitExceeded.mdx new file mode 100644 index 0000000000..c356a4ed26 --- /dev/null +++ b/docs/errors/chain/PriceLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "PriceLimitExceeded" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting. + +Declared by the `Swap` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain PriceLimitExceeded`. diff --git a/docs/errors/chain/ProportionOverflow.mdx b/docs/errors/chain/ProportionOverflow.mdx new file mode 100644 index 0000000000..87d45cda5b --- /dev/null +++ b/docs/errors/chain/ProportionOverflow.mdx @@ -0,0 +1,16 @@ +--- +title: "ProportionOverflow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ProportionOverflow`. diff --git a/docs/errors/chain/PulseVerificationError.mdx b/docs/errors/chain/PulseVerificationError.mdx new file mode 100644 index 0000000000..b623130533 --- /dev/null +++ b/docs/errors/chain/PulseVerificationError.mdx @@ -0,0 +1,16 @@ +--- +title: "PulseVerificationError" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key). + +Declared by the `Drand` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain PulseVerificationError`. diff --git a/docs/errors/chain/RandomSubjectTooLong.mdx b/docs/errors/chain/RandomSubjectTooLong.mdx new file mode 100644 index 0000000000..6f5b59c71a --- /dev/null +++ b/docs/errors/chain/RandomSubjectTooLong.mdx @@ -0,0 +1,16 @@ +--- +title: "RandomSubjectTooLong" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain RandomSubjectTooLong`. diff --git a/docs/errors/chain/ReentranceDenied.mdx b/docs/errors/chain/ReentranceDenied.mdx new file mode 100644 index 0000000000..01defe0646 --- /dev/null +++ b/docs/errors/chain/ReentranceDenied.mdx @@ -0,0 +1,16 @@ +--- +title: "ReentranceDenied" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ReentranceDenied`. diff --git a/docs/errors/chain/Reentrancy.mdx b/docs/errors/chain/Reentrancy.mdx new file mode 100644 index 0000000000..e9d66d3e39 --- /dev/null +++ b/docs/errors/chain/Reentrancy.mdx @@ -0,0 +1,16 @@ +--- +title: "Reentrancy" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call. + +Declared by the `EVM` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain Reentrancy`. diff --git a/docs/errors/chain/RegistrationNotPermittedOnRootSubnet.mdx b/docs/errors/chain/RegistrationNotPermittedOnRootSubnet.mdx new file mode 100644 index 0000000000..b1bda60fad --- /dev/null +++ b/docs/errors/chain/RegistrationNotPermittedOnRootSubnet.mdx @@ -0,0 +1,16 @@ +--- +title: "RegistrationNotPermittedOnRootSubnet" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RegistrationNotPermittedOnRootSubnet`. diff --git a/docs/errors/chain/RegistrationPriceLimitExceeded.mdx b/docs/errors/chain/RegistrationPriceLimitExceeded.mdx new file mode 100644 index 0000000000..49374625fd --- /dev/null +++ b/docs/errors/chain/RegistrationPriceLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "RegistrationPriceLimitExceeded" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain RegistrationPriceLimitExceeded`. diff --git a/docs/errors/chain/RelayerMissMatch.mdx b/docs/errors/chain/RelayerMissMatch.mdx new file mode 100644 index 0000000000..2d00cf347a --- /dev/null +++ b/docs/errors/chain/RelayerMissMatch.mdx @@ -0,0 +1,16 @@ +--- +title: "RelayerMissMatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RelayerMissMatch`. diff --git a/docs/errors/chain/RelayerRequiredForPartialFill.mdx b/docs/errors/chain/RelayerRequiredForPartialFill.mdx new file mode 100644 index 0000000000..0ef8bf0cb4 --- /dev/null +++ b/docs/errors/chain/RelayerRequiredForPartialFill.mdx @@ -0,0 +1,16 @@ +--- +title: "RelayerRequiredForPartialFill" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RelayerRequiredForPartialFill`. diff --git a/docs/errors/chain/Requested.mdx b/docs/errors/chain/Requested.mdx new file mode 100644 index 0000000000..4414ac60cd --- /dev/null +++ b/docs/errors/chain/Requested.mdx @@ -0,0 +1,16 @@ +--- +title: "Requested" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain Requested`. diff --git a/docs/errors/chain/RequireSudo.mdx b/docs/errors/chain/RequireSudo.mdx new file mode 100644 index 0000000000..43acb87c4a --- /dev/null +++ b/docs/errors/chain/RequireSudo.mdx @@ -0,0 +1,16 @@ +--- +title: "RequireSudo" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item. + +Declared by the `Sudo` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain RequireSudo`. diff --git a/docs/errors/chain/RescheduleNoChange.mdx b/docs/errors/chain/RescheduleNoChange.mdx new file mode 100644 index 0000000000..93f305ffd1 --- /dev/null +++ b/docs/errors/chain/RescheduleNoChange.mdx @@ -0,0 +1,16 @@ +--- +title: "RescheduleNoChange" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block. + +Declared by the `Scheduler` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RescheduleNoChange`. diff --git a/docs/errors/chain/ReservesOutOfBalance.mdx b/docs/errors/chain/ReservesOutOfBalance.mdx new file mode 100644 index 0000000000..5640230b56 --- /dev/null +++ b/docs/errors/chain/ReservesOutOfBalance.mdx @@ -0,0 +1,16 @@ +--- +title: "ReservesOutOfBalance" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry. + +Declared by the `Swap` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain ReservesOutOfBalance`. diff --git a/docs/errors/chain/ReservesTooLow.mdx b/docs/errors/chain/ReservesTooLow.mdx new file mode 100644 index 0000000000..4cde918479 --- /dev/null +++ b/docs/errors/chain/ReservesTooLow.mdx @@ -0,0 +1,16 @@ +--- +title: "ReservesTooLow" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size. + +Declared by the `Swap` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain ReservesTooLow`. diff --git a/docs/errors/chain/ResumeFailed.mdx b/docs/errors/chain/ResumeFailed.mdx new file mode 100644 index 0000000000..6678d19b62 --- /dev/null +++ b/docs/errors/chain/ResumeFailed.mdx @@ -0,0 +1,16 @@ +--- +title: "ResumeFailed" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ResumeFailed`. diff --git a/docs/errors/chain/RevealPeriodTooLarge.mdx b/docs/errors/chain/RevealPeriodTooLarge.mdx new file mode 100644 index 0000000000..be328d3145 --- /dev/null +++ b/docs/errors/chain/RevealPeriodTooLarge.mdx @@ -0,0 +1,16 @@ +--- +title: "RevealPeriodTooLarge" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RevealPeriodTooLarge`. diff --git a/docs/errors/chain/RevealPeriodTooSmall.mdx b/docs/errors/chain/RevealPeriodTooSmall.mdx new file mode 100644 index 0000000000..265252ef26 --- /dev/null +++ b/docs/errors/chain/RevealPeriodTooSmall.mdx @@ -0,0 +1,16 @@ +--- +title: "RevealPeriodTooSmall" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RevealPeriodTooSmall`. diff --git a/docs/errors/chain/RevealTooEarly.mdx b/docs/errors/chain/RevealTooEarly.mdx new file mode 100644 index 0000000000..a2916054cc --- /dev/null +++ b/docs/errors/chain/RevealTooEarly.mdx @@ -0,0 +1,16 @@ +--- +title: "RevealTooEarly" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain RevealTooEarly`. diff --git a/docs/errors/chain/RootNetUidNotAllowed.mdx b/docs/errors/chain/RootNetUidNotAllowed.mdx new file mode 100644 index 0000000000..928e3f07af --- /dev/null +++ b/docs/errors/chain/RootNetUidNotAllowed.mdx @@ -0,0 +1,16 @@ +--- +title: "RootNetUidNotAllowed" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain RootNetUidNotAllowed`. diff --git a/docs/errors/chain/RootNetworkDoesNotExist.mdx b/docs/errors/chain/RootNetworkDoesNotExist.mdx new file mode 100644 index 0000000000..96764bca41 --- /dev/null +++ b/docs/errors/chain/RootNetworkDoesNotExist.mdx @@ -0,0 +1,16 @@ +--- +title: "RootNetworkDoesNotExist" +description: "Use an existing netuid; `btcli subnets list` shows valid ones" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`subnet_not_exists`](/docs/errors/subnet-not-exists). + +## Remediation + +Use an existing netuid; `btcli subnets list` shows valid ones + +The same explanation is available in the terminal: `btcli explain RootNetworkDoesNotExist`. diff --git a/docs/errors/chain/SameAutoStakeHotkeyAlreadySet.mdx b/docs/errors/chain/SameAutoStakeHotkeyAlreadySet.mdx new file mode 100644 index 0000000000..9163843436 --- /dev/null +++ b/docs/errors/chain/SameAutoStakeHotkeyAlreadySet.mdx @@ -0,0 +1,16 @@ +--- +title: "SameAutoStakeHotkeyAlreadySet" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain SameAutoStakeHotkeyAlreadySet`. diff --git a/docs/errors/chain/SameNetuid.mdx b/docs/errors/chain/SameNetuid.mdx new file mode 100644 index 0000000000..bb7306a3cd --- /dev/null +++ b/docs/errors/chain/SameNetuid.mdx @@ -0,0 +1,16 @@ +--- +title: "SameNetuid" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain SameNetuid`. diff --git a/docs/errors/chain/SenderInSignatories.mdx b/docs/errors/chain/SenderInSignatories.mdx new file mode 100644 index 0000000000..ef13949901 --- /dev/null +++ b/docs/errors/chain/SenderInSignatories.mdx @@ -0,0 +1,16 @@ +--- +title: "SenderInSignatories" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain SenderInSignatories`. diff --git a/docs/errors/chain/ServingRateLimitExceeded.mdx b/docs/errors/chain/ServingRateLimitExceeded.mdx new file mode 100644 index 0000000000..c20b83fc73 --- /dev/null +++ b/docs/errors/chain/ServingRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "ServingRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain ServingRateLimitExceeded`. diff --git a/docs/errors/chain/SettingWeightsTooFast.mdx b/docs/errors/chain/SettingWeightsTooFast.mdx new file mode 100644 index 0000000000..c5512229a3 --- /dev/null +++ b/docs/errors/chain/SettingWeightsTooFast.mdx @@ -0,0 +1,16 @@ +--- +title: "SettingWeightsTooFast" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain SettingWeightsTooFast`. diff --git a/docs/errors/chain/SignatoriesOutOfOrder.mdx b/docs/errors/chain/SignatoriesOutOfOrder.mdx new file mode 100644 index 0000000000..1d8b3a3bb3 --- /dev/null +++ b/docs/errors/chain/SignatoriesOutOfOrder.mdx @@ -0,0 +1,16 @@ +--- +title: "SignatoriesOutOfOrder" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain SignatoriesOutOfOrder`. diff --git a/docs/errors/chain/SlippageTooHigh.mdx b/docs/errors/chain/SlippageTooHigh.mdx new file mode 100644 index 0000000000..15e5008da2 --- /dev/null +++ b/docs/errors/chain/SlippageTooHigh.mdx @@ -0,0 +1,16 @@ +--- +title: "SlippageTooHigh" +description: "The price moved past the slippage-protection limit (stake trades are protected by default with a 5% tolerance); retry, raise the tolerance (`--rate-tolerance 0.1` / rate_tolerance=0.1), or disable protection entirely (`--no-slippage-protection` / slippage_protection=False)" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The price moved past the slippage-protection limit (stake trades are protected by default with a 5% tolerance); retry, raise the tolerance (`--rate-tolerance 0.1` / rate_tolerance=0.1), or disable protection entirely (`--no-slippage-protection` / slippage_protection=False) + +The same explanation is available in the terminal: `btcli explain SlippageTooHigh`. diff --git a/docs/errors/chain/SpaceLimitExceeded.mdx b/docs/errors/chain/SpaceLimitExceeded.mdx new file mode 100644 index 0000000000..08165d5ac9 --- /dev/null +++ b/docs/errors/chain/SpaceLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "SpaceLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage. + +Declared by the `Commitments` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain SpaceLimitExceeded`. diff --git a/docs/errors/chain/SpecVersionNeedsToIncrease.mdx b/docs/errors/chain/SpecVersionNeedsToIncrease.mdx new file mode 100644 index 0000000000..6f5996b1b0 --- /dev/null +++ b/docs/errors/chain/SpecVersionNeedsToIncrease.mdx @@ -0,0 +1,16 @@ +--- +title: "SpecVersionNeedsToIncrease" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain. + +Declared by the `System` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain SpecVersionNeedsToIncrease`. diff --git a/docs/errors/chain/StakeTooLowForRoot.mdx b/docs/errors/chain/StakeTooLowForRoot.mdx new file mode 100644 index 0000000000..0b6efac609 --- /dev/null +++ b/docs/errors/chain/StakeTooLowForRoot.mdx @@ -0,0 +1,16 @@ +--- +title: "StakeTooLowForRoot" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`). + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain StakeTooLowForRoot`. diff --git a/docs/errors/chain/StakeUnavailable.mdx b/docs/errors/chain/StakeUnavailable.mdx new file mode 100644 index 0000000000..5c50959d17 --- /dev/null +++ b/docs/errors/chain/StakeUnavailable.mdx @@ -0,0 +1,16 @@ +--- +title: "StakeUnavailable" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain StakeUnavailable`. diff --git a/docs/errors/chain/StakingRateLimitExceeded.mdx b/docs/errors/chain/StakingRateLimitExceeded.mdx new file mode 100644 index 0000000000..eb2ee7ae7c --- /dev/null +++ b/docs/errors/chain/StakingRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "StakingRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain StakingRateLimitExceeded`. diff --git a/docs/errors/chain/StartCallNotReady.mdx b/docs/errors/chain/StartCallNotReady.mdx new file mode 100644 index 0000000000..04554e901a --- /dev/null +++ b/docs/errors/chain/StartCallNotReady.mdx @@ -0,0 +1,16 @@ +--- +title: "StartCallNotReady" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain StartCallNotReady`. diff --git a/docs/errors/chain/StateChangeDenied.mdx b/docs/errors/chain/StateChangeDenied.mdx new file mode 100644 index 0000000000..288dbfc42e --- /dev/null +++ b/docs/errors/chain/StateChangeDenied.mdx @@ -0,0 +1,16 @@ +--- +title: "StateChangeDenied" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain StateChangeDenied`. diff --git a/docs/errors/chain/StorageDepositLimitExhausted.mdx b/docs/errors/chain/StorageDepositLimitExhausted.mdx new file mode 100644 index 0000000000..9211f438d4 --- /dev/null +++ b/docs/errors/chain/StorageDepositLimitExhausted.mdx @@ -0,0 +1,16 @@ +--- +title: "StorageDepositLimitExhausted" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain StorageDepositLimitExhausted`. diff --git a/docs/errors/chain/StorageDepositNotEnoughFunds.mdx b/docs/errors/chain/StorageDepositNotEnoughFunds.mdx new file mode 100644 index 0000000000..182ae7d55b --- /dev/null +++ b/docs/errors/chain/StorageDepositNotEnoughFunds.mdx @@ -0,0 +1,16 @@ +--- +title: "StorageDepositNotEnoughFunds" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain StorageDepositNotEnoughFunds`. diff --git a/docs/errors/chain/StorageOverflow.mdx b/docs/errors/chain/StorageOverflow.mdx new file mode 100644 index 0000000000..6e14d26ecc --- /dev/null +++ b/docs/errors/chain/StorageOverflow.mdx @@ -0,0 +1,16 @@ +--- +title: "StorageOverflow" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit. + +Declared by the `Drand` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain StorageOverflow`. diff --git a/docs/errors/chain/SubNetRegistrationDisabled.mdx b/docs/errors/chain/SubNetRegistrationDisabled.mdx new file mode 100644 index 0000000000..ab1ff922e0 --- /dev/null +++ b/docs/errors/chain/SubNetRegistrationDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "SubNetRegistrationDisabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain SubNetRegistrationDisabled`. diff --git a/docs/errors/chain/SubnetBuybackRateLimitExceeded.mdx b/docs/errors/chain/SubnetBuybackRateLimitExceeded.mdx new file mode 100644 index 0000000000..bf466553b1 --- /dev/null +++ b/docs/errors/chain/SubnetBuybackRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "SubnetBuybackRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain SubnetBuybackRateLimitExceeded`. diff --git a/docs/errors/chain/SubnetDoesNotExist.mdx b/docs/errors/chain/SubnetDoesNotExist.mdx new file mode 100644 index 0000000000..d3239e1da8 --- /dev/null +++ b/docs/errors/chain/SubnetDoesNotExist.mdx @@ -0,0 +1,16 @@ +--- +title: "SubnetDoesNotExist" +description: "Use an existing netuid; `btcli subnets list` shows valid ones" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`subnet_not_exists`](/docs/errors/subnet-not-exists). + +## Remediation + +Use an existing netuid; `btcli subnets list` shows valid ones + +The same explanation is available in the terminal: `btcli explain SubnetDoesNotExist`. diff --git a/docs/errors/chain/SubnetLimitReached.mdx b/docs/errors/chain/SubnetLimitReached.mdx new file mode 100644 index 0000000000..173aeafdd0 --- /dev/null +++ b/docs/errors/chain/SubnetLimitReached.mdx @@ -0,0 +1,16 @@ +--- +title: "SubnetLimitReached" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain SubnetLimitReached`. diff --git a/docs/errors/chain/SubnetNotExists.mdx b/docs/errors/chain/SubnetNotExists.mdx new file mode 100644 index 0000000000..2b2dcf65c9 --- /dev/null +++ b/docs/errors/chain/SubnetNotExists.mdx @@ -0,0 +1,16 @@ +--- +title: "SubnetNotExists" +description: "Use an existing netuid; `btcli subnets list` shows valid ones" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`subnet_not_exists`](/docs/errors/subnet-not-exists). + +## Remediation + +Use an existing netuid; `btcli subnets list` shows valid ones + +The same explanation is available in the terminal: `btcli explain SubnetNotExists`. diff --git a/docs/errors/chain/SubtokenDisabled.mdx b/docs/errors/chain/SubtokenDisabled.mdx new file mode 100644 index 0000000000..c429fd65d3 --- /dev/null +++ b/docs/errors/chain/SubtokenDisabled.mdx @@ -0,0 +1,16 @@ +--- +title: "SubtokenDisabled" +description: "The subnet is not active yet; wait for start_call" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved. + +Declared by the `SubtensorModule`, `Swap` pallets; it classifies to the semantic code [`subtoken_disabled`](/docs/errors/subtoken-disabled). + +## Remediation + +The subnet is not active yet; wait for start_call + +The same explanation is available in the terminal: `btcli explain SubtokenDisabled`. diff --git a/docs/errors/chain/SwapInputTooLarge.mdx b/docs/errors/chain/SwapInputTooLarge.mdx new file mode 100644 index 0000000000..15ae3ad440 --- /dev/null +++ b/docs/errors/chain/SwapInputTooLarge.mdx @@ -0,0 +1,16 @@ +--- +title: "SwapInputTooLarge" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed. + +Declared by the `Swap` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain SwapInputTooLarge`. diff --git a/docs/errors/chain/SwapReturnedZero.mdx b/docs/errors/chain/SwapReturnedZero.mdx new file mode 100644 index 0000000000..6b12b80bc2 --- /dev/null +++ b/docs/errors/chain/SwapReturnedZero.mdx @@ -0,0 +1,16 @@ +--- +title: "SwapReturnedZero" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`insufficient_liquidity`](/docs/errors/insufficient-liquidity). + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +The same explanation is available in the terminal: `btcli explain SwapReturnedZero`. diff --git a/docs/errors/chain/SymbolAlreadyInUse.mdx b/docs/errors/chain/SymbolAlreadyInUse.mdx new file mode 100644 index 0000000000..bf8378cc86 --- /dev/null +++ b/docs/errors/chain/SymbolAlreadyInUse.mdx @@ -0,0 +1,16 @@ +--- +title: "SymbolAlreadyInUse" +description: "The object or state already exists; treat the goal as met or pick a different target" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`already_exists`](/docs/errors/already-exists). + +## Remediation + +The object or state already exists; treat the goal as met or pick a different target + +The same explanation is available in the terminal: `btcli explain SymbolAlreadyInUse`. diff --git a/docs/errors/chain/SymbolDoesNotExist.mdx b/docs/errors/chain/SymbolDoesNotExist.mdx new file mode 100644 index 0000000000..ad891e3da7 --- /dev/null +++ b/docs/errors/chain/SymbolDoesNotExist.mdx @@ -0,0 +1,16 @@ +--- +title: "SymbolDoesNotExist" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_found`](/docs/errors/not-found). + +## Remediation + +The referenced object is not on-chain; check the identifier + +The same explanation is available in the terminal: `btcli explain SymbolDoesNotExist`. diff --git a/docs/errors/chain/TargetBlockNumberInPast.mdx b/docs/errors/chain/TargetBlockNumberInPast.mdx new file mode 100644 index 0000000000..ee0e0e4db7 --- /dev/null +++ b/docs/errors/chain/TargetBlockNumberInPast.mdx @@ -0,0 +1,16 @@ +--- +title: "TargetBlockNumberInPast" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block. + +Declared by the `Scheduler` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain TargetBlockNumberInPast`. diff --git a/docs/errors/chain/TempoOutOfBounds.mdx b/docs/errors/chain/TempoOutOfBounds.mdx new file mode 100644 index 0000000000..eeb9eab56b --- /dev/null +++ b/docs/errors/chain/TempoOutOfBounds.mdx @@ -0,0 +1,16 @@ +--- +title: "TempoOutOfBounds" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain constants and pick a value inside the bounds; only root may set a tempo outside them. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain TempoOutOfBounds`. diff --git a/docs/errors/chain/TerminatedInConstructor.mdx b/docs/errors/chain/TerminatedInConstructor.mdx new file mode 100644 index 0000000000..28b44c8007 --- /dev/null +++ b/docs/errors/chain/TerminatedInConstructor.mdx @@ -0,0 +1,16 @@ +--- +title: "TerminatedInConstructor" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain TerminatedInConstructor`. diff --git a/docs/errors/chain/TerminatedWhileReentrant.mdx b/docs/errors/chain/TerminatedWhileReentrant.mdx new file mode 100644 index 0000000000..8854bc47c3 --- /dev/null +++ b/docs/errors/chain/TerminatedWhileReentrant.mdx @@ -0,0 +1,16 @@ +--- +title: "TerminatedWhileReentrant" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain TerminatedWhileReentrant`. diff --git a/docs/errors/chain/TooBig.mdx b/docs/errors/chain/TooBig.mdx new file mode 100644 index 0000000000..625c6a961b --- /dev/null +++ b/docs/errors/chain/TooBig.mdx @@ -0,0 +1,16 @@ +--- +title: "TooBig" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooBig`. diff --git a/docs/errors/chain/TooFew.mdx b/docs/errors/chain/TooFew.mdx new file mode 100644 index 0000000000..b9b0a4dec4 --- /dev/null +++ b/docs/errors/chain/TooFew.mdx @@ -0,0 +1,16 @@ +--- +title: "TooFew" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. + +Declared by the `Preimage` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain TooFew`. diff --git a/docs/errors/chain/TooFewSignatories.mdx b/docs/errors/chain/TooFewSignatories.mdx new file mode 100644 index 0000000000..c01a3c6106 --- /dev/null +++ b/docs/errors/chain/TooFewSignatories.mdx @@ -0,0 +1,16 @@ +--- +title: "TooFewSignatories" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain TooFewSignatories`. diff --git a/docs/errors/chain/TooMany.mdx b/docs/errors/chain/TooMany.mdx new file mode 100644 index 0000000000..5fddb44c41 --- /dev/null +++ b/docs/errors/chain/TooMany.mdx @@ -0,0 +1,16 @@ +--- +title: "TooMany" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`. + +Declared by the `Preimage`, `Proxy` pallets; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooMany`. diff --git a/docs/errors/chain/TooManyCalls.mdx b/docs/errors/chain/TooManyCalls.mdx new file mode 100644 index 0000000000..80c45f503b --- /dev/null +++ b/docs/errors/chain/TooManyCalls.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyCalls" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions. + +Declared by the `Utility` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyCalls`. diff --git a/docs/errors/chain/TooManyChildren.mdx b/docs/errors/chain/TooManyChildren.mdx new file mode 100644 index 0000000000..2ad0fce861 --- /dev/null +++ b/docs/errors/chain/TooManyChildren.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyChildren" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyChildren`. diff --git a/docs/errors/chain/TooManyFieldsInCommitmentInfo.mdx b/docs/errors/chain/TooManyFieldsInCommitmentInfo.mdx new file mode 100644 index 0000000000..e6424076da --- /dev/null +++ b/docs/errors/chain/TooManyFieldsInCommitmentInfo.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyFieldsInCommitmentInfo" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit. + +Declared by the `Commitments` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyFieldsInCommitmentInfo`. diff --git a/docs/errors/chain/TooManyFreezes.mdx b/docs/errors/chain/TooManyFreezes.mdx new file mode 100644 index 0000000000..674f79e05e --- /dev/null +++ b/docs/errors/chain/TooManyFreezes.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyFreezes" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first. + +Declared by the `Balances` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyFreezes`. diff --git a/docs/errors/chain/TooManyHolds.mdx b/docs/errors/chain/TooManyHolds.mdx new file mode 100644 index 0000000000..a54f309996 --- /dev/null +++ b/docs/errors/chain/TooManyHolds.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyHolds" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another. + +Declared by the `Balances` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyHolds`. diff --git a/docs/errors/chain/TooManyPendingExtrinsics.mdx b/docs/errors/chain/TooManyPendingExtrinsics.mdx new file mode 100644 index 0000000000..451ed311d0 --- /dev/null +++ b/docs/errors/chain/TooManyPendingExtrinsics.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyPendingExtrinsics" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire. + +Declared by the `MevShield` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyPendingExtrinsics`. diff --git a/docs/errors/chain/TooManyRegistrationsThisBlock.mdx b/docs/errors/chain/TooManyRegistrationsThisBlock.mdx new file mode 100644 index 0000000000..640f53ac93 --- /dev/null +++ b/docs/errors/chain/TooManyRegistrationsThisBlock.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyRegistrationsThisBlock" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain TooManyRegistrationsThisBlock`. diff --git a/docs/errors/chain/TooManyRegistrationsThisInterval.mdx b/docs/errors/chain/TooManyRegistrationsThisInterval.mdx new file mode 100644 index 0000000000..66c9874ef0 --- /dev/null +++ b/docs/errors/chain/TooManyRegistrationsThisInterval.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyRegistrationsThisInterval" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain TooManyRegistrationsThisInterval`. diff --git a/docs/errors/chain/TooManyReserves.mdx b/docs/errors/chain/TooManyReserves.mdx new file mode 100644 index 0000000000..80c2640620 --- /dev/null +++ b/docs/errors/chain/TooManyReserves.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyReserves" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another. + +Declared by the `Balances` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyReserves`. diff --git a/docs/errors/chain/TooManySignatories.mdx b/docs/errors/chain/TooManySignatories.mdx new file mode 100644 index 0000000000..08b8a3f8e0 --- /dev/null +++ b/docs/errors/chain/TooManySignatories.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManySignatories" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManySignatories`. diff --git a/docs/errors/chain/TooManyTopics.mdx b/docs/errors/chain/TooManyTopics.mdx new file mode 100644 index 0000000000..97c76a677b --- /dev/null +++ b/docs/errors/chain/TooManyTopics.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyTopics" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyTopics`. diff --git a/docs/errors/chain/TooManyUIDsPerMechanism.mdx b/docs/errors/chain/TooManyUIDsPerMechanism.mdx new file mode 100644 index 0000000000..749b3a62d5 --- /dev/null +++ b/docs/errors/chain/TooManyUIDsPerMechanism.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyUIDsPerMechanism" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyUIDsPerMechanism`. diff --git a/docs/errors/chain/TooManyUnrevealedCommits.mdx b/docs/errors/chain/TooManyUnrevealedCommits.mdx new file mode 100644 index 0000000000..a3027a8ae5 --- /dev/null +++ b/docs/errors/chain/TooManyUnrevealedCommits.mdx @@ -0,0 +1,16 @@ +--- +title: "TooManyUnrevealedCommits" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TooManyUnrevealedCommits`. diff --git a/docs/errors/chain/TooSoon.mdx b/docs/errors/chain/TooSoon.mdx new file mode 100644 index 0000000000..6a2002946e --- /dev/null +++ b/docs/errors/chain/TooSoon.mdx @@ -0,0 +1,16 @@ +--- +title: "TooSoon" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change. + +Declared by the `Grandpa` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain TooSoon`. diff --git a/docs/errors/chain/TransactionMustComeFromEOA.mdx b/docs/errors/chain/TransactionMustComeFromEOA.mdx new file mode 100644 index 0000000000..693c68c459 --- /dev/null +++ b/docs/errors/chain/TransactionMustComeFromEOA.mdx @@ -0,0 +1,16 @@ +--- +title: "TransactionMustComeFromEOA" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead. + +Declared by the `EVM` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain TransactionMustComeFromEOA`. diff --git a/docs/errors/chain/TransactorAccountShouldBeHotKey.mdx b/docs/errors/chain/TransactorAccountShouldBeHotKey.mdx new file mode 100644 index 0000000000..3f0f575f6d --- /dev/null +++ b/docs/errors/chain/TransactorAccountShouldBeHotKey.mdx @@ -0,0 +1,16 @@ +--- +title: "TransactorAccountShouldBeHotKey" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain TransactorAccountShouldBeHotKey`. diff --git a/docs/errors/chain/TransferDisallowed.mdx b/docs/errors/chain/TransferDisallowed.mdx new file mode 100644 index 0000000000..7dc3b1bc15 --- /dev/null +++ b/docs/errors/chain/TransferDisallowed.mdx @@ -0,0 +1,16 @@ +--- +title: "TransferDisallowed" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain TransferDisallowed`. diff --git a/docs/errors/chain/TransferFailed.mdx b/docs/errors/chain/TransferFailed.mdx new file mode 100644 index 0000000000..e44a351eed --- /dev/null +++ b/docs/errors/chain/TransferFailed.mdx @@ -0,0 +1,16 @@ +--- +title: "TransferFailed" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain TransferFailed`. diff --git a/docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage.mdx b/docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage.mdx new file mode 100644 index 0000000000..b85c073e98 --- /dev/null +++ b/docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage.mdx @@ -0,0 +1,16 @@ +--- +title: "TrimmingWouldExceedMaxImmunePercentage" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain TrimmingWouldExceedMaxImmunePercentage`. diff --git a/docs/errors/chain/TxChildkeyTakeRateLimitExceeded.mdx b/docs/errors/chain/TxChildkeyTakeRateLimitExceeded.mdx new file mode 100644 index 0000000000..de9d9551f5 --- /dev/null +++ b/docs/errors/chain/TxChildkeyTakeRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "TxChildkeyTakeRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain TxChildkeyTakeRateLimitExceeded`. diff --git a/docs/errors/chain/TxRateLimitExceeded.mdx b/docs/errors/chain/TxRateLimitExceeded.mdx new file mode 100644 index 0000000000..74d91bbe94 --- /dev/null +++ b/docs/errors/chain/TxRateLimitExceeded.mdx @@ -0,0 +1,16 @@ +--- +title: "TxRateLimitExceeded" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`rate_limited`](/docs/errors/rate-limited). + +## Remediation + +Wait for the rate-limit window to pass, then retry + +The same explanation is available in the terminal: `btcli explain TxRateLimitExceeded`. diff --git a/docs/errors/chain/UidMapCouldNotBeCleared.mdx b/docs/errors/chain/UidMapCouldNotBeCleared.mdx new file mode 100644 index 0000000000..87d4169ada --- /dev/null +++ b/docs/errors/chain/UidMapCouldNotBeCleared.mdx @@ -0,0 +1,16 @@ +--- +title: "UidMapCouldNotBeCleared" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain UidMapCouldNotBeCleared`. diff --git a/docs/errors/chain/UidVecContainInvalidOne.mdx b/docs/errors/chain/UidVecContainInvalidOne.mdx new file mode 100644 index 0000000000..37492d7fe9 --- /dev/null +++ b/docs/errors/chain/UidVecContainInvalidOne.mdx @@ -0,0 +1,16 @@ +--- +title: "UidVecContainInvalidOne" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`). + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain UidVecContainInvalidOne`. diff --git a/docs/errors/chain/UidsLengthExceedUidsInSubNet.mdx b/docs/errors/chain/UidsLengthExceedUidsInSubNet.mdx new file mode 100644 index 0000000000..50dfbb6414 --- /dev/null +++ b/docs/errors/chain/UidsLengthExceedUidsInSubNet.mdx @@ -0,0 +1,16 @@ +--- +title: "UidsLengthExceedUidsInSubNet" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain UidsLengthExceedUidsInSubNet`. diff --git a/docs/errors/chain/UnableToRecoverPublicKey.mdx b/docs/errors/chain/UnableToRecoverPublicKey.mdx new file mode 100644 index 0000000000..be53050c28 --- /dev/null +++ b/docs/errors/chain/UnableToRecoverPublicKey.mdx @@ -0,0 +1,16 @@ +--- +title: "UnableToRecoverPublicKey" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain UnableToRecoverPublicKey`. diff --git a/docs/errors/chain/Unannounced.mdx b/docs/errors/chain/Unannounced.mdx new file mode 100644 index 0000000000..dde1ee9689 --- /dev/null +++ b/docs/errors/chain/Unannounced.mdx @@ -0,0 +1,16 @@ +--- +title: "Unannounced" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain Unannounced`. diff --git a/docs/errors/chain/Unauthorized.mdx b/docs/errors/chain/Unauthorized.mdx new file mode 100644 index 0000000000..bea4a8a5d0 --- /dev/null +++ b/docs/errors/chain/Unauthorized.mdx @@ -0,0 +1,16 @@ +--- +title: "Unauthorized" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`. + +Declared by the `System`, `LimitOrders` pallets; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain Unauthorized`. diff --git a/docs/errors/chain/Undefined.mdx b/docs/errors/chain/Undefined.mdx new file mode 100644 index 0000000000..4d413d9728 --- /dev/null +++ b/docs/errors/chain/Undefined.mdx @@ -0,0 +1,16 @@ +--- +title: "Undefined" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs. + +Declared by the `EVM` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain Undefined`. diff --git a/docs/errors/chain/Underflow.mdx b/docs/errors/chain/Underflow.mdx new file mode 100644 index 0000000000..f0ce65753d --- /dev/null +++ b/docs/errors/chain/Underflow.mdx @@ -0,0 +1,16 @@ +--- +title: "Underflow" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`. + +Declared by the `Crowdloan` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain Underflow`. diff --git a/docs/errors/chain/UnexpectedTimepoint.mdx b/docs/errors/chain/UnexpectedTimepoint.mdx new file mode 100644 index 0000000000..3fc5f58053 --- /dev/null +++ b/docs/errors/chain/UnexpectedTimepoint.mdx @@ -0,0 +1,16 @@ +--- +title: "UnexpectedTimepoint" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain UnexpectedTimepoint`. diff --git a/docs/errors/chain/UnexpectedUnreserveLeftover.mdx b/docs/errors/chain/UnexpectedUnreserveLeftover.mdx new file mode 100644 index 0000000000..153d775e3c --- /dev/null +++ b/docs/errors/chain/UnexpectedUnreserveLeftover.mdx @@ -0,0 +1,16 @@ +--- +title: "UnexpectedUnreserveLeftover" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`. + +Declared by the `Commitments` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain UnexpectedUnreserveLeftover`. diff --git a/docs/errors/chain/UnlockAmountTooHigh.mdx b/docs/errors/chain/UnlockAmountTooHigh.mdx new file mode 100644 index 0000000000..dae264d542 --- /dev/null +++ b/docs/errors/chain/UnlockAmountTooHigh.mdx @@ -0,0 +1,16 @@ +--- +title: "UnlockAmountTooHigh" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain UnlockAmountTooHigh`. diff --git a/docs/errors/chain/Unproxyable.mdx b/docs/errors/chain/Unproxyable.mdx new file mode 100644 index 0000000000..ef2ce4e305 --- /dev/null +++ b/docs/errors/chain/Unproxyable.mdx @@ -0,0 +1,16 @@ +--- +title: "Unproxyable" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call. + +Declared by the `Proxy` pallet; it classifies to the semantic code [`not_authorized`](/docs/errors/not-authorized). + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +The same explanation is available in the terminal: `btcli explain Unproxyable`. diff --git a/docs/errors/chain/Unreachable.mdx b/docs/errors/chain/Unreachable.mdx new file mode 100644 index 0000000000..2166b9885b --- /dev/null +++ b/docs/errors/chain/Unreachable.mdx @@ -0,0 +1,16 @@ +--- +title: "Unreachable" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring. + +Declared by the `MevShield` pallet; it classifies to the semantic code [`internal`](/docs/errors/internal). + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +The same explanation is available in the terminal: `btcli explain Unreachable`. diff --git a/docs/errors/chain/UnverifiedPulse.mdx b/docs/errors/chain/UnverifiedPulse.mdx new file mode 100644 index 0000000000..5d909b13c6 --- /dev/null +++ b/docs/errors/chain/UnverifiedPulse.mdx @@ -0,0 +1,16 @@ +--- +title: "UnverifiedPulse" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`. + +Declared by the `Drand` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain UnverifiedPulse`. diff --git a/docs/errors/chain/ValueNotInBounds.mdx b/docs/errors/chain/ValueNotInBounds.mdx new file mode 100644 index 0000000000..0113d968c1 --- /dev/null +++ b/docs/errors/chain/ValueNotInBounds.mdx @@ -0,0 +1,16 @@ +--- +title: "ValueNotInBounds" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds. + +Declared by the `AdminUtils` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ValueNotInBounds`. diff --git a/docs/errors/chain/ValueTooLarge.mdx b/docs/errors/chain/ValueTooLarge.mdx new file mode 100644 index 0000000000..aeb885de88 --- /dev/null +++ b/docs/errors/chain/ValueTooLarge.mdx @@ -0,0 +1,16 @@ +--- +title: "ValueTooLarge" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain ValueTooLarge`. diff --git a/docs/errors/chain/VestingBalance.mdx b/docs/errors/chain/VestingBalance.mdx new file mode 100644 index 0000000000..c86d19d585 --- /dev/null +++ b/docs/errors/chain/VestingBalance.mdx @@ -0,0 +1,16 @@ +--- +title: "VestingBalance" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs. + +Declared by the `Balances` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain VestingBalance`. diff --git a/docs/errors/chain/VotingPowerTrackingNotEnabled.mdx b/docs/errors/chain/VotingPowerTrackingNotEnabled.mdx new file mode 100644 index 0000000000..af3881418f --- /dev/null +++ b/docs/errors/chain/VotingPowerTrackingNotEnabled.mdx @@ -0,0 +1,16 @@ +--- +title: "VotingPowerTrackingNotEnabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`disabled`](/docs/errors/disabled). + +## Remediation + +This call or feature is switched off on this network + +The same explanation is available in the terminal: `btcli explain VotingPowerTrackingNotEnabled`. diff --git a/docs/errors/chain/WaitingForDissolvedSubnetCleanup.mdx b/docs/errors/chain/WaitingForDissolvedSubnetCleanup.mdx new file mode 100644 index 0000000000..cd468dedb1 --- /dev/null +++ b/docs/errors/chain/WaitingForDissolvedSubnetCleanup.mdx @@ -0,0 +1,16 @@ +--- +title: "WaitingForDissolvedSubnetCleanup" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`too_early`](/docs/errors/too-early). + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +The same explanation is available in the terminal: `btcli explain WaitingForDissolvedSubnetCleanup`. diff --git a/docs/errors/chain/WeightExceedsAbsoluteMax.mdx b/docs/errors/chain/WeightExceedsAbsoluteMax.mdx new file mode 100644 index 0000000000..16c15d0608 --- /dev/null +++ b/docs/errors/chain/WeightExceedsAbsoluteMax.mdx @@ -0,0 +1,16 @@ +--- +title: "WeightExceedsAbsoluteMax" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +`set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant. + +Declared by the `MevShield` pallet; it classifies to the semantic code [`limit_exceeded`](/docs/errors/limit-exceeded). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +The same explanation is available in the terminal: `btcli explain WeightExceedsAbsoluteMax`. diff --git a/docs/errors/chain/WeightVecLengthIsLow.mdx b/docs/errors/chain/WeightVecLengthIsLow.mdx new file mode 100644 index 0000000000..ddea68e598 --- /dev/null +++ b/docs/errors/chain/WeightVecLengthIsLow.mdx @@ -0,0 +1,16 @@ +--- +title: "WeightVecLengthIsLow" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain WeightVecLengthIsLow`. diff --git a/docs/errors/chain/WeightVecNotEqualSize.mdx b/docs/errors/chain/WeightVecNotEqualSize.mdx new file mode 100644 index 0000000000..91db639d38 --- /dev/null +++ b/docs/errors/chain/WeightVecNotEqualSize.mdx @@ -0,0 +1,16 @@ +--- +title: "WeightVecNotEqualSize" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain WeightVecNotEqualSize`. diff --git a/docs/errors/chain/WithdrawFailed.mdx b/docs/errors/chain/WithdrawFailed.mdx new file mode 100644 index 0000000000..64e71f9b81 --- /dev/null +++ b/docs/errors/chain/WithdrawFailed.mdx @@ -0,0 +1,16 @@ +--- +title: "WithdrawFailed" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance. + +Declared by the `EVM` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain WithdrawFailed`. diff --git a/docs/errors/chain/WrongTimepoint.mdx b/docs/errors/chain/WrongTimepoint.mdx new file mode 100644 index 0000000000..bdaf3acf82 --- /dev/null +++ b/docs/errors/chain/WrongTimepoint.mdx @@ -0,0 +1,16 @@ +--- +title: "WrongTimepoint" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint. + +Declared by the `Multisig` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain WrongTimepoint`. diff --git a/docs/errors/chain/XCMDecodeFailed.mdx b/docs/errors/chain/XCMDecodeFailed.mdx new file mode 100644 index 0000000000..333b39909b --- /dev/null +++ b/docs/errors/chain/XCMDecodeFailed.mdx @@ -0,0 +1,16 @@ +--- +title: "XCMDecodeFailed" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports. + +Declared by the `Contracts` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain XCMDecodeFailed`. diff --git a/docs/errors/chain/ZeroBalanceAfterWithdrawn.mdx b/docs/errors/chain/ZeroBalanceAfterWithdrawn.mdx new file mode 100644 index 0000000000..96f576c82c --- /dev/null +++ b/docs/errors/chain/ZeroBalanceAfterWithdrawn.mdx @@ -0,0 +1,16 @@ +--- +title: "ZeroBalanceAfterWithdrawn" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn. + +Declared by the `SubtensorModule` pallet; it classifies to the semantic code [`insufficient_balance`](/docs/errors/insufficient-balance). + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +The same explanation is available in the terminal: `btcli explain ZeroBalanceAfterWithdrawn`. diff --git a/docs/errors/chain/ZeroShareInBatch.mdx b/docs/errors/chain/ZeroShareInBatch.mdx new file mode 100644 index 0000000000..63a488b474 --- /dev/null +++ b/docs/errors/chain/ZeroShareInBatch.mdx @@ -0,0 +1,16 @@ +--- +title: "ZeroShareInBatch" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch. + +Declared by the `LimitOrders` pallet; it classifies to the semantic code [`invalid_argument`](/docs/errors/invalid-argument). + +## Remediation + +Check the argument values against the operation schema + +The same explanation is available in the terminal: `btcli explain ZeroShareInBatch`. diff --git a/docs/errors/chain/index.mdx b/docs/errors/chain/index.mdx new file mode 100644 index 0000000000..154f3efb9e --- /dev/null +++ b/docs/errors/chain/index.mdx @@ -0,0 +1,364 @@ +--- +title: "Chain errors" +description: "Every exact chain error name, classified to a semantic code." +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The exact chain error name (from the extrinsic receipt) maps to a semantic [code](/docs/errors); the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Code | Description | +| --- | --- | --- | +| [`AccountNotAllowedCommit`](/docs/errors/chain/AccountNotAllowedCommit) | [`not_authorized`](/docs/errors/not-authorized) | Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet. | +| [`AccountRejectsLockedAlpha`](/docs/errors/chain/AccountRejectsLockedAlpha) | [`invalid_argument`](/docs/errors/invalid-argument) | Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying. | +| [`ActiveLockExists`](/docs/errors/chain/ActiveLockExists) | [`already_exists`](/docs/errors/already-exists) | The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first. | +| [`ActivityCutoffFactorMilliOutOfBounds`](/docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds) | [`invalid_argument`](/docs/errors/invalid-argument) | The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting. | +| [`ActivityCutoffTooLow`](/docs/errors/chain/ActivityCutoffTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `. | +| [`AddStakeBurnRateLimitExceeded`](/docs/errors/chain/AddStakeBurnRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes. | +| [`AdminActionProhibitedDuringWeightsWindow`](/docs/errors/chain/AdminActionProhibitedDuringWeightsWindow) | [`too_early`](/docs/errors/too-early) | An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires. | +| [`AllNetworksInImmunity`](/docs/errors/chain/AllNetworksInImmunity) | [`too_early`](/docs/errors/too-early) | Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity. | +| [`AlphaHighTooLow`](/docs/errors/chain/AlphaHighTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid. | +| [`AlphaLowOutOfRange`](/docs/errors/chain/AlphaLowOutOfRange) | [`invalid_argument`](/docs/errors/invalid-argument) | The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid. | +| [`AlreadyApproved`](/docs/errors/chain/AlreadyApproved) | [`already_exists`](/docs/errors/already-exists) | The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list. | +| [`AlreadyDeposited`](/docs/errors/chain/AlreadyDeposited) | [`already_exists`](/docs/errors/already-exists) | The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason. | +| [`AlreadyFinalized`](/docs/errors/chain/AlreadyFinalized) | [`already_exists`](/docs/errors/already-exists) | The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`. | +| [`AlreadyFinalizing`](/docs/errors/chain/AlreadyFinalizing) | [`already_exists`](/docs/errors/already-exists) | A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying. | +| [`AlreadyNoted`](/docs/errors/chain/AlreadyNoted) | [`already_exists`](/docs/errors/already-exists) | The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again. | +| [`AlreadyStored`](/docs/errors/chain/AlreadyStored) | [`already_exists`](/docs/errors/already-exists) | The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again. | +| [`AmountTooLow`](/docs/errors/chain/AmountTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount. | +| [`AnnouncedColdkeyHashDoesNotMatch`](/docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch) | [`invalid_argument`](/docs/errors/invalid-argument) | The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to. | +| [`AnnouncementDepositInvariantViolated`](/docs/errors/chain/AnnouncementDepositInvariantViolated) | [`internal`](/docs/errors/internal) | Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input. | +| [`ArithmeticOverflow`](/docs/errors/chain/ArithmeticOverflow) | [`internal`](/docs/errors/internal) | Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts. | +| [`AutoEpochAlreadyImminent`](/docs/errors/chain/AutoEpochAlreadyImminent) | [`already_exists`](/docs/errors/already-exists) | `trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire. | +| [`BadEncKeyLen`](/docs/errors/chain/BadEncKeyLen) | [`invalid_argument`](/docs/errors/invalid-argument) | The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing. | +| [`BalanceLow`](/docs/errors/chain/BalanceLow) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price. | +| [`BalanceWithdrawalError`](/docs/errors/chain/BalanceWithdrawalError) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up. | +| [`BeneficiaryDoesNotOwnHotkey`](/docs/errors/chain/BeneficiaryDoesNotOwnHotkey) | [`not_authorized`](/docs/errors/not-authorized) | When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns. | +| [`BlockDurationTooLong`](/docs/errors/chain/BlockDurationTooLong) | [`invalid_argument`](/docs/errors/invalid-argument) | The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`. | +| [`BlockDurationTooShort`](/docs/errors/chain/BlockDurationTooShort) | [`invalid_argument`](/docs/errors/invalid-argument) | The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`. | +| [`BondsMovingAverageMaxReached`](/docs/errors/chain/BondsMovingAverageMaxReached) | [`limit_exceeded`](/docs/errors/limit-exceeded) | A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root. | +| [`CallDisabled`](/docs/errors/chain/CallDisabled) | [`disabled`](/docs/errors/disabled) | The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version. | +| [`CallFiltered`](/docs/errors/chain/CallFiltered) | [`not_authorized`](/docs/errors/not-authorized) | The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect. | +| [`CallUnavailable`](/docs/errors/chain/CallUnavailable) | [`not_found`](/docs/errors/not-found) | During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet. | +| [`CanNotSetRootNetworkWeights`](/docs/errors/chain/CanNotSetRootNetworkWeights) | [`invalid_argument`](/docs/errors/invalid-argument) | `set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism. | +| [`CannotAddSelfAsDelegateDependency`](/docs/errors/chain/CannotAddSelfAsDelegateDependency) | [`invalid_argument`](/docs/errors/invalid-argument) | A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash. | +| [`CannotAffordLockCost`](/docs/errors/chain/CannotAffordLockCost) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet. | +| [`CannotBurnOrRecycleOnRootSubnet`](/docs/errors/chain/CannotBurnOrRecycleOnRootSubnet) | [`invalid_argument`](/docs/errors/invalid-argument) | `recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn. | +| [`CannotEndInPast`](/docs/errors/chain/CannotEndInPast) | [`invalid_argument`](/docs/errors/invalid-argument) | The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater. | +| [`CannotReleaseYet`](/docs/errors/chain/CannotReleaseYet) | [`too_early`](/docs/errors/too-early) | `release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config. | +| [`CannotUseSystemAccount`](/docs/errors/chain/CannotUseSystemAccount) | [`not_authorized`](/docs/errors/not-authorized) | The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`. | +| [`CapNotRaised`](/docs/errors/chain/CapNotRaised) | [`too_early`](/docs/errors/too-early) | `finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing. | +| [`CapRaised`](/docs/errors/chain/CapRaised) | [`limit_exceeded`](/docs/errors/limit-exceeded) | A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`. | +| [`CapTooLow`](/docs/errors/chain/CapTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry. | +| [`ChainIdMismatch`](/docs/errors/chain/ChainIdMismatch) | [`invalid_argument`](/docs/errors/invalid-argument) | The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed. | +| [`ChangePending`](/docs/errors/chain/ChangePending) | [`already_exists`](/docs/errors/already-exists) | A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first. | +| [`ChildParentInconsistency`](/docs/errors/chain/ChildParentInconsistency) | [`invalid_argument`](/docs/errors/invalid-argument) | A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap. | +| [`CodeInUse`](/docs/errors/chain/CodeInUse) | [`invalid_argument`](/docs/errors/invalid-argument) | `remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal. | +| [`CodeInfoNotFound`](/docs/errors/chain/CodeInfoNotFound) | [`not_found`](/docs/errors/not-found) | No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed. | +| [`CodeNotFound`](/docs/errors/chain/CodeNotFound) | [`not_found`](/docs/errors/not-found) | No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed. | +| [`CodeRejected`](/docs/errors/chain/CodeRejected) | [`invalid_argument`](/docs/errors/invalid-argument) | The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason. | +| [`CodeTooLarge`](/docs/errors/chain/CodeTooLarge) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract. | +| [`ColdKeyAlreadyAssociated`](/docs/errors/chain/ColdKeyAlreadyAssociated) | [`already_exists`](/docs/errors/already-exists) | The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead. | +| [`ColdkeySwapAlreadyDisputed`](/docs/errors/chain/ColdkeySwapAlreadyDisputed) | [`already_exists`](/docs/errors/already-exists) | `dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed. | +| [`ColdkeySwapAnnounced`](/docs/errors/chain/ColdkeySwapAnnounced) | [`already_exists`](/docs/errors/already-exists) | The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement. | +| [`ColdkeySwapAnnouncementNotFound`](/docs/errors/chain/ColdkeySwapAnnouncementNotFound) | [`not_found`](/docs/errors/not-found) | `coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first. | +| [`ColdkeySwapClearTooEarly`](/docs/errors/chain/ColdkeySwapClearTooEarly) | [`too_early`](/docs/errors/too-early) | The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later. | +| [`ColdkeySwapDisputed`](/docs/errors/chain/ColdkeySwapDisputed) | [`not_authorized`](/docs/errors/not-authorized) | All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact. | +| [`ColdkeySwapReannouncedTooEarly`](/docs/errors/chain/ColdkeySwapReannouncedTooEarly) | [`too_early`](/docs/errors/too-early) | `announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later. | +| [`ColdkeySwapTooEarly`](/docs/errors/chain/ColdkeySwapTooEarly) | [`too_early`](/docs/errors/too-early) | `coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then. | +| [`CommitRevealDisabled`](/docs/errors/chain/CommitRevealDisabled) | [`disabled`](/docs/errors/disabled) | A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled. | +| [`CommitRevealEnabled`](/docs/errors/chain/CommitRevealEnabled) | [`disabled`](/docs/errors/disabled) | Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`. | +| [`CommittingWeightsTooFast`](/docs/errors/chain/CommittingWeightsTooFast) | [`rate_limited`](/docs/errors/rate-limited) | The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait. | +| [`ContractNotFound`](/docs/errors/chain/ContractNotFound) | [`not_found`](/docs/errors/not-found) | No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated. | +| [`ContractReverted`](/docs/errors/chain/ContractReverted) | [`internal`](/docs/errors/internal) | The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value. | +| [`ContractTrapped`](/docs/errors/chain/ContractTrapped) | [`internal`](/docs/errors/internal) | The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations. | +| [`ContributionPeriodEnded`](/docs/errors/chain/ContributionPeriodEnded) | [`expired`](/docs/errors/expired) | A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized. | +| [`ContributionPeriodNotEnded`](/docs/errors/chain/ContributionPeriodNotEnded) | [`too_early`](/docs/errors/too-early) | The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number. | +| [`ContributionTooLow`](/docs/errors/chain/ContributionTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount. | +| [`CreateOriginNotAllowed`](/docs/errors/chain/CreateOriginNotAllowed) | [`not_authorized`](/docs/errors/not-authorized) | A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list. | +| [`CurrencyError`](/docs/errors/chain/CurrencyError) | [`internal`](/docs/errors/internal) | A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason. | +| [`DeadAccount`](/docs/errors/chain/DeadAccount) | [`not_found`](/docs/errors/not-found) | The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs. | +| [`DecodingFailed`](/docs/errors/chain/DecodingFailed) | [`invalid_argument`](/docs/errors/invalid-argument) | Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API. | +| [`DelegateDependencyAlreadyExists`](/docs/errors/chain/DelegateDependencyAlreadyExists) | [`already_exists`](/docs/errors/already-exists) | The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it. | +| [`DelegateDependencyNotFound`](/docs/errors/chain/DelegateDependencyNotFound) | [`not_found`](/docs/errors/not-found) | `unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info. | +| [`DelegateTakeTooHigh`](/docs/errors/chain/DelegateTakeTooHigh) | [`invalid_argument`](/docs/errors/invalid-argument) | The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it. | +| [`DelegateTakeTooLow`](/docs/errors/chain/DelegateTakeTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item. | +| [`DelegateTxRateLimitExceeded`](/docs/errors/chain/DelegateTxRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later. | +| [`DeltaZero`](/docs/errors/chain/DeltaZero) | [`invalid_argument`](/docs/errors/invalid-argument) | The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount. | +| [`DepositCannotBeWithdrawn`](/docs/errors/chain/DepositCannotBeWithdrawn) | [`invalid_argument`](/docs/errors/invalid-argument) | The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry. | +| [`DepositTooLow`](/docs/errors/chain/DepositTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit. | +| [`Deprecated`](/docs/errors/chain/Deprecated) | [`disabled`](/docs/errors/disabled) | The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`). | +| [`DisabledTemporarily`](/docs/errors/chain/DisabledTemporarily) | [`disabled`](/docs/errors/disabled) | The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled. | +| [`DrandConnectionFailure`](/docs/errors/chain/DrandConnectionFailure) | [`internal`](/docs/errors/internal) | Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints. | +| [`Duplicate`](/docs/errors/chain/Duplicate) | [`already_exists`](/docs/errors/already-exists) | This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple. | +| [`DuplicateChild`](/docs/errors/chain/DuplicateChild) | [`invalid_argument`](/docs/errors/invalid-argument) | The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid. | +| [`DuplicateContract`](/docs/errors/chain/DuplicateContract) | [`already_exists`](/docs/errors/already-exists) | Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address. | +| [`DuplicateOffenceReport`](/docs/errors/chain/DuplicateOffenceReport) | [`already_exists`](/docs/errors/already-exists) | The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again. | +| [`DuplicateOrderInBatch`](/docs/errors/chain/DuplicateOrderInBatch) | [`invalid_argument`](/docs/errors/invalid-argument) | Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`. | +| [`DuplicateUids`](/docs/errors/chain/DuplicateUids) | [`invalid_argument`](/docs/errors/invalid-argument) | The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector. | +| [`DynamicTempoBlockedByCommitReveal`](/docs/errors/chain/DynamicTempoBlockedByCommitReveal) | [`disabled`](/docs/errors/disabled) | `trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs. | +| [`Entered`](/docs/errors/chain/Entered) | [`already_exists`](/docs/errors/already-exists) | Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages. | +| [`EpochTriggerAlreadyPending`](/docs/errors/chain/EpochTriggerAlreadyPending) | [`already_exists`](/docs/errors/already-exists) | `trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again. | +| [`EvmKeyAssociateRateLimitExceeded`](/docs/errors/chain/EvmKeyAssociateRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | `associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later. | +| [`EvmKeyAssociationLimitExceeded`](/docs/errors/chain/EvmKeyAssociationLimitExceeded) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address. | +| [`ExistentialDeposit`](/docs/errors/chain/ExistentialDeposit) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant. | +| [`ExistingVestingSchedule`](/docs/errors/chain/ExistingVestingSchedule) | [`already_exists`](/docs/errors/already-exists) | A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule. | +| [`Exited`](/docs/errors/chain/Exited) | [`already_exists`](/docs/errors/already-exists) | Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting. | +| [`ExpectedBeneficiaryOrigin`](/docs/errors/chain/ExpectedBeneficiaryOrigin) | [`not_authorized`](/docs/errors/not-authorized) | A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey. | +| [`Expendability`](/docs/errors/chain/Expendability) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable. | +| [`ExpiredWeightCommit`](/docs/errors/chain/ExpiredWeightCommit) | [`expired`](/docs/errors/expired) | The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time. | +| [`FailedToExtractRuntimeVersion`](/docs/errors/chain/FailedToExtractRuntimeVersion) | [`invalid_argument`](/docs/errors/invalid-argument) | The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly. | +| [`FailedToSchedule`](/docs/errors/chain/FailedToSchedule) | [`internal`](/docs/errors/internal) | The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated. | +| [`FaucetDisabled`](/docs/errors/chain/FaucetDisabled) | [`disabled`](/docs/errors/disabled) | The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead. | +| [`FeeOverflow`](/docs/errors/chain/FeeOverflow) | [`internal`](/docs/errors/internal) | Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction. | +| [`FeeRateTooHigh`](/docs/errors/chain/FeeRateTooHigh) | [`invalid_argument`](/docs/errors/invalid-argument) | `set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting. | +| [`FirstEmissionBlockNumberAlreadySet`](/docs/errors/chain/FirstEmissionBlockNumberAlreadySet) | [`already_exists`](/docs/errors/already-exists) | `start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed. | +| [`GasLimitTooHigh`](/docs/errors/chain/GasLimitTooHigh) | [`invalid_argument`](/docs/errors/invalid-argument) | The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. | +| [`GasLimitTooLow`](/docs/errors/chain/GasLimitTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. | +| [`GasPriceTooLow`](/docs/errors/chain/GasPriceTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. | +| [`HotKeyAccountNotExists`](/docs/errors/chain/HotKeyAccountNotExists) | [`not_registered`](/docs/errors/not-registered) | The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first. | +| [`HotKeyAlreadyDelegate`](/docs/errors/chain/HotKeyAlreadyDelegate) | [`already_exists`](/docs/errors/already-exists) | `become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed. | +| [`HotKeyAlreadyRegisteredInSubNet`](/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet) | [`already_exists`](/docs/errors/already-exists) | A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid. | +| [`HotKeyNotRegisteredInNetwork`](/docs/errors/chain/HotKeyNotRegisteredInNetwork) | [`not_registered`](/docs/errors/not-registered) | The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first. | +| [`HotKeyNotRegisteredInSubNet`](/docs/errors/chain/HotKeyNotRegisteredInSubNet) | [`not_registered`](/docs/errors/not-registered) | The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed. | +| [`HotKeySetTxRateLimitExceeded`](/docs/errors/chain/HotKeySetTxRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks. | +| [`HotKeySwapOnSubnetIntervalNotPassed`](/docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed) | [`rate_limited`](/docs/errors/rate-limited) | A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval. | +| [`IncorrectCommitRevealVersion`](/docs/errors/chain/IncorrectCommitRevealVersion) | [`invalid_argument`](/docs/errors/invalid-argument) | The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version. | +| [`IncorrectPartialFillAmount`](/docs/errors/chain/IncorrectPartialFillAmount) | [`invalid_argument`](/docs/errors/invalid-argument) | The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`. | +| [`IncorrectWeightVersionKey`](/docs/errors/chain/IncorrectWeightVersionKey) | [`invalid_argument`](/docs/errors/invalid-argument) | The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key. | +| [`Indeterministic`](/docs/errors/chain/Indeterministic) | [`invalid_argument`](/docs/errors/invalid-argument) | Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically. | +| [`InputForwarded`](/docs/errors/chain/InputForwarded) | [`invalid_argument`](/docs/errors/invalid-argument) | The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards. | +| [`InputLengthsUnequal`](/docs/errors/chain/InputLengthsUnequal) | [`invalid_argument`](/docs/errors/invalid-argument) | A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length. | +| [`InsufficientBalance`](/docs/errors/chain/InsufficientBalance) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved. | +| [`InsufficientInputAmount`](/docs/errors/chain/InsufficientInputAmount) | [`invalid_argument`](/docs/errors/invalid-argument) | Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output. | +| [`InsufficientLiquidity`](/docs/errors/chain/InsufficientLiquidity) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount. | +| [`InsufficientStakeForLock`](/docs/errors/chain/InsufficientStakeForLock) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first. | +| [`InvalidCallFlags`](/docs/errors/chain/InvalidCallFlags) | [`invalid_argument`](/docs/errors/invalid-argument) | The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values. | +| [`InvalidChainId`](/docs/errors/chain/InvalidChainId) | [`invalid_argument`](/docs/errors/invalid-argument) | The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction. | +| [`InvalidChild`](/docs/errors/chain/InvalidChild) | [`invalid_argument`](/docs/errors/invalid-argument) | The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved. | +| [`InvalidChildkeyTake`](/docs/errors/chain/InvalidChildkeyTake) | [`invalid_argument`](/docs/errors/invalid-argument) | The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds. | +| [`InvalidCrowdloanId`](/docs/errors/chain/InvalidCrowdloanId) | [`not_found`](/docs/errors/not-found) | No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued. | +| [`InvalidDerivedAccount`](/docs/errors/chain/InvalidDerivedAccount) | [`invalid_argument`](/docs/errors/invalid-argument) | Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation. | +| [`InvalidDerivedAccountId`](/docs/errors/chain/InvalidDerivedAccountId) | [`invalid_argument`](/docs/errors/invalid-argument) | Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one). | +| [`InvalidDifficulty`](/docs/errors/chain/InvalidDifficulty) | [`invalid_argument`](/docs/errors/invalid-argument) | The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block. | +| [`InvalidEquivocationProof`](/docs/errors/chain/InvalidEquivocationProof) | [`invalid_argument`](/docs/errors/invalid-argument) | The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set. | +| [`InvalidFinalizationConfig`](/docs/errors/chain/InvalidFinalizationConfig) | [`invalid_argument`](/docs/errors/invalid-argument) | Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry. | +| [`InvalidIdentity`](/docs/errors/chain/InvalidIdentity) | [`invalid_argument`](/docs/errors/invalid-argument) | The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity. | +| [`InvalidIpAddress`](/docs/errors/chain/InvalidIpAddress) | [`invalid_argument`](/docs/errors/invalid-argument) | The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed. | +| [`InvalidIpType`](/docs/errors/chain/InvalidIpType) | [`invalid_argument`](/docs/errors/invalid-argument) | The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted. | +| [`InvalidKeyOwnershipProof`](/docs/errors/chain/InvalidKeyOwnershipProof) | [`invalid_argument`](/docs/errors/invalid-argument) | The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report. | +| [`InvalidLeaseBeneficiary`](/docs/errors/chain/InvalidLeaseBeneficiary) | [`invalid_argument`](/docs/errors/invalid-argument) | The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey. | +| [`InvalidLiquidityValue`](/docs/errors/chain/InvalidLiquidityValue) | [`invalid_argument`](/docs/errors/invalid-argument) | Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`. | +| [`InvalidNonce`](/docs/errors/chain/InvalidNonce) | [`invalid_argument`](/docs/errors/invalid-argument) | The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`. | +| [`InvalidNumRootClaim`](/docs/errors/chain/InvalidNumRootClaim) | [`invalid_argument`](/docs/errors/invalid-argument) | The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number. | +| [`InvalidOrigin`](/docs/errors/chain/InvalidOrigin) | [`not_authorized`](/docs/errors/not-authorized) | The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`. | +| [`InvalidPort`](/docs/errors/chain/InvalidPort) | [`invalid_argument`](/docs/errors/invalid-argument) | The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port. | +| [`InvalidRecoveredPublicKey`](/docs/errors/chain/InvalidRecoveredPublicKey) | [`invalid_argument`](/docs/errors/invalid-argument) | The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format). | +| [`InvalidRevealCommitHashNotMatch`](/docs/errors/chain/InvalidRevealCommitHashNotMatch) | [`invalid_argument`](/docs/errors/invalid-argument) | The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid. | +| [`InvalidRevealRound`](/docs/errors/chain/InvalidRevealRound) | [`expired`](/docs/errors/expired) | A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number. | +| [`InvalidRootClaimThreshold`](/docs/errors/chain/InvalidRootClaimThreshold) | [`invalid_argument`](/docs/errors/invalid-argument) | The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid. | +| [`InvalidRoundNumber`](/docs/errors/chain/InvalidRoundNumber) | [`invalid_argument`](/docs/errors/invalid-argument) | A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`. | +| [`InvalidSchedule`](/docs/errors/chain/InvalidSchedule) | [`invalid_argument`](/docs/errors/invalid-argument) | The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments. | +| [`InvalidSeal`](/docs/errors/chain/InvalidSeal) | [`invalid_argument`](/docs/errors/invalid-argument) | The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit. | +| [`InvalidSignature`](/docs/errors/chain/InvalidSignature) | [`invalid_argument`](/docs/errors/invalid-argument) | Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed. | +| [`InvalidSpecName`](/docs/errors/chain/InvalidSpecName) | [`invalid_argument`](/docs/errors/invalid-argument) | The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one. | +| [`InvalidSubnetNumber`](/docs/errors/chain/InvalidSubnetNumber) | [`invalid_argument`](/docs/errors/invalid-argument) | A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit. | +| [`InvalidTickRange`](/docs/errors/chain/InvalidTickRange) | [`invalid_argument`](/docs/errors/invalid-argument) | Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones. | +| [`InvalidValue`](/docs/errors/chain/InvalidValue) | [`invalid_argument`](/docs/errors/invalid-argument) | A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`). | +| [`InvalidVotingPowerEmaAlpha`](/docs/errors/chain/InvalidVotingPowerEmaAlpha) | [`invalid_argument`](/docs/errors/invalid-argument) | The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid. | +| [`InvalidWorkBlock`](/docs/errors/chain/InvalidWorkBlock) | [`invalid_argument`](/docs/errors/invalid-argument) | The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block. | +| [`IssuanceDeactivated`](/docs/errors/chain/IssuanceDeactivated) | [`disabled`](/docs/errors/disabled) | Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again. | +| [`LeaseCannotEndInThePast`](/docs/errors/chain/LeaseCannotEndInThePast) | [`invalid_argument`](/docs/errors/invalid-argument) | The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease. | +| [`LeaseDoesNotExist`](/docs/errors/chain/LeaseDoesNotExist) | [`not_found`](/docs/errors/not-found) | The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated. | +| [`LeaseHasNoEndBlock`](/docs/errors/chain/LeaseHasNoEndBlock) | [`invalid_argument`](/docs/errors/invalid-argument) | The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id. | +| [`LeaseHasNotEnded`](/docs/errors/chain/LeaseHasNotEnded) | [`too_early`](/docs/errors/too-early) | The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes. | +| [`LeaseNetuidNotFound`](/docs/errors/chain/LeaseNetuidNotFound) | [`not_found`](/docs/errors/not-found) | After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete. | +| [`LimitOrdersDisabled`](/docs/errors/chain/LimitOrdersDisabled) | [`disabled`](/docs/errors/disabled) | Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet. | +| [`LiquidAlphaDisabled`](/docs/errors/chain/LiquidAlphaDisabled) | [`disabled`](/docs/errors/disabled) | Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first. | +| [`LiquidityRestrictions`](/docs/errors/chain/LiquidityRestrictions) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal. | +| [`LockHotkeyMismatch`](/docs/errors/chain/LockHotkeyMismatch) | [`invalid_argument`](/docs/errors/invalid-argument) | The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first. | +| [`LockIdOverFlow`](/docs/errors/chain/LockIdOverFlow) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem. | +| [`MaxAllowedUIdsLessThanCurrentUIds`](/docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds) | [`invalid_argument`](/docs/errors/invalid-argument) | `sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid. | +| [`MaxAllowedUidsGreaterThanDefaultMaxAllowedUids`](/docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids) | [`invalid_argument`](/docs/errors/invalid-argument) | `sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value. | +| [`MaxAllowedUidsLessThanMinAllowedUids`](/docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids) | [`invalid_argument`](/docs/errors/invalid-argument) | `sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid. | +| [`MaxCallDepthReached`](/docs/errors/chain/MaxCallDepthReached) | [`limit_exceeded`](/docs/errors/limit-exceeded) | A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth. | +| [`MaxContributionReached`](/docs/errors/chain/MaxContributionReached) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`. | +| [`MaxContributorsReached`](/docs/errors/chain/MaxContributorsReached) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant. | +| [`MaxDelegateDependenciesReached`](/docs/errors/chain/MaxDelegateDependenciesReached) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first. | +| [`MaxValidatorsLargerThanMaxUIds`](/docs/errors/chain/MaxValidatorsLargerThanMaxUIds) | [`invalid_argument`](/docs/errors/invalid-argument) | `sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid. | +| [`MaxWeightExceeded`](/docs/errors/chain/MaxWeightExceeded) | [`limit_exceeded`](/docs/errors/limit-exceeded) | After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting. | +| [`MaxWeightTooLow`](/docs/errors/chain/MaxWeightTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`. | +| [`MaximumContributionTooLow`](/docs/errors/chain/MaximumContributionTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry. | +| [`MechanismDoesNotExist`](/docs/errors/chain/MechanismDoesNotExist) | [`subnet_not_exists`](/docs/errors/subnet-not-exists) | The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet. | +| [`MigrationInProgress`](/docs/errors/chain/MigrationInProgress) | [`too_early`](/docs/errors/too-early) | A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it. | +| [`MinAllowedUidsGreaterThanCurrentUids`](/docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids) | [`invalid_argument`](/docs/errors/invalid-argument) | `sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid. | +| [`MinAllowedUidsGreaterThanMaxAllowedUids`](/docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids) | [`invalid_argument`](/docs/errors/invalid-argument) | `sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid. | +| [`MinimumContributionTooHigh`](/docs/errors/chain/MinimumContributionTooHigh) | [`invalid_argument`](/docs/errors/invalid-argument) | The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`. | +| [`MinimumContributionTooLow`](/docs/errors/chain/MinimumContributionTooLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value. | +| [`MinimumThreshold`](/docs/errors/chain/MinimumThreshold) | [`invalid_argument`](/docs/errors/invalid-argument) | The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case. | +| [`MultiBlockMigrationsOngoing`](/docs/errors/chain/MultiBlockMigrationsOngoing) | [`too_early`](/docs/errors/too-early) | Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade. | +| [`Named`](/docs/errors/chain/Named) | [`invalid_argument`](/docs/errors/invalid-argument) | An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map. | +| [`NeedWaitingMoreBlocksToStarCall`](/docs/errors/chain/NeedWaitingMoreBlocksToStarCall) | [`too_early`](/docs/errors/too-early) | The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens. | +| [`NegativeSigmoidSteepness`](/docs/errors/chain/NegativeSigmoidSteepness) | [`invalid_argument`](/docs/errors/invalid-argument) | A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root. | +| [`NetworkDissolveAlreadyQueued`](/docs/errors/chain/NetworkDissolveAlreadyQueued) | [`already_exists`](/docs/errors/already-exists) | The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request. | +| [`NetworkTxRateLimitExceeded`](/docs/errors/chain/NetworkTxRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks. | +| [`NeuronNoValidatorPermit`](/docs/errors/chain/NeuronNoValidatorPermit) | [`not_authorized`](/docs/errors/not-authorized) | The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator. | +| [`NewColdKeyIsHotkey`](/docs/errors/chain/NewColdKeyIsHotkey) | [`invalid_argument`](/docs/errors/invalid-argument) | The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey. | +| [`NewHotKeyIsSameWithOld`](/docs/errors/chain/NewHotKeyIsSameWithOld) | [`invalid_argument`](/docs/errors/invalid-argument) | swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey. | +| [`NewHotKeyNotCleanForRootSwap`](/docs/errors/chain/NewHotKeyNotCleanForRootSwap) | [`invalid_argument`](/docs/errors/invalid-argument) | The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey. | +| [`NoApprovalsNeeded`](/docs/errors/chain/NoApprovalsNeeded) | [`invalid_argument`](/docs/errors/invalid-argument) | The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it. | +| [`NoChainExtension`](/docs/errors/chain/NoChainExtension) | [`disabled`](/docs/errors/disabled) | The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against. | +| [`NoContribution`](/docs/errors/chain/NoContribution) | [`not_found`](/docs/errors/not-found) | The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question. | +| [`NoDeposit`](/docs/errors/chain/NoDeposit) | [`not_found`](/docs/errors/not-found) | No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block. | +| [`NoExistingLock`](/docs/errors/chain/NoExistingLock) | [`not_found`](/docs/errors/not-found) | move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey. | +| [`NoMigrationPerformed`](/docs/errors/chain/NoMigrationPerformed) | [`invalid_argument`](/docs/errors/invalid-argument) | A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument. | +| [`NoNeuronIdAvailable`](/docs/errors/chain/NoNeuronIdAvailable) | [`limit_exceeded`](/docs/errors/limit-exceeded) | Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire. | +| [`NoPermission`](/docs/errors/chain/NoPermission) | [`not_authorized`](/docs/errors/not-authorized) | The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments. | +| [`NoSelfProxy`](/docs/errors/chain/NoSelfProxy) | [`invalid_argument`](/docs/errors/invalid-argument) | An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account. | +| [`NoTimepoint`](/docs/errors/chain/NoTimepoint) | [`invalid_argument`](/docs/errors/invalid-argument) | No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`. | +| [`NoWeightsCommitFound`](/docs/errors/chain/NoWeightsCommitFound) | [`not_found`](/docs/errors/not-found) | A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window. | +| [`NonAssociatedColdKey`](/docs/errors/chain/NonAssociatedColdKey) | [`not_authorized`](/docs/errors/not-authorized) | The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it. | +| [`NonDefaultComposite`](/docs/errors/chain/NonDefaultComposite) | [`invalid_argument`](/docs/errors/invalid-argument) | The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way. | +| [`NonZeroRefCount`](/docs/errors/chain/NonZeroRefCount) | [`invalid_argument`](/docs/errors/invalid-argument) | The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first. | +| [`NoneValue`](/docs/errors/chain/NoneValue) | [`not_found`](/docs/errors/not-found) | Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization. | +| [`NotAllowed`](/docs/errors/chain/NotAllowed) | [`not_authorized`](/docs/errors/not-authorized) | Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value. | +| [`NotAuthorized`](/docs/errors/chain/NotAuthorized) | [`not_authorized`](/docs/errors/not-authorized) | The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`. | +| [`NotConfigured`](/docs/errors/chain/NotConfigured) | [`disabled`](/docs/errors/disabled) | The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants. | +| [`NotEnoughAlphaOutToRecycle`](/docs/errors/chain/NotEnoughAlphaOutToRecycle) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount. | +| [`NotEnoughBalanceToPaySwapColdKey`](/docs/errors/chain/NotEnoughBalanceToPaySwapColdKey) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap. | +| [`NotEnoughBalanceToPaySwapHotKey`](/docs/errors/chain/NotEnoughBalanceToPaySwapHotKey) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying. | +| [`NotEnoughBalanceToStake`](/docs/errors/chain/NotEnoughBalanceToStake) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid). | +| [`NotEnoughStake`](/docs/errors/chain/NotEnoughStake) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs. | +| [`NotEnoughStakeToSetChildkeys`](/docs/errors/chain/NotEnoughStakeToSetChildkeys) | [`insufficient_balance`](/docs/errors/insufficient-balance) | Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value. | +| [`NotEnoughStakeToSetWeights`](/docs/errors/chain/NotEnoughStakeToSetWeights) | [`insufficient_balance`](/docs/errors/insufficient-balance) | Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`. | +| [`NotEnoughStakeToWithdraw`](/docs/errors/chain/NotEnoughStakeToWithdraw) | [`insufficient_balance`](/docs/errors/insufficient-balance) | An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage). | +| [`NotFound`](/docs/errors/chain/NotFound) | [`not_found`](/docs/errors/not-found) | The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state. | +| [`NotNoted`](/docs/errors/chain/NotNoted) | [`not_found`](/docs/errors/not-found) | The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored. | +| [`NotOwner`](/docs/errors/chain/NotOwner) | [`not_authorized`](/docs/errors/not-authorized) | Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash. | +| [`NotPermittedOnRootSubnet`](/docs/errors/chain/NotPermittedOnRootSubnet) | [`invalid_argument`](/docs/errors/invalid-argument) | An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0. | +| [`NotProxy`](/docs/errors/chain/NotProxy) | [`not_authorized`](/docs/errors/not-authorized) | The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call. | +| [`NotReadyToDissolve`](/docs/errors/chain/NotReadyToDissolve) | [`too_early`](/docs/errors/too-early) | `dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record. | +| [`NotRequested`](/docs/errors/chain/NotRequested) | [`not_found`](/docs/errors/not-found) | The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`. | +| [`NotRootSubnet`](/docs/errors/chain/NotRootSubnet) | [`invalid_argument`](/docs/errors/invalid-argument) | A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0. | +| [`NotSubnetOwner`](/docs/errors/chain/NotSubnetOwner) | [`not_authorized`](/docs/errors/not-authorized) | The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`). | +| [`NothingAuthorized`](/docs/errors/chain/NothingAuthorized) | [`not_found`](/docs/errors/not-found) | No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code. | +| [`OrderAlreadyProcessed`](/docs/errors/chain/OrderAlreadyProcessed) | [`already_exists`](/docs/errors/already-exists) | The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`. | +| [`OrderCancelled`](/docs/errors/chain/OrderCancelled) | [`expired`](/docs/errors/expired) | The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order. | +| [`OrderExpired`](/docs/errors/chain/OrderExpired) | [`expired`](/docs/errors/expired) | The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value. | +| [`OrderNetUidMismatch`](/docs/errors/chain/OrderNetUidMismatch) | [`invalid_argument`](/docs/errors/invalid-argument) | An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out. | +| [`OutOfBounds`](/docs/errors/chain/OutOfBounds) | [`invalid_argument`](/docs/errors/invalid-argument) | A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug. | +| [`OutOfGas`](/docs/errors/chain/OutOfGas) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight. | +| [`OutOfTransientStorage`](/docs/errors/chain/OutOfTransientStorage) | [`limit_exceeded`](/docs/errors/limit-exceeded) | A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit. | +| [`OutputBufferTooSmall`](/docs/errors/chain/OutputBufferTooSmall) | [`invalid_argument`](/docs/errors/invalid-argument) | The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug. | +| [`Overflow`](/docs/errors/chain/Overflow) | [`internal`](/docs/errors/internal) | A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values. | +| [`POWRegistrationDisabled`](/docs/errors/chain/POWRegistrationDisabled) | [`disabled`](/docs/errors/disabled) | `sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled. | +| [`PalletHotkeyNotRegistered`](/docs/errors/chain/PalletHotkeyNotRegistered) | [`not_registered`](/docs/errors/not-registered) | Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs. | +| [`PartialFillsNotEnabled`](/docs/errors/chain/PartialFillsNotEnabled) | [`disabled`](/docs/errors/disabled) | A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing. | +| [`PauseFailed`](/docs/errors/chain/PauseFailed) | [`invalid_argument`](/docs/errors/invalid-argument) | A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause. | +| [`PaymentOverflow`](/docs/errors/chain/PaymentOverflow) | [`internal`](/docs/errors/internal) | Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction. | +| [`PreLogExists`](/docs/errors/chain/PreLogExists) | [`invalid_argument`](/docs/errors/invalid-argument) | An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it. | +| [`PriceConditionNotMet`](/docs/errors/chain/PriceConditionNotMet) | [`too_early`](/docs/errors/too-early) | The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field. | +| [`PriceLimitExceeded`](/docs/errors/chain/PriceLimitExceeded) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting. | +| [`ProportionOverflow`](/docs/errors/chain/ProportionOverflow) | [`invalid_argument`](/docs/errors/invalid-argument) | The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX. | +| [`PulseVerificationError`](/docs/errors/chain/PulseVerificationError) | [`invalid_argument`](/docs/errors/invalid-argument) | BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key). | +| [`RandomSubjectTooLong`](/docs/errors/chain/RandomSubjectTooLong) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section. | +| [`ReentranceDenied`](/docs/errors/chain/ReentranceDenied) | [`invalid_argument`](/docs/errors/invalid-argument) | A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag. | +| [`Reentrancy`](/docs/errors/chain/Reentrancy) | [`internal`](/docs/errors/internal) | EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call. | +| [`RegistrationNotPermittedOnRootSubnet`](/docs/errors/chain/RegistrationNotPermittedOnRootSubnet) | [`invalid_argument`](/docs/errors/invalid-argument) | A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership. | +| [`RegistrationPriceLimitExceeded`](/docs/errors/chain/RegistrationPriceLimitExceeded) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay. | +| [`RelayerMissMatch`](/docs/errors/chain/RelayerMissMatch) | [`invalid_argument`](/docs/errors/invalid-argument) | The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload. | +| [`RelayerRequiredForPartialFill`](/docs/errors/chain/RelayerRequiredForPartialFill) | [`invalid_argument`](/docs/errors/invalid-argument) | A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount. | +| [`Requested`](/docs/errors/chain/Requested) | [`invalid_argument`](/docs/errors/invalid-argument) | The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed. | +| [`RequireSudo`](/docs/errors/chain/RequireSudo) | [`not_authorized`](/docs/errors/not-authorized) | The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item. | +| [`RescheduleNoChange`](/docs/errors/chain/RescheduleNoChange) | [`invalid_argument`](/docs/errors/invalid-argument) | The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block. | +| [`ReservesOutOfBalance`](/docs/errors/chain/ReservesOutOfBalance) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry. | +| [`ReservesTooLow`](/docs/errors/chain/ReservesTooLow) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size. | +| [`ResumeFailed`](/docs/errors/chain/ResumeFailed) | [`invalid_argument`](/docs/errors/invalid-argument) | A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume. | +| [`RevealPeriodTooLarge`](/docs/errors/chain/RevealPeriodTooLarge) | [`invalid_argument`](/docs/errors/invalid-argument) | `set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | +| [`RevealPeriodTooSmall`](/docs/errors/chain/RevealPeriodTooSmall) | [`invalid_argument`](/docs/errors/invalid-argument) | `set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | +| [`RevealTooEarly`](/docs/errors/chain/RevealTooEarly) | [`too_early`](/docs/errors/too-early) | A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch. | +| [`RootNetUidNotAllowed`](/docs/errors/chain/RootNetUidNotAllowed) | [`invalid_argument`](/docs/errors/invalid-argument) | The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet. | +| [`RootNetworkDoesNotExist`](/docs/errors/chain/RootNetworkDoesNotExist) | [`subnet_not_exists`](/docs/errors/subnet-not-exists) | Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`. | +| [`SameAutoStakeHotkeyAlreadySet`](/docs/errors/chain/SameAutoStakeHotkeyAlreadySet) | [`already_exists`](/docs/errors/already-exists) | The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted. | +| [`SameNetuid`](/docs/errors/chain/SameNetuid) | [`invalid_argument`](/docs/errors/invalid-argument) | A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ. | +| [`SenderInSignatories`](/docs/errors/chain/SenderInSignatories) | [`invalid_argument`](/docs/errors/invalid-argument) | The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting. | +| [`ServingRateLimitExceeded`](/docs/errors/chain/ServingRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | `serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait. | +| [`SettingWeightsTooFast`](/docs/errors/chain/SettingWeightsTooFast) | [`rate_limited`](/docs/errors/rate-limited) | The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks. | +| [`SignatoriesOutOfOrder`](/docs/errors/chain/SignatoriesOutOfOrder) | [`invalid_argument`](/docs/errors/invalid-argument) | The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting. | +| [`SlippageTooHigh`](/docs/errors/chain/SlippageTooHigh) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution. | +| [`SpaceLimitExceeded`](/docs/errors/chain/SpaceLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage. | +| [`SpecVersionNeedsToIncrease`](/docs/errors/chain/SpecVersionNeedsToIncrease) | [`invalid_argument`](/docs/errors/invalid-argument) | The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain. | +| [`StakeTooLowForRoot`](/docs/errors/chain/StakeTooLowForRoot) | [`insufficient_balance`](/docs/errors/insufficient-balance) | `root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`). | +| [`StakeUnavailable`](/docs/errors/chain/StakeUnavailable) | [`insufficient_balance`](/docs/errors/insufficient-balance) | An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked. | +| [`StakingRateLimitExceeded`](/docs/errors/chain/StakingRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block. | +| [`StartCallNotReady`](/docs/errors/chain/StartCallNotReady) | [`too_early`](/docs/errors/too-early) | `start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder. | +| [`StateChangeDenied`](/docs/errors/chain/StateChangeDenied) | [`not_authorized`](/docs/errors/not-authorized) | The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context. | +| [`StorageDepositLimitExhausted`](/docs/errors/chain/StorageDepositLimitExhausted) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`. | +| [`StorageDepositNotEnoughFunds`](/docs/errors/chain/StorageDepositNotEnoughFunds) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit. | +| [`StorageOverflow`](/docs/errors/chain/StorageOverflow) | [`internal`](/docs/errors/internal) | Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit. | +| [`SubNetRegistrationDisabled`](/docs/errors/chain/SubNetRegistrationDisabled) | [`disabled`](/docs/errors/disabled) | Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid. | +| [`SubnetBuybackRateLimitExceeded`](/docs/errors/chain/SubnetBuybackRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback. | +| [`SubnetDoesNotExist`](/docs/errors/chain/SubnetDoesNotExist) | [`subnet_not_exists`](/docs/errors/subnet-not-exists) | The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters. | +| [`SubnetLimitReached`](/docs/errors/chain/SubnetLimitReached) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable. | +| [`SubnetNotExists`](/docs/errors/chain/SubnetNotExists) | [`subnet_not_exists`](/docs/errors/subnet-not-exists) | The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved. | +| [`SubtokenDisabled`](/docs/errors/chain/SubtokenDisabled) | [`subtoken_disabled`](/docs/errors/subtoken-disabled) | The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved. | +| [`SwapInputTooLarge`](/docs/errors/chain/SwapInputTooLarge) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed. | +| [`SwapReturnedZero`](/docs/errors/chain/SwapReturnedZero) | [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit. | +| [`SymbolAlreadyInUse`](/docs/errors/chain/SymbolAlreadyInUse) | [`already_exists`](/docs/errors/already-exists) | The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken. | +| [`SymbolDoesNotExist`](/docs/errors/chain/SymbolDoesNotExist) | [`not_found`](/docs/errors/not-found) | The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry. | +| [`TargetBlockNumberInPast`](/docs/errors/chain/TargetBlockNumberInPast) | [`invalid_argument`](/docs/errors/invalid-argument) | The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block. | +| [`TempoOutOfBounds`](/docs/errors/chain/TempoOutOfBounds) | [`invalid_argument`](/docs/errors/invalid-argument) | The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain constants and pick a value inside the bounds; only root may set a tempo outside them. | +| [`TerminatedInConstructor`](/docs/errors/chain/TerminatedInConstructor) | [`internal`](/docs/errors/internal) | The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls. | +| [`TerminatedWhileReentrant`](/docs/errors/chain/TerminatedWhileReentrant) | [`invalid_argument`](/docs/errors/invalid-argument) | `seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. | +| [`TooBig`](/docs/errors/chain/TooBig) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it. | +| [`TooFew`](/docs/errors/chain/TooFew) | [`invalid_argument`](/docs/errors/invalid-argument) | The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. | +| [`TooFewSignatories`](/docs/errors/chain/TooFewSignatories) | [`invalid_argument`](/docs/errors/invalid-argument) | The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. | +| [`TooMany`](/docs/errors/chain/TooMany) | [`limit_exceeded`](/docs/errors/limit-exceeded) | A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`. | +| [`TooManyCalls`](/docs/errors/chain/TooManyCalls) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions. | +| [`TooManyChildren`](/docs/errors/chain/TooManyChildren) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries. | +| [`TooManyFieldsInCommitmentInfo`](/docs/errors/chain/TooManyFieldsInCommitmentInfo) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit. | +| [`TooManyFreezes`](/docs/errors/chain/TooManyFreezes) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first. | +| [`TooManyHolds`](/docs/errors/chain/TooManyHolds) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another. | +| [`TooManyPendingExtrinsics`](/docs/errors/chain/TooManyPendingExtrinsics) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire. | +| [`TooManyRegistrationsThisBlock`](/docs/errors/chain/TooManyRegistrationsThisBlock) | [`rate_limited`](/docs/errors/rate-limited) | Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block. | +| [`TooManyRegistrationsThisInterval`](/docs/errors/chain/TooManyRegistrationsThisInterval) | [`rate_limited`](/docs/errors/rate-limited) | Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start. | +| [`TooManyReserves`](/docs/errors/chain/TooManyReserves) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another. | +| [`TooManySignatories`](/docs/errors/chain/TooManySignatories) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant. | +| [`TooManyTopics`](/docs/errors/chain/TooManyTopics) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit. | +| [`TooManyUIDsPerMechanism`](/docs/errors/chain/TooManyUIDsPerMechanism) | [`limit_exceeded`](/docs/errors/limit-exceeded) | Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit. | +| [`TooManyUnrevealedCommits`](/docs/errors/chain/TooManyUnrevealedCommits) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again. | +| [`TooSoon`](/docs/errors/chain/TooSoon) | [`rate_limited`](/docs/errors/rate-limited) | A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change. | +| [`TransactionMustComeFromEOA`](/docs/errors/chain/TransactionMustComeFromEOA) | [`not_authorized`](/docs/errors/not-authorized) | Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead. | +| [`TransactorAccountShouldBeHotKey`](/docs/errors/chain/TransactorAccountShouldBeHotKey) | [`not_authorized`](/docs/errors/not-authorized) | The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin. | +| [`TransferDisallowed`](/docs/errors/chain/TransferDisallowed) | [`disabled`](/docs/errors/disabled) | A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first. | +| [`TransferFailed`](/docs/errors/chain/TransferFailed) | [`insufficient_balance`](/docs/errors/insufficient-balance) | A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit. | +| [`TrimmingWouldExceedMaxImmunePercentage`](/docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage) | [`limit_exceeded`](/docs/errors/limit-exceeded) | Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target. | +| [`TxChildkeyTakeRateLimitExceeded`](/docs/errors/chain/TxChildkeyTakeRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | `set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder. | +| [`TxRateLimitExceeded`](/docs/errors/chain/TxRateLimitExceeded) | [`rate_limited`](/docs/errors/rate-limited) | An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass. | +| [`UidMapCouldNotBeCleared`](/docs/errors/chain/UidMapCouldNotBeCleared) | [`internal`](/docs/errors/internal) | During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it. | +| [`UidVecContainInvalidOne`](/docs/errors/chain/UidVecContainInvalidOne) | [`invalid_argument`](/docs/errors/invalid-argument) | The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`). | +| [`UidsLengthExceedUidsInSubNet`](/docs/errors/chain/UidsLengthExceedUidsInSubNet) | [`limit_exceeded`](/docs/errors/limit-exceeded) | The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector. | +| [`UnableToRecoverPublicKey`](/docs/errors/chain/UnableToRecoverPublicKey) | [`invalid_argument`](/docs/errors/invalid-argument) | While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key. | +| [`Unannounced`](/docs/errors/chain/Unannounced) | [`too_early`](/docs/errors/too-early) | The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`. | +| [`Unauthorized`](/docs/errors/chain/Unauthorized) | [`not_authorized`](/docs/errors/not-authorized) | In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`. | +| [`Undefined`](/docs/errors/chain/Undefined) | [`internal`](/docs/errors/internal) | Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs. | +| [`Underflow`](/docs/errors/chain/Underflow) | [`internal`](/docs/errors/internal) | A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`. | +| [`UnexpectedTimepoint`](/docs/errors/chain/UnexpectedTimepoint) | [`invalid_argument`](/docs/errors/invalid-argument) | A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry. | +| [`UnexpectedUnreserveLeftover`](/docs/errors/chain/UnexpectedUnreserveLeftover) | [`internal`](/docs/errors/internal) | While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`. | +| [`UnlockAmountTooHigh`](/docs/errors/chain/UnlockAmountTooHigh) | [`insufficient_balance`](/docs/errors/insufficient-balance) | An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount. | +| [`Unproxyable`](/docs/errors/chain/Unproxyable) | [`not_authorized`](/docs/errors/not-authorized) | The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call. | +| [`Unreachable`](/docs/errors/chain/Unreachable) | [`internal`](/docs/errors/internal) | `announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring. | +| [`UnverifiedPulse`](/docs/errors/chain/UnverifiedPulse) | [`invalid_argument`](/docs/errors/invalid-argument) | Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`. | +| [`ValueNotInBounds`](/docs/errors/chain/ValueNotInBounds) | [`invalid_argument`](/docs/errors/invalid-argument) | An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds. | +| [`ValueTooLarge`](/docs/errors/chain/ValueTooLarge) | [`limit_exceeded`](/docs/errors/limit-exceeded) | A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant. | +| [`VestingBalance`](/docs/errors/chain/VestingBalance) | [`insufficient_balance`](/docs/errors/insufficient-balance) | The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs. | +| [`VotingPowerTrackingNotEnabled`](/docs/errors/chain/VotingPowerTrackingNotEnabled) | [`disabled`](/docs/errors/disabled) | Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic. | +| [`WaitingForDissolvedSubnetCleanup`](/docs/errors/chain/WaitingForDissolvedSubnetCleanup) | [`too_early`](/docs/errors/too-early) | The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes. | +| [`WeightExceedsAbsoluteMax`](/docs/errors/chain/WeightExceedsAbsoluteMax) | [`limit_exceeded`](/docs/errors/limit-exceeded) | `set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant. | +| [`WeightVecLengthIsLow`](/docs/errors/chain/WeightVecLengthIsLow) | [`invalid_argument`](/docs/errors/invalid-argument) | The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid. | +| [`WeightVecNotEqualSize`](/docs/errors/chain/WeightVecNotEqualSize) | [`invalid_argument`](/docs/errors/invalid-argument) | The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID. | +| [`WithdrawFailed`](/docs/errors/chain/WithdrawFailed) | [`insufficient_balance`](/docs/errors/insufficient-balance) | Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance. | +| [`WrongTimepoint`](/docs/errors/chain/WrongTimepoint) | [`invalid_argument`](/docs/errors/invalid-argument) | The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint. | +| [`XCMDecodeFailed`](/docs/errors/chain/XCMDecodeFailed) | [`invalid_argument`](/docs/errors/invalid-argument) | The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports. | +| [`ZeroBalanceAfterWithdrawn`](/docs/errors/chain/ZeroBalanceAfterWithdrawn) | [`insufficient_balance`](/docs/errors/insufficient-balance) | Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn. | +| [`ZeroShareInBatch`](/docs/errors/chain/ZeroShareInBatch) | [`invalid_argument`](/docs/errors/invalid-argument) | An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch. | diff --git a/docs/errors/chain/meta.json b/docs/errors/chain/meta.json new file mode 100644 index 0000000000..917e7aefd3 --- /dev/null +++ b/docs/errors/chain/meta.json @@ -0,0 +1,359 @@ +{ + "title": "Chain errors", + "pages": [ + "index", + "AccountNotAllowedCommit", + "AccountRejectsLockedAlpha", + "ActiveLockExists", + "ActivityCutoffFactorMilliOutOfBounds", + "ActivityCutoffTooLow", + "AddStakeBurnRateLimitExceeded", + "AdminActionProhibitedDuringWeightsWindow", + "AllNetworksInImmunity", + "AlphaHighTooLow", + "AlphaLowOutOfRange", + "AlreadyApproved", + "AlreadyDeposited", + "AlreadyFinalized", + "AlreadyFinalizing", + "AlreadyNoted", + "AlreadyStored", + "AmountTooLow", + "AnnouncedColdkeyHashDoesNotMatch", + "AnnouncementDepositInvariantViolated", + "ArithmeticOverflow", + "AutoEpochAlreadyImminent", + "BadEncKeyLen", + "BalanceLow", + "BalanceWithdrawalError", + "BeneficiaryDoesNotOwnHotkey", + "BlockDurationTooLong", + "BlockDurationTooShort", + "BondsMovingAverageMaxReached", + "CallDisabled", + "CallFiltered", + "CallUnavailable", + "CanNotSetRootNetworkWeights", + "CannotAddSelfAsDelegateDependency", + "CannotAffordLockCost", + "CannotBurnOrRecycleOnRootSubnet", + "CannotEndInPast", + "CannotReleaseYet", + "CannotUseSystemAccount", + "CapNotRaised", + "CapRaised", + "CapTooLow", + "ChainIdMismatch", + "ChangePending", + "ChildParentInconsistency", + "CodeInUse", + "CodeInfoNotFound", + "CodeNotFound", + "CodeRejected", + "CodeTooLarge", + "ColdKeyAlreadyAssociated", + "ColdkeySwapAlreadyDisputed", + "ColdkeySwapAnnounced", + "ColdkeySwapAnnouncementNotFound", + "ColdkeySwapClearTooEarly", + "ColdkeySwapDisputed", + "ColdkeySwapReannouncedTooEarly", + "ColdkeySwapTooEarly", + "CommitRevealDisabled", + "CommitRevealEnabled", + "CommittingWeightsTooFast", + "ContractNotFound", + "ContractReverted", + "ContractTrapped", + "ContributionPeriodEnded", + "ContributionPeriodNotEnded", + "ContributionTooLow", + "CreateOriginNotAllowed", + "CurrencyError", + "DeadAccount", + "DecodingFailed", + "DelegateDependencyAlreadyExists", + "DelegateDependencyNotFound", + "DelegateTakeTooHigh", + "DelegateTakeTooLow", + "DelegateTxRateLimitExceeded", + "DeltaZero", + "DepositCannotBeWithdrawn", + "DepositTooLow", + "Deprecated", + "DisabledTemporarily", + "DrandConnectionFailure", + "Duplicate", + "DuplicateChild", + "DuplicateContract", + "DuplicateOffenceReport", + "DuplicateOrderInBatch", + "DuplicateUids", + "DynamicTempoBlockedByCommitReveal", + "Entered", + "EpochTriggerAlreadyPending", + "EvmKeyAssociateRateLimitExceeded", + "EvmKeyAssociationLimitExceeded", + "ExistentialDeposit", + "ExistingVestingSchedule", + "Exited", + "ExpectedBeneficiaryOrigin", + "Expendability", + "ExpiredWeightCommit", + "FailedToExtractRuntimeVersion", + "FailedToSchedule", + "FaucetDisabled", + "FeeOverflow", + "FeeRateTooHigh", + "FirstEmissionBlockNumberAlreadySet", + "GasLimitTooHigh", + "GasLimitTooLow", + "GasPriceTooLow", + "HotKeyAccountNotExists", + "HotKeyAlreadyDelegate", + "HotKeyAlreadyRegisteredInSubNet", + "HotKeyNotRegisteredInNetwork", + "HotKeyNotRegisteredInSubNet", + "HotKeySetTxRateLimitExceeded", + "HotKeySwapOnSubnetIntervalNotPassed", + "IncorrectCommitRevealVersion", + "IncorrectPartialFillAmount", + "IncorrectWeightVersionKey", + "Indeterministic", + "InputForwarded", + "InputLengthsUnequal", + "InsufficientBalance", + "InsufficientInputAmount", + "InsufficientLiquidity", + "InsufficientStakeForLock", + "InvalidCallFlags", + "InvalidChainId", + "InvalidChild", + "InvalidChildkeyTake", + "InvalidCrowdloanId", + "InvalidDerivedAccount", + "InvalidDerivedAccountId", + "InvalidDifficulty", + "InvalidEquivocationProof", + "InvalidFinalizationConfig", + "InvalidIdentity", + "InvalidIpAddress", + "InvalidIpType", + "InvalidKeyOwnershipProof", + "InvalidLeaseBeneficiary", + "InvalidLiquidityValue", + "InvalidNonce", + "InvalidNumRootClaim", + "InvalidOrigin", + "InvalidPort", + "InvalidRecoveredPublicKey", + "InvalidRevealCommitHashNotMatch", + "InvalidRevealRound", + "InvalidRootClaimThreshold", + "InvalidRoundNumber", + "InvalidSchedule", + "InvalidSeal", + "InvalidSignature", + "InvalidSpecName", + "InvalidSubnetNumber", + "InvalidTickRange", + "InvalidValue", + "InvalidVotingPowerEmaAlpha", + "InvalidWorkBlock", + "IssuanceDeactivated", + "LeaseCannotEndInThePast", + "LeaseDoesNotExist", + "LeaseHasNoEndBlock", + "LeaseHasNotEnded", + "LeaseNetuidNotFound", + "LimitOrdersDisabled", + "LiquidAlphaDisabled", + "LiquidityRestrictions", + "LockHotkeyMismatch", + "LockIdOverFlow", + "MaxAllowedUIdsLessThanCurrentUIds", + "MaxAllowedUidsGreaterThanDefaultMaxAllowedUids", + "MaxAllowedUidsLessThanMinAllowedUids", + "MaxCallDepthReached", + "MaxContributionReached", + "MaxContributorsReached", + "MaxDelegateDependenciesReached", + "MaxValidatorsLargerThanMaxUIds", + "MaxWeightExceeded", + "MaxWeightTooLow", + "MaximumContributionTooLow", + "MechanismDoesNotExist", + "MigrationInProgress", + "MinAllowedUidsGreaterThanCurrentUids", + "MinAllowedUidsGreaterThanMaxAllowedUids", + "MinimumContributionTooHigh", + "MinimumContributionTooLow", + "MinimumThreshold", + "MultiBlockMigrationsOngoing", + "Named", + "NeedWaitingMoreBlocksToStarCall", + "NegativeSigmoidSteepness", + "NetworkDissolveAlreadyQueued", + "NetworkTxRateLimitExceeded", + "NeuronNoValidatorPermit", + "NewColdKeyIsHotkey", + "NewHotKeyIsSameWithOld", + "NewHotKeyNotCleanForRootSwap", + "NoApprovalsNeeded", + "NoChainExtension", + "NoContribution", + "NoDeposit", + "NoExistingLock", + "NoMigrationPerformed", + "NoNeuronIdAvailable", + "NoPermission", + "NoSelfProxy", + "NoTimepoint", + "NoWeightsCommitFound", + "NonAssociatedColdKey", + "NonDefaultComposite", + "NonZeroRefCount", + "NoneValue", + "NotAllowed", + "NotAuthorized", + "NotConfigured", + "NotEnoughAlphaOutToRecycle", + "NotEnoughBalanceToPaySwapColdKey", + "NotEnoughBalanceToPaySwapHotKey", + "NotEnoughBalanceToStake", + "NotEnoughStake", + "NotEnoughStakeToSetChildkeys", + "NotEnoughStakeToSetWeights", + "NotEnoughStakeToWithdraw", + "NotFound", + "NotNoted", + "NotOwner", + "NotPermittedOnRootSubnet", + "NotProxy", + "NotReadyToDissolve", + "NotRequested", + "NotRootSubnet", + "NotSubnetOwner", + "NothingAuthorized", + "OrderAlreadyProcessed", + "OrderCancelled", + "OrderExpired", + "OrderNetUidMismatch", + "OutOfBounds", + "OutOfGas", + "OutOfTransientStorage", + "OutputBufferTooSmall", + "Overflow", + "POWRegistrationDisabled", + "PalletHotkeyNotRegistered", + "PartialFillsNotEnabled", + "PauseFailed", + "PaymentOverflow", + "PreLogExists", + "PriceConditionNotMet", + "PriceLimitExceeded", + "ProportionOverflow", + "PulseVerificationError", + "RandomSubjectTooLong", + "ReentranceDenied", + "Reentrancy", + "RegistrationNotPermittedOnRootSubnet", + "RegistrationPriceLimitExceeded", + "RelayerMissMatch", + "RelayerRequiredForPartialFill", + "Requested", + "RequireSudo", + "RescheduleNoChange", + "ReservesOutOfBalance", + "ReservesTooLow", + "ResumeFailed", + "RevealPeriodTooLarge", + "RevealPeriodTooSmall", + "RevealTooEarly", + "RootNetUidNotAllowed", + "RootNetworkDoesNotExist", + "SameAutoStakeHotkeyAlreadySet", + "SameNetuid", + "SenderInSignatories", + "ServingRateLimitExceeded", + "SettingWeightsTooFast", + "SignatoriesOutOfOrder", + "SlippageTooHigh", + "SpaceLimitExceeded", + "SpecVersionNeedsToIncrease", + "StakeTooLowForRoot", + "StakeUnavailable", + "StakingRateLimitExceeded", + "StartCallNotReady", + "StateChangeDenied", + "StorageDepositLimitExhausted", + "StorageDepositNotEnoughFunds", + "StorageOverflow", + "SubNetRegistrationDisabled", + "SubnetBuybackRateLimitExceeded", + "SubnetDoesNotExist", + "SubnetLimitReached", + "SubnetNotExists", + "SubtokenDisabled", + "SwapInputTooLarge", + "SwapReturnedZero", + "SymbolAlreadyInUse", + "SymbolDoesNotExist", + "TargetBlockNumberInPast", + "TempoOutOfBounds", + "TerminatedInConstructor", + "TerminatedWhileReentrant", + "TooBig", + "TooFew", + "TooFewSignatories", + "TooMany", + "TooManyCalls", + "TooManyChildren", + "TooManyFieldsInCommitmentInfo", + "TooManyFreezes", + "TooManyHolds", + "TooManyPendingExtrinsics", + "TooManyRegistrationsThisBlock", + "TooManyRegistrationsThisInterval", + "TooManyReserves", + "TooManySignatories", + "TooManyTopics", + "TooManyUIDsPerMechanism", + "TooManyUnrevealedCommits", + "TooSoon", + "TransactionMustComeFromEOA", + "TransactorAccountShouldBeHotKey", + "TransferDisallowed", + "TransferFailed", + "TrimmingWouldExceedMaxImmunePercentage", + "TxChildkeyTakeRateLimitExceeded", + "TxRateLimitExceeded", + "UidMapCouldNotBeCleared", + "UidVecContainInvalidOne", + "UidsLengthExceedUidsInSubNet", + "UnableToRecoverPublicKey", + "Unannounced", + "Unauthorized", + "Undefined", + "Underflow", + "UnexpectedTimepoint", + "UnexpectedUnreserveLeftover", + "UnlockAmountTooHigh", + "Unproxyable", + "Unreachable", + "UnverifiedPulse", + "ValueNotInBounds", + "ValueTooLarge", + "VestingBalance", + "VotingPowerTrackingNotEnabled", + "WaitingForDissolvedSubnetCleanup", + "WeightExceedsAbsoluteMax", + "WeightVecLengthIsLow", + "WeightVecNotEqualSize", + "WithdrawFailed", + "WrongTimepoint", + "XCMDecodeFailed", + "ZeroBalanceAfterWithdrawn", + "ZeroShareInBatch" + ] +} diff --git a/docs/errors/disabled.mdx b/docs/errors/disabled.mdx new file mode 100644 index 0000000000..81b42ae0b3 --- /dev/null +++ b/docs/errors/disabled.mdx @@ -0,0 +1,40 @@ +--- +title: "disabled" +description: "This call or feature is switched off on this network" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The call or feature is switched off: registration is closed on the subnet, commit-reveal (or the legacy direct path) is not enabled, transfers are disallowed by the subnet, the extrinsic is deprecated, or an admin has disabled it temporarily. + +This is a deliberate chain- or subnet-level switch, not a problem with your arguments. use the supported alternative call if one exists (the error name usually points at it), or wait for the feature to be enabled. + +## Remediation + +This call or feature is switched off on this network + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `disabled`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`CallDisabled`](/docs/errors/chain/CallDisabled) | The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version. | +| [`CommitRevealDisabled`](/docs/errors/chain/CommitRevealDisabled) | A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled. | +| [`CommitRevealEnabled`](/docs/errors/chain/CommitRevealEnabled) | Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`. | +| [`Deprecated`](/docs/errors/chain/Deprecated) | The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`). | +| [`DisabledTemporarily`](/docs/errors/chain/DisabledTemporarily) | The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled. | +| [`DynamicTempoBlockedByCommitReveal`](/docs/errors/chain/DynamicTempoBlockedByCommitReveal) | `trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs. | +| [`FaucetDisabled`](/docs/errors/chain/FaucetDisabled) | The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead. | +| [`IssuanceDeactivated`](/docs/errors/chain/IssuanceDeactivated) | Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again. | +| [`LimitOrdersDisabled`](/docs/errors/chain/LimitOrdersDisabled) | Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet. | +| [`LiquidAlphaDisabled`](/docs/errors/chain/LiquidAlphaDisabled) | Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first. | +| [`NoChainExtension`](/docs/errors/chain/NoChainExtension) | The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against. | +| [`NotConfigured`](/docs/errors/chain/NotConfigured) | The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants. | +| [`POWRegistrationDisabled`](/docs/errors/chain/POWRegistrationDisabled) | `sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled. | +| [`PartialFillsNotEnabled`](/docs/errors/chain/PartialFillsNotEnabled) | A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing. | +| [`SubNetRegistrationDisabled`](/docs/errors/chain/SubNetRegistrationDisabled) | Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid. | +| [`TransferDisallowed`](/docs/errors/chain/TransferDisallowed) | A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first. | +| [`VotingPowerTrackingNotEnabled`](/docs/errors/chain/VotingPowerTrackingNotEnabled) | Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic. | + +The same explanation is available in the terminal: `btcli explain disabled` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/expired.mdx b/docs/errors/expired.mdx new file mode 100644 index 0000000000..25f410c376 --- /dev/null +++ b/docs/errors/expired.mdx @@ -0,0 +1,28 @@ +--- +title: "expired" +description: "The window has closed; restart the flow with fresh state" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The call arrived after its window closed: a weights commit past its reveal period, an order past its expiry, or a contribution after the period ended. + +The expired object cannot be revived. restart the flow with fresh state — make a new commit, place a new order, or move on. + +## Remediation + +The window has closed; restart the flow with fresh state + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `expired`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`ContributionPeriodEnded`](/docs/errors/chain/ContributionPeriodEnded) | A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized. | +| [`ExpiredWeightCommit`](/docs/errors/chain/ExpiredWeightCommit) | The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time. | +| [`InvalidRevealRound`](/docs/errors/chain/InvalidRevealRound) | A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number. | +| [`OrderCancelled`](/docs/errors/chain/OrderCancelled) | The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order. | +| [`OrderExpired`](/docs/errors/chain/OrderExpired) | The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value. | + +The same explanation is available in the terminal: `btcli explain expired` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/index.mdx b/docs/errors/index.mdx new file mode 100644 index 0000000000..fddf3e7aec --- /dev/null +++ b/docs/errors/index.mdx @@ -0,0 +1,29 @@ +--- +title: "Errors" +description: "Every failure carries a machine-readable code and a remediation hint." +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A failed `execute` returns an `ExtrinsicResult` whose `error` has a semantic `code` (branch on it) and a `remediation` hint (what to try next). Every chain error name is deliberately classified — a CI gate keeps the mapping complete in both directions. Each code has its own explainer page listing the chain errors that map to it, and every exact chain error name has its own page under [chain errors](/docs/errors/chain). The machine-readable version is at [`/catalog/errors.json`](/catalog/errors.json). + +| Code | Chain errors | Remediation | +| --- | --- | --- | +| [`insufficient_balance`](/docs/errors/insufficient-balance) | 23 | Fund the signing account or reduce the amount; check with `btcli wallet balance` | +| [`insufficient_liquidity`](/docs/errors/insufficient-liquidity) | 8 | The pool cannot absorb this trade; reduce the amount or split it into smaller steps | +| [`rate_limited`](/docs/errors/rate-limited) | 17 | Wait for the rate-limit window to pass, then retry | +| [`not_registered`](/docs/errors/not-registered) | 4 | Register the hotkey on this subnet first with `btcli subnets register` | +| [`not_authorized`](/docs/errors/not-authorized) | 22 | Sign with the key or origin that owns the target object, then retry | +| [`already_exists`](/docs/errors/already-exists) | 27 | The object or state already exists; treat the goal as met or pick a different target | +| [`not_found`](/docs/errors/not-found) | 20 | The referenced object is not on-chain; check the identifier | +| [`subnet_not_exists`](/docs/errors/subnet-not-exists) | 4 | Use an existing netuid; `btcli subnets list` shows valid ones | +| [`subtoken_disabled`](/docs/errors/subtoken-disabled) | 1 | The subnet is not active yet; wait for start_call | +| [`disabled`](/docs/errors/disabled) | 17 | This call or feature is switched off on this network | +| [`too_early`](/docs/errors/too-early) | 18 | The required window has not opened yet; wait some blocks and retry | +| [`expired`](/docs/errors/expired) | 5 | The window has closed; restart the flow with fresh state | +| [`limit_exceeded`](/docs/errors/limit-exceeded) | 34 | A chain-side capacity limit was hit; reduce the size or count of the request | +| [`unit_mismatch`](/docs/errors/unit-mismatch) | — | Match the Balance netuid to the operation's currency | +| [`invalid_argument`](/docs/errors/invalid-argument) | 135 | Check the argument values against the operation schema | +| [`policy_violation`](/docs/errors/policy-violation) | — | The action exceeds a configured safety policy | +| [`internal`](/docs/errors/internal) | 18 | A chain-side invariant failed; nothing to fix client-side — report it if it persists | +| [`unknown`](/docs/errors/unknown) | — | Inspect the message for details | diff --git a/docs/errors/insufficient-balance.mdx b/docs/errors/insufficient-balance.mdx new file mode 100644 index 0000000000..b1efc11fb6 --- /dev/null +++ b/docs/errors/insufficient-balance.mdx @@ -0,0 +1,48 @@ +--- +title: "insufficient_balance" +description: "Fund the signing account or reduce the amount; check with `btcli wallet balance`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The signing account cannot cover the requested amount plus the transaction fee. + +This covers several chain-side variants: the free balance is too low for a transfer, the stake being withdrawn is larger than what is actually staked, or the transfer would drop the account below the existential deposit and reap it. + +Check the account with `btcli wallet balance`, then reduce the amount or fund the coldkey. for stake operations, `btcli stake list` shows what is actually staked per subnet. + +## Remediation + +Fund the signing account or reduce the amount; check with `btcli wallet balance` + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `insufficient_balance`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`BalanceLow`](/docs/errors/chain/BalanceLow) | The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price. | +| [`BalanceWithdrawalError`](/docs/errors/chain/BalanceWithdrawalError) | The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up. | +| [`CannotAffordLockCost`](/docs/errors/chain/CannotAffordLockCost) | The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet. | +| [`ExistentialDeposit`](/docs/errors/chain/ExistentialDeposit) | The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant. | +| [`Expendability`](/docs/errors/chain/Expendability) | The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable. | +| [`InsufficientBalance`](/docs/errors/chain/InsufficientBalance) | The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved. | +| [`InsufficientStakeForLock`](/docs/errors/chain/InsufficientStakeForLock) | The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first. | +| [`LiquidityRestrictions`](/docs/errors/chain/LiquidityRestrictions) | The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal. | +| [`NotEnoughBalanceToPaySwapColdKey`](/docs/errors/chain/NotEnoughBalanceToPaySwapColdKey) | The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap. | +| [`NotEnoughBalanceToPaySwapHotKey`](/docs/errors/chain/NotEnoughBalanceToPaySwapHotKey) | The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying. | +| [`NotEnoughBalanceToStake`](/docs/errors/chain/NotEnoughBalanceToStake) | The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid). | +| [`NotEnoughStake`](/docs/errors/chain/NotEnoughStake) | The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs. | +| [`NotEnoughStakeToSetChildkeys`](/docs/errors/chain/NotEnoughStakeToSetChildkeys) | Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value. | +| [`NotEnoughStakeToSetWeights`](/docs/errors/chain/NotEnoughStakeToSetWeights) | Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`. | +| [`NotEnoughStakeToWithdraw`](/docs/errors/chain/NotEnoughStakeToWithdraw) | An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage). | +| [`StakeTooLowForRoot`](/docs/errors/chain/StakeTooLowForRoot) | `root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`). | +| [`StakeUnavailable`](/docs/errors/chain/StakeUnavailable) | An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked. | +| [`StorageDepositNotEnoughFunds`](/docs/errors/chain/StorageDepositNotEnoughFunds) | The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit. | +| [`TransferFailed`](/docs/errors/chain/TransferFailed) | A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit. | +| [`UnlockAmountTooHigh`](/docs/errors/chain/UnlockAmountTooHigh) | An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount. | +| [`VestingBalance`](/docs/errors/chain/VestingBalance) | The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs. | +| [`WithdrawFailed`](/docs/errors/chain/WithdrawFailed) | Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance. | +| [`ZeroBalanceAfterWithdrawn`](/docs/errors/chain/ZeroBalanceAfterWithdrawn) | Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn. | + +The same explanation is available in the terminal: `btcli explain insufficient_balance` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/insufficient-liquidity.mdx b/docs/errors/insufficient-liquidity.mdx new file mode 100644 index 0000000000..0c2f508989 --- /dev/null +++ b/docs/errors/insufficient-liquidity.mdx @@ -0,0 +1,33 @@ +--- +title: "insufficient_liquidity" +description: "The pool cannot absorb this trade; reduce the amount or split it into smaller steps" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The pool on the other side of the operation cannot absorb it: the swap reserves are too low or too imbalanced, the price would move past the configured limit, or the slippage exceeds the allowed tolerance. + +Unlike insufficient_balance this is not about your account — it is about the subnet's liquidity. reduce the amount, split it into smaller steps across blocks, or trade on a subnet with deeper reserves. + +Stake trades are slippage-protected by default with a 5% tolerance (SlippageTooHigh): raise it with `--rate-tolerance`, or disable the protection with `--no-slippage-protection` (slippage_protection=False in the SDK) to trade through the price move. + +## Remediation + +The pool cannot absorb this trade; reduce the amount or split it into smaller steps + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `insufficient_liquidity`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`InsufficientLiquidity`](/docs/errors/chain/InsufficientLiquidity) | The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount. | +| [`NotEnoughAlphaOutToRecycle`](/docs/errors/chain/NotEnoughAlphaOutToRecycle) | A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount. | +| [`PriceLimitExceeded`](/docs/errors/chain/PriceLimitExceeded) | The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting. | +| [`ReservesOutOfBalance`](/docs/errors/chain/ReservesOutOfBalance) | Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry. | +| [`ReservesTooLow`](/docs/errors/chain/ReservesTooLow) | The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size. | +| [`SlippageTooHigh`](/docs/errors/chain/SlippageTooHigh) | A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution. | +| [`SwapInputTooLarge`](/docs/errors/chain/SwapInputTooLarge) | The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed. | +| [`SwapReturnedZero`](/docs/errors/chain/SwapReturnedZero) | The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit. | + +The same explanation is available in the terminal: `btcli explain insufficient_liquidity` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/internal.mdx b/docs/errors/internal.mdx new file mode 100644 index 0000000000..58eeb065e3 --- /dev/null +++ b/docs/errors/internal.mdx @@ -0,0 +1,41 @@ +--- +title: "internal" +description: "A chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The chain hit an internal invariant it could not uphold: an arithmetic overflow, an unreachable branch, a storage inconsistency, or a failure in an underlying pallet. + +There is usually nothing to fix client-side. retry once in case it was state-dependent; if it persists, report it upstream with the exact chain error name from the diagnostic. + +## Remediation + +A chain-side invariant failed; nothing to fix client-side — report it if it persists + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `internal`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`AnnouncementDepositInvariantViolated`](/docs/errors/chain/AnnouncementDepositInvariantViolated) | Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input. | +| [`ArithmeticOverflow`](/docs/errors/chain/ArithmeticOverflow) | Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts. | +| [`ContractReverted`](/docs/errors/chain/ContractReverted) | The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value. | +| [`ContractTrapped`](/docs/errors/chain/ContractTrapped) | The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations. | +| [`CurrencyError`](/docs/errors/chain/CurrencyError) | A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason. | +| [`DrandConnectionFailure`](/docs/errors/chain/DrandConnectionFailure) | Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints. | +| [`FailedToSchedule`](/docs/errors/chain/FailedToSchedule) | The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated. | +| [`FeeOverflow`](/docs/errors/chain/FeeOverflow) | Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction. | +| [`Overflow`](/docs/errors/chain/Overflow) | A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values. | +| [`PaymentOverflow`](/docs/errors/chain/PaymentOverflow) | Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction. | +| [`Reentrancy`](/docs/errors/chain/Reentrancy) | EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call. | +| [`StorageOverflow`](/docs/errors/chain/StorageOverflow) | Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit. | +| [`TerminatedInConstructor`](/docs/errors/chain/TerminatedInConstructor) | The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls. | +| [`UidMapCouldNotBeCleared`](/docs/errors/chain/UidMapCouldNotBeCleared) | During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it. | +| [`Undefined`](/docs/errors/chain/Undefined) | Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs. | +| [`Underflow`](/docs/errors/chain/Underflow) | A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`. | +| [`UnexpectedUnreserveLeftover`](/docs/errors/chain/UnexpectedUnreserveLeftover) | While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`. | +| [`Unreachable`](/docs/errors/chain/Unreachable) | `announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring. | + +The same explanation is available in the terminal: `btcli explain internal` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/invalid-argument.mdx b/docs/errors/invalid-argument.mdx new file mode 100644 index 0000000000..58ff794f0c --- /dev/null +++ b/docs/errors/invalid-argument.mdx @@ -0,0 +1,158 @@ +--- +title: "invalid_argument" +description: "Check the argument values against the operation schema" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +An argument was rejected before or at submission: a malformed address, an out-of-range value, a bad signature, or an extrinsic the node refused to accept into its pool. + +Check the argument values against the operation's schema (`btcli tools` prints the machine-readable catalog; `--help` on any command shows its parameters). + +## Remediation + +Check the argument values against the operation schema + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `invalid_argument`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`AccountRejectsLockedAlpha`](/docs/errors/chain/AccountRejectsLockedAlpha) | Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying. | +| [`ActivityCutoffFactorMilliOutOfBounds`](/docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds) | The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting. | +| [`ActivityCutoffTooLow`](/docs/errors/chain/ActivityCutoffTooLow) | An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `. | +| [`AlphaHighTooLow`](/docs/errors/chain/AlphaHighTooLow) | The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid. | +| [`AlphaLowOutOfRange`](/docs/errors/chain/AlphaLowOutOfRange) | The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid. | +| [`AmountTooLow`](/docs/errors/chain/AmountTooLow) | A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount. | +| [`AnnouncedColdkeyHashDoesNotMatch`](/docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch) | The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to. | +| [`BadEncKeyLen`](/docs/errors/chain/BadEncKeyLen) | The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing. | +| [`BlockDurationTooLong`](/docs/errors/chain/BlockDurationTooLong) | The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`. | +| [`BlockDurationTooShort`](/docs/errors/chain/BlockDurationTooShort) | The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`. | +| [`CanNotSetRootNetworkWeights`](/docs/errors/chain/CanNotSetRootNetworkWeights) | `set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism. | +| [`CannotAddSelfAsDelegateDependency`](/docs/errors/chain/CannotAddSelfAsDelegateDependency) | A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash. | +| [`CannotBurnOrRecycleOnRootSubnet`](/docs/errors/chain/CannotBurnOrRecycleOnRootSubnet) | `recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn. | +| [`CannotEndInPast`](/docs/errors/chain/CannotEndInPast) | The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater. | +| [`CapTooLow`](/docs/errors/chain/CapTooLow) | On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry. | +| [`ChainIdMismatch`](/docs/errors/chain/ChainIdMismatch) | The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed. | +| [`ChildParentInconsistency`](/docs/errors/chain/ChildParentInconsistency) | A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap. | +| [`CodeInUse`](/docs/errors/chain/CodeInUse) | `remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal. | +| [`CodeRejected`](/docs/errors/chain/CodeRejected) | The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason. | +| [`ContributionTooLow`](/docs/errors/chain/ContributionTooLow) | The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount. | +| [`DecodingFailed`](/docs/errors/chain/DecodingFailed) | Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API. | +| [`DelegateTakeTooHigh`](/docs/errors/chain/DelegateTakeTooHigh) | The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it. | +| [`DelegateTakeTooLow`](/docs/errors/chain/DelegateTakeTooLow) | The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item. | +| [`DeltaZero`](/docs/errors/chain/DeltaZero) | The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount. | +| [`DepositCannotBeWithdrawn`](/docs/errors/chain/DepositCannotBeWithdrawn) | The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry. | +| [`DepositTooLow`](/docs/errors/chain/DepositTooLow) | The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit. | +| [`DuplicateChild`](/docs/errors/chain/DuplicateChild) | The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid. | +| [`DuplicateOrderInBatch`](/docs/errors/chain/DuplicateOrderInBatch) | Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`. | +| [`DuplicateUids`](/docs/errors/chain/DuplicateUids) | The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector. | +| [`FailedToExtractRuntimeVersion`](/docs/errors/chain/FailedToExtractRuntimeVersion) | The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly. | +| [`FeeRateTooHigh`](/docs/errors/chain/FeeRateTooHigh) | `set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting. | +| [`GasLimitTooHigh`](/docs/errors/chain/GasLimitTooHigh) | The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it. | +| [`GasLimitTooLow`](/docs/errors/chain/GasLimitTooLow) | The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result. | +| [`GasPriceTooLow`](/docs/errors/chain/GasPriceTooLow) | The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee. | +| [`IncorrectCommitRevealVersion`](/docs/errors/chain/IncorrectCommitRevealVersion) | The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version. | +| [`IncorrectPartialFillAmount`](/docs/errors/chain/IncorrectPartialFillAmount) | The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`. | +| [`IncorrectWeightVersionKey`](/docs/errors/chain/IncorrectWeightVersionKey) | The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key. | +| [`Indeterministic`](/docs/errors/chain/Indeterministic) | Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically. | +| [`InputForwarded`](/docs/errors/chain/InputForwarded) | The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards. | +| [`InputLengthsUnequal`](/docs/errors/chain/InputLengthsUnequal) | A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length. | +| [`InsufficientInputAmount`](/docs/errors/chain/InsufficientInputAmount) | Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output. | +| [`InvalidCallFlags`](/docs/errors/chain/InvalidCallFlags) | The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values. | +| [`InvalidChainId`](/docs/errors/chain/InvalidChainId) | The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction. | +| [`InvalidChild`](/docs/errors/chain/InvalidChild) | The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved. | +| [`InvalidChildkeyTake`](/docs/errors/chain/InvalidChildkeyTake) | The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds. | +| [`InvalidDerivedAccount`](/docs/errors/chain/InvalidDerivedAccount) | Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation. | +| [`InvalidDerivedAccountId`](/docs/errors/chain/InvalidDerivedAccountId) | Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one). | +| [`InvalidDifficulty`](/docs/errors/chain/InvalidDifficulty) | The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block. | +| [`InvalidEquivocationProof`](/docs/errors/chain/InvalidEquivocationProof) | The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set. | +| [`InvalidFinalizationConfig`](/docs/errors/chain/InvalidFinalizationConfig) | Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry. | +| [`InvalidIdentity`](/docs/errors/chain/InvalidIdentity) | The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity. | +| [`InvalidIpAddress`](/docs/errors/chain/InvalidIpAddress) | The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed. | +| [`InvalidIpType`](/docs/errors/chain/InvalidIpType) | The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted. | +| [`InvalidKeyOwnershipProof`](/docs/errors/chain/InvalidKeyOwnershipProof) | The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report. | +| [`InvalidLeaseBeneficiary`](/docs/errors/chain/InvalidLeaseBeneficiary) | The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey. | +| [`InvalidLiquidityValue`](/docs/errors/chain/InvalidLiquidityValue) | Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`. | +| [`InvalidNonce`](/docs/errors/chain/InvalidNonce) | The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`. | +| [`InvalidNumRootClaim`](/docs/errors/chain/InvalidNumRootClaim) | The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number. | +| [`InvalidPort`](/docs/errors/chain/InvalidPort) | The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port. | +| [`InvalidRecoveredPublicKey`](/docs/errors/chain/InvalidRecoveredPublicKey) | The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format). | +| [`InvalidRevealCommitHashNotMatch`](/docs/errors/chain/InvalidRevealCommitHashNotMatch) | The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid. | +| [`InvalidRootClaimThreshold`](/docs/errors/chain/InvalidRootClaimThreshold) | The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid. | +| [`InvalidRoundNumber`](/docs/errors/chain/InvalidRoundNumber) | A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`. | +| [`InvalidSchedule`](/docs/errors/chain/InvalidSchedule) | The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments. | +| [`InvalidSeal`](/docs/errors/chain/InvalidSeal) | The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit. | +| [`InvalidSignature`](/docs/errors/chain/InvalidSignature) | Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed. | +| [`InvalidSpecName`](/docs/errors/chain/InvalidSpecName) | The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one. | +| [`InvalidSubnetNumber`](/docs/errors/chain/InvalidSubnetNumber) | A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit. | +| [`InvalidTickRange`](/docs/errors/chain/InvalidTickRange) | Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones. | +| [`InvalidValue`](/docs/errors/chain/InvalidValue) | A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`). | +| [`InvalidVotingPowerEmaAlpha`](/docs/errors/chain/InvalidVotingPowerEmaAlpha) | The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid. | +| [`InvalidWorkBlock`](/docs/errors/chain/InvalidWorkBlock) | The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block. | +| [`LeaseCannotEndInThePast`](/docs/errors/chain/LeaseCannotEndInThePast) | The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease. | +| [`LeaseHasNoEndBlock`](/docs/errors/chain/LeaseHasNoEndBlock) | The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id. | +| [`LockHotkeyMismatch`](/docs/errors/chain/LockHotkeyMismatch) | The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first. | +| [`MaxAllowedUIdsLessThanCurrentUIds`](/docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds) | `sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid. | +| [`MaxAllowedUidsGreaterThanDefaultMaxAllowedUids`](/docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids) | `sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value. | +| [`MaxAllowedUidsLessThanMinAllowedUids`](/docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids) | `sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid. | +| [`MaxValidatorsLargerThanMaxUIds`](/docs/errors/chain/MaxValidatorsLargerThanMaxUIds) | `sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid. | +| [`MaxWeightTooLow`](/docs/errors/chain/MaxWeightTooLow) | The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`. | +| [`MaximumContributionTooLow`](/docs/errors/chain/MaximumContributionTooLow) | The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry. | +| [`MinAllowedUidsGreaterThanCurrentUids`](/docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids) | `sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid. | +| [`MinAllowedUidsGreaterThanMaxAllowedUids`](/docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids) | `sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid. | +| [`MinimumContributionTooHigh`](/docs/errors/chain/MinimumContributionTooHigh) | The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`. | +| [`MinimumContributionTooLow`](/docs/errors/chain/MinimumContributionTooLow) | The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value. | +| [`MinimumThreshold`](/docs/errors/chain/MinimumThreshold) | The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case. | +| [`Named`](/docs/errors/chain/Named) | An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map. | +| [`NegativeSigmoidSteepness`](/docs/errors/chain/NegativeSigmoidSteepness) | A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root. | +| [`NewColdKeyIsHotkey`](/docs/errors/chain/NewColdKeyIsHotkey) | The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey. | +| [`NewHotKeyIsSameWithOld`](/docs/errors/chain/NewHotKeyIsSameWithOld) | swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey. | +| [`NewHotKeyNotCleanForRootSwap`](/docs/errors/chain/NewHotKeyNotCleanForRootSwap) | The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey. | +| [`NoApprovalsNeeded`](/docs/errors/chain/NoApprovalsNeeded) | The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it. | +| [`NoMigrationPerformed`](/docs/errors/chain/NoMigrationPerformed) | A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument. | +| [`NoSelfProxy`](/docs/errors/chain/NoSelfProxy) | An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account. | +| [`NoTimepoint`](/docs/errors/chain/NoTimepoint) | No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`. | +| [`NonDefaultComposite`](/docs/errors/chain/NonDefaultComposite) | The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way. | +| [`NonZeroRefCount`](/docs/errors/chain/NonZeroRefCount) | The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first. | +| [`NotPermittedOnRootSubnet`](/docs/errors/chain/NotPermittedOnRootSubnet) | An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0. | +| [`NotRootSubnet`](/docs/errors/chain/NotRootSubnet) | A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0. | +| [`OrderNetUidMismatch`](/docs/errors/chain/OrderNetUidMismatch) | An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out. | +| [`OutOfBounds`](/docs/errors/chain/OutOfBounds) | A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug. | +| [`OutputBufferTooSmall`](/docs/errors/chain/OutputBufferTooSmall) | The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug. | +| [`PauseFailed`](/docs/errors/chain/PauseFailed) | A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause. | +| [`PreLogExists`](/docs/errors/chain/PreLogExists) | An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it. | +| [`ProportionOverflow`](/docs/errors/chain/ProportionOverflow) | The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX. | +| [`PulseVerificationError`](/docs/errors/chain/PulseVerificationError) | BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key). | +| [`ReentranceDenied`](/docs/errors/chain/ReentranceDenied) | A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag. | +| [`RegistrationNotPermittedOnRootSubnet`](/docs/errors/chain/RegistrationNotPermittedOnRootSubnet) | A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership. | +| [`RelayerMissMatch`](/docs/errors/chain/RelayerMissMatch) | The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload. | +| [`RelayerRequiredForPartialFill`](/docs/errors/chain/RelayerRequiredForPartialFill) | A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount. | +| [`Requested`](/docs/errors/chain/Requested) | The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed. | +| [`RescheduleNoChange`](/docs/errors/chain/RescheduleNoChange) | The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block. | +| [`ResumeFailed`](/docs/errors/chain/ResumeFailed) | A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume. | +| [`RevealPeriodTooLarge`](/docs/errors/chain/RevealPeriodTooLarge) | `set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | +| [`RevealPeriodTooSmall`](/docs/errors/chain/RevealPeriodTooSmall) | `set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid. | +| [`RootNetUidNotAllowed`](/docs/errors/chain/RootNetUidNotAllowed) | The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet. | +| [`SameNetuid`](/docs/errors/chain/SameNetuid) | A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ. | +| [`SenderInSignatories`](/docs/errors/chain/SenderInSignatories) | The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting. | +| [`SignatoriesOutOfOrder`](/docs/errors/chain/SignatoriesOutOfOrder) | The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting. | +| [`SpecVersionNeedsToIncrease`](/docs/errors/chain/SpecVersionNeedsToIncrease) | The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain. | +| [`TargetBlockNumberInPast`](/docs/errors/chain/TargetBlockNumberInPast) | The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block. | +| [`TempoOutOfBounds`](/docs/errors/chain/TempoOutOfBounds) | The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain constants and pick a value inside the bounds; only root may set a tempo outside them. | +| [`TerminatedWhileReentrant`](/docs/errors/chain/TerminatedWhileReentrant) | `seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated. | +| [`TooFew`](/docs/errors/chain/TooFew) | The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`. | +| [`TooFewSignatories`](/docs/errors/chain/TooFewSignatories) | The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using. | +| [`UidVecContainInvalidOne`](/docs/errors/chain/UidVecContainInvalidOne) | The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`). | +| [`UnableToRecoverPublicKey`](/docs/errors/chain/UnableToRecoverPublicKey) | While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key. | +| [`UnexpectedTimepoint`](/docs/errors/chain/UnexpectedTimepoint) | A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry. | +| [`UnverifiedPulse`](/docs/errors/chain/UnverifiedPulse) | Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`. | +| [`ValueNotInBounds`](/docs/errors/chain/ValueNotInBounds) | An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds. | +| [`WeightVecLengthIsLow`](/docs/errors/chain/WeightVecLengthIsLow) | The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid. | +| [`WeightVecNotEqualSize`](/docs/errors/chain/WeightVecNotEqualSize) | The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID. | +| [`WrongTimepoint`](/docs/errors/chain/WrongTimepoint) | The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint. | +| [`XCMDecodeFailed`](/docs/errors/chain/XCMDecodeFailed) | The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports. | +| [`ZeroShareInBatch`](/docs/errors/chain/ZeroShareInBatch) | An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch. | + +The same explanation is available in the terminal: `btcli explain invalid_argument` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/limit-exceeded.mdx b/docs/errors/limit-exceeded.mdx new file mode 100644 index 0000000000..aef90ffd76 --- /dev/null +++ b/docs/errors/limit-exceeded.mdx @@ -0,0 +1,57 @@ +--- +title: "limit_exceeded" +description: "A chain-side capacity limit was hit; reduce the size or count of the request" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +A chain-side capacity limit was hit: too many children, weights above the maximum, no free UID slots on the subnet, the subnet limit reached, or a batch/queue at its configured maximum. + +These are hard caps rather than timing windows, so retrying unchanged will fail again. reduce the size or count of the request, or free capacity first (e.g. remove a child before adding another). + +## Remediation + +A chain-side capacity limit was hit; reduce the size or count of the request + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `limit_exceeded`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`BondsMovingAverageMaxReached`](/docs/errors/chain/BondsMovingAverageMaxReached) | A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root. | +| [`CapRaised`](/docs/errors/chain/CapRaised) | A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`. | +| [`CodeTooLarge`](/docs/errors/chain/CodeTooLarge) | The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract. | +| [`EvmKeyAssociationLimitExceeded`](/docs/errors/chain/EvmKeyAssociationLimitExceeded) | The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address. | +| [`LockIdOverFlow`](/docs/errors/chain/LockIdOverFlow) | The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem. | +| [`MaxCallDepthReached`](/docs/errors/chain/MaxCallDepthReached) | A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth. | +| [`MaxContributionReached`](/docs/errors/chain/MaxContributionReached) | The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`. | +| [`MaxContributorsReached`](/docs/errors/chain/MaxContributorsReached) | The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant. | +| [`MaxDelegateDependenciesReached`](/docs/errors/chain/MaxDelegateDependenciesReached) | `lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first. | +| [`MaxWeightExceeded`](/docs/errors/chain/MaxWeightExceeded) | After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting. | +| [`NoNeuronIdAvailable`](/docs/errors/chain/NoNeuronIdAvailable) | Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire. | +| [`OutOfGas`](/docs/errors/chain/OutOfGas) | The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight. | +| [`OutOfTransientStorage`](/docs/errors/chain/OutOfTransientStorage) | A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit. | +| [`RandomSubjectTooLong`](/docs/errors/chain/RandomSubjectTooLong) | The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section. | +| [`RegistrationPriceLimitExceeded`](/docs/errors/chain/RegistrationPriceLimitExceeded) | `burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay. | +| [`StorageDepositLimitExhausted`](/docs/errors/chain/StorageDepositLimitExhausted) | The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`. | +| [`SubnetLimitReached`](/docs/errors/chain/SubnetLimitReached) | `register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable. | +| [`TooBig`](/docs/errors/chain/TooBig) | The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it. | +| [`TooMany`](/docs/errors/chain/TooMany) | A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`. | +| [`TooManyCalls`](/docs/errors/chain/TooManyCalls) | The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions. | +| [`TooManyChildren`](/docs/errors/chain/TooManyChildren) | `set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries. | +| [`TooManyFieldsInCommitmentInfo`](/docs/errors/chain/TooManyFieldsInCommitmentInfo) | The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit. | +| [`TooManyFreezes`](/docs/errors/chain/TooManyFreezes) | The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first. | +| [`TooManyHolds`](/docs/errors/chain/TooManyHolds) | The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another. | +| [`TooManyPendingExtrinsics`](/docs/errors/chain/TooManyPendingExtrinsics) | `store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire. | +| [`TooManyReserves`](/docs/errors/chain/TooManyReserves) | The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another. | +| [`TooManySignatories`](/docs/errors/chain/TooManySignatories) | The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant. | +| [`TooManyTopics`](/docs/errors/chain/TooManyTopics) | The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit. | +| [`TooManyUIDsPerMechanism`](/docs/errors/chain/TooManyUIDsPerMechanism) | Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit. | +| [`TooManyUnrevealedCommits`](/docs/errors/chain/TooManyUnrevealedCommits) | `commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again. | +| [`TrimmingWouldExceedMaxImmunePercentage`](/docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage) | Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target. | +| [`UidsLengthExceedUidsInSubNet`](/docs/errors/chain/UidsLengthExceedUidsInSubNet) | The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector. | +| [`ValueTooLarge`](/docs/errors/chain/ValueTooLarge) | A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant. | +| [`WeightExceedsAbsoluteMax`](/docs/errors/chain/WeightExceedsAbsoluteMax) | `set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant. | + +The same explanation is available in the terminal: `btcli explain limit_exceeded` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/meta.json b/docs/errors/meta.json new file mode 100644 index 0000000000..d760fdcc2b --- /dev/null +++ b/docs/errors/meta.json @@ -0,0 +1,25 @@ +{ + "title": "Errors", + "pages": [ + "index", + "insufficient-balance", + "insufficient-liquidity", + "rate-limited", + "not-registered", + "not-authorized", + "already-exists", + "not-found", + "subnet-not-exists", + "subtoken-disabled", + "disabled", + "too-early", + "expired", + "limit-exceeded", + "unit-mismatch", + "invalid-argument", + "policy-violation", + "internal", + "unknown", + "chain" + ] +} diff --git a/docs/errors/not-authorized.mdx b/docs/errors/not-authorized.mdx new file mode 100644 index 0000000000..424ad8359a --- /dev/null +++ b/docs/errors/not-authorized.mdx @@ -0,0 +1,45 @@ +--- +title: "not_authorized" +description: "Sign with the key or origin that owns the target object, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The signing key is not allowed to perform this call: the coldkey is not associated with the hotkey, the caller is not the subnet owner, the origin is filtered, a proxy lacks permission for this call type, or the call requires a root/sudo origin. + +Check which key actually owns the target object and sign with it. for proxy signing, the proxy type must permit the call; for subnet hyperparameters, the signer must be the subnet owner coldkey. + +## Remediation + +Sign with the key or origin that owns the target object, then retry + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `not_authorized`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`AccountNotAllowedCommit`](/docs/errors/chain/AccountNotAllowedCommit) | Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet. | +| [`BeneficiaryDoesNotOwnHotkey`](/docs/errors/chain/BeneficiaryDoesNotOwnHotkey) | When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns. | +| [`CallFiltered`](/docs/errors/chain/CallFiltered) | The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect. | +| [`CannotUseSystemAccount`](/docs/errors/chain/CannotUseSystemAccount) | The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`. | +| [`ColdkeySwapDisputed`](/docs/errors/chain/ColdkeySwapDisputed) | All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact. | +| [`CreateOriginNotAllowed`](/docs/errors/chain/CreateOriginNotAllowed) | A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list. | +| [`ExpectedBeneficiaryOrigin`](/docs/errors/chain/ExpectedBeneficiaryOrigin) | A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey. | +| [`InvalidOrigin`](/docs/errors/chain/InvalidOrigin) | The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`. | +| [`NeuronNoValidatorPermit`](/docs/errors/chain/NeuronNoValidatorPermit) | The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator. | +| [`NoPermission`](/docs/errors/chain/NoPermission) | The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments. | +| [`NonAssociatedColdKey`](/docs/errors/chain/NonAssociatedColdKey) | The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it. | +| [`NotAllowed`](/docs/errors/chain/NotAllowed) | Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value. | +| [`NotAuthorized`](/docs/errors/chain/NotAuthorized) | The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`. | +| [`NotOwner`](/docs/errors/chain/NotOwner) | Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash. | +| [`NotProxy`](/docs/errors/chain/NotProxy) | The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call. | +| [`NotSubnetOwner`](/docs/errors/chain/NotSubnetOwner) | The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`). | +| [`RequireSudo`](/docs/errors/chain/RequireSudo) | The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item. | +| [`StateChangeDenied`](/docs/errors/chain/StateChangeDenied) | The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context. | +| [`TransactionMustComeFromEOA`](/docs/errors/chain/TransactionMustComeFromEOA) | Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead. | +| [`TransactorAccountShouldBeHotKey`](/docs/errors/chain/TransactorAccountShouldBeHotKey) | The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin. | +| [`Unauthorized`](/docs/errors/chain/Unauthorized) | In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`. | +| [`Unproxyable`](/docs/errors/chain/Unproxyable) | The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call. | + +The same explanation is available in the terminal: `btcli explain not_authorized` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/not-found.mdx b/docs/errors/not-found.mdx new file mode 100644 index 0000000000..87b5e0e93d --- /dev/null +++ b/docs/errors/not-found.mdx @@ -0,0 +1,43 @@ +--- +title: "not_found" +description: "The referenced object is not on-chain; check the identifier" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The call references an object that is not on-chain: a weights commit, lease, multisig operation, scheduled call, announcement, or contribution that was never created, was already consumed, or has been removed. + +Check the identifier and the current chain state. if the flow has a create step (commit before reveal, announce before execute), make sure it completed on the network you are connected to (check `--network`). + +## Remediation + +The referenced object is not on-chain; check the identifier + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `not_found`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`CallUnavailable`](/docs/errors/chain/CallUnavailable) | During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet. | +| [`CodeInfoNotFound`](/docs/errors/chain/CodeInfoNotFound) | No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed. | +| [`CodeNotFound`](/docs/errors/chain/CodeNotFound) | No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed. | +| [`ColdkeySwapAnnouncementNotFound`](/docs/errors/chain/ColdkeySwapAnnouncementNotFound) | `coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first. | +| [`ContractNotFound`](/docs/errors/chain/ContractNotFound) | No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated. | +| [`DeadAccount`](/docs/errors/chain/DeadAccount) | The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs. | +| [`DelegateDependencyNotFound`](/docs/errors/chain/DelegateDependencyNotFound) | `unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info. | +| [`InvalidCrowdloanId`](/docs/errors/chain/InvalidCrowdloanId) | No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued. | +| [`LeaseDoesNotExist`](/docs/errors/chain/LeaseDoesNotExist) | The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated. | +| [`LeaseNetuidNotFound`](/docs/errors/chain/LeaseNetuidNotFound) | After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete. | +| [`NoContribution`](/docs/errors/chain/NoContribution) | The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question. | +| [`NoDeposit`](/docs/errors/chain/NoDeposit) | No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block. | +| [`NoExistingLock`](/docs/errors/chain/NoExistingLock) | move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey. | +| [`NoWeightsCommitFound`](/docs/errors/chain/NoWeightsCommitFound) | A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window. | +| [`NoneValue`](/docs/errors/chain/NoneValue) | Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization. | +| [`NotFound`](/docs/errors/chain/NotFound) | The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state. | +| [`NotNoted`](/docs/errors/chain/NotNoted) | The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored. | +| [`NotRequested`](/docs/errors/chain/NotRequested) | The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`. | +| [`NothingAuthorized`](/docs/errors/chain/NothingAuthorized) | No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code. | +| [`SymbolDoesNotExist`](/docs/errors/chain/SymbolDoesNotExist) | The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry. | + +The same explanation is available in the terminal: `btcli explain not_found` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/not-registered.mdx b/docs/errors/not-registered.mdx new file mode 100644 index 0000000000..8636735614 --- /dev/null +++ b/docs/errors/not-registered.mdx @@ -0,0 +1,27 @@ +--- +title: "not_registered" +description: "Register the hotkey on this subnet first with `btcli subnets register`" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The hotkey is not registered where the call expects it to be: either not on the specific subnet, or not anywhere on the network. + +Many calls (serving an axon, setting weights, some stake operations) require the hotkey to hold a UID on the target subnet. register it first with `btcli subnets register --netuid N`, or check where it is registered with `btcli view` commands. + +## Remediation + +Register the hotkey on this subnet first with `btcli subnets register` + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `not_registered`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`HotKeyAccountNotExists`](/docs/errors/chain/HotKeyAccountNotExists) | The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first. | +| [`HotKeyNotRegisteredInNetwork`](/docs/errors/chain/HotKeyNotRegisteredInNetwork) | The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first. | +| [`HotKeyNotRegisteredInSubNet`](/docs/errors/chain/HotKeyNotRegisteredInSubNet) | The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed. | +| [`PalletHotkeyNotRegistered`](/docs/errors/chain/PalletHotkeyNotRegistered) | Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs. | + +The same explanation is available in the terminal: `btcli explain not_registered` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/policy-violation.mdx b/docs/errors/policy-violation.mdx new file mode 100644 index 0000000000..08419e5bfb --- /dev/null +++ b/docs/errors/policy-violation.mdx @@ -0,0 +1,20 @@ +--- +title: "policy_violation" +description: "The action exceeds a configured safety policy" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The action was blocked locally by a configured safety policy before reaching the chain. + +Policies cap what a session is allowed to do (spend limits, allowed operations). this is a deliberate guardrail: if the action is intended, raise or remove the relevant policy limit in your configuration and rerun. + +## Remediation + +The action exceeds a configured safety policy + +## Chain errors + +No chain error classifies to this code — it is raised client-side by the SDK before or after the call reaches the chain. + +The same explanation is available in the terminal: `btcli explain policy_violation` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/rate-limited.mdx b/docs/errors/rate-limited.mdx new file mode 100644 index 0000000000..4113d2d7f3 --- /dev/null +++ b/docs/errors/rate-limited.mdx @@ -0,0 +1,40 @@ +--- +title: "rate_limited" +description: "Wait for the rate-limit window to pass, then retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The chain enforces per-key rate limits on certain calls (registration, weight setting, stake movement, child hotkey changes) to keep the network stable. + +The limit is measured in blocks since the same key last performed the same kind of call, so retrying immediately will fail with the same error. wait for the window to pass (typically a few blocks to a few hundred blocks depending on the call), then retry. + +## Remediation + +Wait for the rate-limit window to pass, then retry + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `rate_limited`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`AddStakeBurnRateLimitExceeded`](/docs/errors/chain/AddStakeBurnRateLimitExceeded) | The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes. | +| [`CommittingWeightsTooFast`](/docs/errors/chain/CommittingWeightsTooFast) | The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait. | +| [`DelegateTxRateLimitExceeded`](/docs/errors/chain/DelegateTxRateLimitExceeded) | The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later. | +| [`EvmKeyAssociateRateLimitExceeded`](/docs/errors/chain/EvmKeyAssociateRateLimitExceeded) | `associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later. | +| [`HotKeySetTxRateLimitExceeded`](/docs/errors/chain/HotKeySetTxRateLimitExceeded) | The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks. | +| [`HotKeySwapOnSubnetIntervalNotPassed`](/docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed) | A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval. | +| [`NetworkTxRateLimitExceeded`](/docs/errors/chain/NetworkTxRateLimitExceeded) | The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks. | +| [`ServingRateLimitExceeded`](/docs/errors/chain/ServingRateLimitExceeded) | `serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait. | +| [`SettingWeightsTooFast`](/docs/errors/chain/SettingWeightsTooFast) | The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks. | +| [`SpaceLimitExceeded`](/docs/errors/chain/SpaceLimitExceeded) | The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage. | +| [`StakingRateLimitExceeded`](/docs/errors/chain/StakingRateLimitExceeded) | Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block. | +| [`SubnetBuybackRateLimitExceeded`](/docs/errors/chain/SubnetBuybackRateLimitExceeded) | A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback. | +| [`TooManyRegistrationsThisBlock`](/docs/errors/chain/TooManyRegistrationsThisBlock) | Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block. | +| [`TooManyRegistrationsThisInterval`](/docs/errors/chain/TooManyRegistrationsThisInterval) | Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start. | +| [`TooSoon`](/docs/errors/chain/TooSoon) | A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change. | +| [`TxChildkeyTakeRateLimitExceeded`](/docs/errors/chain/TxChildkeyTakeRateLimitExceeded) | `set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder. | +| [`TxRateLimitExceeded`](/docs/errors/chain/TxRateLimitExceeded) | An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass. | + +The same explanation is available in the terminal: `btcli explain rate_limited` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/subnet-not-exists.mdx b/docs/errors/subnet-not-exists.mdx new file mode 100644 index 0000000000..8b83d8f7cb --- /dev/null +++ b/docs/errors/subnet-not-exists.mdx @@ -0,0 +1,27 @@ +--- +title: "subnet_not_exists" +description: "Use an existing netuid; `btcli subnets list` shows valid ones" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The netuid does not name an existing subnet on this network. + +Netuids are not stable across networks: a subnet that exists on finney may not exist on testnet. `btcli subnets list` shows the valid netuids for the network you are connected to (check `--network`). + +## Remediation + +Use an existing netuid; `btcli subnets list` shows valid ones + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `subnet_not_exists`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`MechanismDoesNotExist`](/docs/errors/chain/MechanismDoesNotExist) | The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet. | +| [`RootNetworkDoesNotExist`](/docs/errors/chain/RootNetworkDoesNotExist) | Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`. | +| [`SubnetDoesNotExist`](/docs/errors/chain/SubnetDoesNotExist) | The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters. | +| [`SubnetNotExists`](/docs/errors/chain/SubnetNotExists) | The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved. | + +The same explanation is available in the terminal: `btcli explain subnet_not_exists` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/subtoken-disabled.mdx b/docs/errors/subtoken-disabled.mdx new file mode 100644 index 0000000000..95c306cf46 --- /dev/null +++ b/docs/errors/subtoken-disabled.mdx @@ -0,0 +1,24 @@ +--- +title: "subtoken_disabled" +description: "The subnet is not active yet; wait for start_call" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The subnet exists but its token operations are not enabled yet. + +A newly registered subnet starts inactive: staking, unstaking, and other alpha operations are rejected until the subnet owner activates it with start_call. there is nothing to fix on your side; wait for the subnet to become active. + +## Remediation + +The subnet is not active yet; wait for start_call + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `subtoken_disabled`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`SubtokenDisabled`](/docs/errors/chain/SubtokenDisabled) | The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved. | + +The same explanation is available in the terminal: `btcli explain subtoken_disabled` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/too-early.mdx b/docs/errors/too-early.mdx new file mode 100644 index 0000000000..53d6adaf9f --- /dev/null +++ b/docs/errors/too-early.mdx @@ -0,0 +1,41 @@ +--- +title: "too_early" +description: "The required window has not opened yet; wait some blocks and retry" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The call arrived before its window opened: a reveal before the reveal period, a coldkey swap before its delay elapsed, a start_call before enough blocks passed, or a finalization before the period ended. + +Unlike rate_limited this is not about calling too often — the flow has a built-in waiting period that has not elapsed yet. wait the required blocks and retry; the chain state (announcement block, commit block) tells you how long is left. + +## Remediation + +The required window has not opened yet; wait some blocks and retry + +## Chain errors + +The exact chain error names (from the extrinsic receipt) that classify to `too_early`; the description says what triggered the failure and where to check. Each name has its own page: + +| Chain error | Description | +| --- | --- | +| [`AdminActionProhibitedDuringWeightsWindow`](/docs/errors/chain/AdminActionProhibitedDuringWeightsWindow) | An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires. | +| [`AllNetworksInImmunity`](/docs/errors/chain/AllNetworksInImmunity) | Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity. | +| [`CannotReleaseYet`](/docs/errors/chain/CannotReleaseYet) | `release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config. | +| [`CapNotRaised`](/docs/errors/chain/CapNotRaised) | `finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing. | +| [`ColdkeySwapClearTooEarly`](/docs/errors/chain/ColdkeySwapClearTooEarly) | The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later. | +| [`ColdkeySwapReannouncedTooEarly`](/docs/errors/chain/ColdkeySwapReannouncedTooEarly) | `announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later. | +| [`ColdkeySwapTooEarly`](/docs/errors/chain/ColdkeySwapTooEarly) | `coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then. | +| [`ContributionPeriodNotEnded`](/docs/errors/chain/ContributionPeriodNotEnded) | The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number. | +| [`LeaseHasNotEnded`](/docs/errors/chain/LeaseHasNotEnded) | The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes. | +| [`MigrationInProgress`](/docs/errors/chain/MigrationInProgress) | A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it. | +| [`MultiBlockMigrationsOngoing`](/docs/errors/chain/MultiBlockMigrationsOngoing) | Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade. | +| [`NeedWaitingMoreBlocksToStarCall`](/docs/errors/chain/NeedWaitingMoreBlocksToStarCall) | The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens. | +| [`NotReadyToDissolve`](/docs/errors/chain/NotReadyToDissolve) | `dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record. | +| [`PriceConditionNotMet`](/docs/errors/chain/PriceConditionNotMet) | The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field. | +| [`RevealTooEarly`](/docs/errors/chain/RevealTooEarly) | A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch. | +| [`StartCallNotReady`](/docs/errors/chain/StartCallNotReady) | `start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder. | +| [`Unannounced`](/docs/errors/chain/Unannounced) | The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`. | +| [`WaitingForDissolvedSubnetCleanup`](/docs/errors/chain/WaitingForDissolvedSubnetCleanup) | The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes. | + +The same explanation is available in the terminal: `btcli explain too_early` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/unit-mismatch.mdx b/docs/errors/unit-mismatch.mdx new file mode 100644 index 0000000000..980cf3eadd --- /dev/null +++ b/docs/errors/unit-mismatch.mdx @@ -0,0 +1,22 @@ +--- +title: "unit_mismatch" +description: "Match the Balance netuid to the operation's currency" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +Two amounts denominated in different currencies were combined. + +Every Balance carries the netuid whose currency it denominates: netuid 0 is TAO, any other netuid is that subnet's alpha. arithmetic between different netuids raises instead of silently mixing currencies, because 1 alpha on one subnet is not worth 1 alpha on another. + +Construct the amount in the operation's own currency: Balance.from_tao for TAO, Balance.from_alpha(amount, netuid) for a subnet's alpha. + +## Remediation + +Match the Balance netuid to the operation's currency + +## Chain errors + +No chain error classifies to this code — it is raised client-side by the SDK before or after the call reaches the chain. + +The same explanation is available in the terminal: `btcli explain unit_mismatch` (or `btcli explain ` for one exact chain error). diff --git a/docs/errors/unknown.mdx b/docs/errors/unknown.mdx new file mode 100644 index 0000000000..a5ee0d9e41 --- /dev/null +++ b/docs/errors/unknown.mdx @@ -0,0 +1,20 @@ +--- +title: "unknown" +description: "Inspect the message for details" +--- + +{/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} + +The error did not match any known chain error name or message pattern. + +The original message is preserved in the diagnostic; read it for details. if it names a chain error that should be classified, the mapping lives in bittensor/error_map.py. + +## Remediation + +Inspect the message for details + +## Chain errors + +No chain error classifies to this code — it is raised client-side by the SDK before or after the call reaches the chain. + +The same explanation is available in the terminal: `btcli explain unknown` (or `btcli explain ` for one exact chain error). diff --git a/docs/guides/meta.json b/docs/guides/meta.json index d6e6eb4a05..1b6cf847ed 100644 --- a/docs/guides/meta.json +++ b/docs/guides/meta.json @@ -1,4 +1,4 @@ { "title": "Guides", - "pages": ["staking", "conviction", "mining", "validating", "subnets", "signed-requests", "extension-signing", "ledger", "evm", "local-development", "running-a-node", "timelock"] + "pages": ["staking", "conviction", "mining", "validating", "subnets", "multisig", "proxies", "signed-requests", "extension-signing", "ledger", "evm", "local-development", "running-a-node", "timelock"] } diff --git a/docs/guides/multisig.mdx b/docs/guides/multisig.mdx new file mode 100644 index 0000000000..0bee079988 --- /dev/null +++ b/docs/guides/multisig.mdx @@ -0,0 +1,421 @@ +--- +title: Multisig wallets +description: Put a coldkey under M-of-N control so no single stolen or lost key can move your funds. +--- + +A single coldkey is a single point of failure. If it leaks — a compromised +laptop, a phished mnemonic, a malicious dependency — everything it holds is +gone, irreversibly: subnet ownership, stake, free balance. A **multisig** +removes that single point of failure by deriving an account address from a +*set* of coldkeys plus a **threshold**: a call only executes from that account +once `M` of the `N` signatories have approved it. + +Conventionally written "M-of-N": a 2-of-3 multisig has three member keys and +requires any two of them to sign. That protects you in both directions — + +* **Compromise:** an attacker with one stolen key can open an operation but + cannot execute anything. You see the pending approval and simply never + co-sign it. +* **Loss:** with 2-of-3, losing any one key loses nothing. The remaining two + can move the funds to a new account. + +The signatories can be separate people (a subnet team's treasury) or separate +keys held by one person on separate machines (your own coldkey, hardened). +Nobody holds "the multisig key" — no such key exists. The address is pure math +over the member set and threshold. + +## How it works + +The multisig address is derived deterministically from the sorted signatory +set and the threshold. The same three keys with threshold 2 always produce the +same address, on any machine, with no on-chain registration step. + +Spending is an approval round: + +1. One signatory **opens** an operation by submitting the full call + ([`multisig-execute`](/docs/tx/multisig-execute)) or its approval + ([`multisig-approve`](/docs/tx/multisig-approve)) with no timepoint. This + reserves a deposit from the opener (returned on execution or cancellation) + and records the operation on-chain under the hash of the call. +2. Other signatories approve, quoting the **timepoint** (block height and + extrinsic index) of the opening approval. Every approval must describe the + identical call, threshold, and signatory set — the chain matches by hash. +3. Whoever brings the count to `threshold` must submit + [`multisig-execute`](/docs/tx/multisig-execute) with the full call, which + then dispatches *as the multisig account* in the same extrinsic. + +Two consequences worth internalizing: the inner call's arguments must be fully +explicit (it runs as the multisig, not as any signer's wallet), and because +the address is derived from the member set, **changing membership changes the +address**. If a signer leaves the team you must create a new multisig and move +the funds — unless you make the members [pure proxies](/docs/guides/proxies) +instead of raw coldkeys, which lets you swap the human behind a member slot +without changing the multisig address. + +## Prerequisites + +```bash +uv venv && source .venv/bin/activate +uv pip install bittensor +``` + +One install gives you both `btcli` and the Python SDK. Practice on testnet +(`-n test` on every command, or `btcli config set network test`) with test TAO +before touching mainnet. Each *signatory* needs a little TAO for fees and the +opener's deposit; the multisig account itself holds the actual funds. + +## Step 1 — the signatory keys + +For this walkthrough, a 2-of-3 with wallets `alice`, `bob`, and `carol`. In +production these live on different machines owned by different people; each +person only ever holds their own coldkey. + +```bash +btcli wallet create -w alice # repeat for bob and carol (on their machines) +``` + +Signers who are other people are just addresses to you — save them in the +address book so every later command can use names instead of raw ss58: + +```bash +btcli addresses add bob 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty +btcli addresses add carol 5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy +btcli addresses list +``` + +## Step 2 — save the signer set and derive the address + +`btcli multisig add` stores a named signer set in your local multisig book and +derives the on-chain address. Signatories can be wallet names, address-book +names, or raw ss58 — order doesn't matter. + +```bash +btcli multisig add team-treasury --threshold 2 --signatories alice,bob,carol +btcli multisig show team-treasury # derives and prints the multisig address +btcli multisig list # all saved signer sets +btcli wallet list # multisigs appear alongside wallets on disk +``` + +The book entry is purely local convenience — every signer should run the same +`multisig add` on their own machine (same members, same threshold) and confirm +`multisig show` prints the **same address**. If it doesn't, someone has a +wrong member list, and funds sent there would belong to a different account. + +In Python, the same derivation: + +```python +import bittensor as sub + +async with sub.Client("test") as client: + ms = await client.multisig( + ["5Grw...alice", "5FHn...bob", "5DAA...carol"], + threshold=2, + ) + print(ms.address) # deterministic in the set + threshold +``` + +## Step 3 — fund and watch it + +Send TAO to the derived address like any other account: + +```bash +btcli addresses add team-treasury-addr 5Fmulti...sigAddress +btcli tx transfer --dest team-treasury-addr --amount-tao 100 -w alice +``` + +Balances and every other [query](/docs/query) work on the address directly — +no key needed for reads: + +```bash +btcli query balance --coldkey team-treasury-addr +``` + +Optionally register it as a watch-only wallet (public key only, no secrets), +so wallet-flavored commands work by name: + +```bash +btcli wallet regen-coldkeypub -w team-treasury --ss58 5Fmulti...sigAddress +btcli wallet balance team-treasury +``` + +## Step 4 — spend: open the operation + +Alice proposes paying 10 TAO out of the treasury. The inner call is an intent +spec — `{"op": , ...args}`, same shape as a batch child — with +fully explicit arguments. As always, `--dry-run` previews fee and effects +without submitting: + +```bash +btcli tx multisig-execute \ + --threshold 2 \ + --other-signatories bob,carol \ + --call '{"op": "transfer", "dest_ss58": "5DevPayee...", "amount_tao": 10}' \ + -w alice --dry-run + +btcli tx multisig-execute \ + --threshold 2 \ + --other-signatories bob,carol \ + --call '{"op": "transfer", "dest_ss58": "5DevPayee...", "amount_tao": 10}' \ + -w alice +``` + +`--other-signatories` lists every member *except* the signer; the CLI adds +Alice's coldkey and sorts the set. Since no timepoint was passed, this opens +the operation: Alice's deposit is reserved, and nothing executes yet. + +After submission the CLI prints the operation's `call_hash`, `call_data`, the +opening `timepoint`, and **ready-to-run commands for each remaining +co-signer** — copy-paste them to Bob and Carol over your team channel. The +opening extrinsic embeds the full call, so co-signers can also recover +everything from chain state alone (next step); no out-of-band call data is +required. + +## Step 5 — view pending operations + +Any signer can inspect what's awaiting approval. With the saved multisig book +entry: + +```bash +btcli multisig pending --multisig team-treasury -w bob +``` + +This lists every open operation on the multisig account with its target call, +decoded parameters, approval count, who has signed, who hasn't, the timepoint, +and a copy-paste command for each remaining co-signer. Filter to one operation +with `--call-hash 0x...`; if the call details can't be decoded locally (e.g. +the opening block is pruned on your RPC node), pass the `call_data` hex once +with `--call-data 0x...`. + +The raw chain state is also one query away: + +```bash +btcli query multisig --account team-treasury-addr --call-hash 0x... --json +``` + +which returns the pending operation's timepoint (`when`), the approvals so +far, the depositor, and the reserved deposit. **Check `pending` on a +schedule.** An operation you don't recognize means a member key is +compromised — don't co-sign, and rotate that member out. + +## Step 6 — approve and execute + +Bob was handed a ready-to-run command by `pending` (or by Alice). Because his +approval is the one that reaches the threshold, it must be +`multisig-execute` with the full call — the chain needs the call to run it. +The timepoint identifies the pending operation: + +```bash +btcli tx multisig-execute \ + --threshold 2 \ + --other-signatories alice,carol \ + --call '{"op": "transfer", "dest_ss58": "5DevPayee...", "amount_tao": 10}' \ + --timepoint '{"height": 5951841, "index": 6}' \ + -w bob +``` + +The transfer executes as the multisig account in this same extrinsic, and +Alice's deposit is returned. + +In a wider set (say 3-of-5), the signers *between* the first and the last can +use [`multisig-approve`](/docs/tx/multisig-approve) instead — it records +consent by hash only, which stays cheap even for huge calls, but never +executes. Opening approval: omit the timepoint. Intermediate approvals: pass +it. Last signer: always `multisig-execute` with the full call. + +## 1-of-N: shared access without approval rounds + +A threshold-1 multisig lets any single member act alone — useful as a shared +operational account where you still want membership to be explicit and +auditable. No approval round, timepoint, or deposit: + +```bash +btcli tx multisig-threshold-1 \ + --other-signatories bob,carol \ + --call '{"op": "transfer", "dest_ss58": "5DevPayee...", "amount_tao": 1}' \ + -w alice +``` + +Note that 1-of-N adds *no* compromise protection — any one stolen member key +spends. Use threshold ≥ 2 for security. See +[`multisig-threshold-1`](/docs/tx/multisig-threshold-1). + +## Cancel a pending operation + +Only the signatory who opened the operation (and paid the deposit) can cancel +it, which discards the stored approvals and returns the deposit. Threshold, +signatory set, call, and timepoint must all match exactly: + +```bash +btcli tx multisig-cancel \ + --threshold 2 \ + --other-signatories bob,carol \ + --call '{"op": "transfer", "dest_ss58": "5DevPayee...", "amount_tao": 10}' \ + --timepoint '{"height": 5951841, "index": 6}' \ + -w alice +``` + +If the *opener's* key is the compromised one, the honest members can't cancel +— but they don't need to: an operation below threshold never executes, and +the attacker's deposit stays locked until they cancel it themselves. Just +never co-sign it, and move the funds to a fresh multisig without the bad key. +See [`multisig-cancel`](/docs/tx/multisig-cancel). + +## Migrate an existing account to a multisig + +If the account you want to protect already exists — a subnet owner's coldkey +especially — funding the multisig is **not** a migration. A +[`transfer`](/docs/tx/transfer) moves transferable TAO and nothing else: +stake, conviction locks, hotkey registrations, and subnet ownership are +separate on-chain state that stays with the old coldkey. +([`transfer-stake`](/docs/tx/transfer-stake) moves a stake position, but +still not ownership.) The tool that moves *everything* is the announced +**coldkey swap**: + +```bash +# 1. Verify the destination first: every member derives the same address, +# and it must be a completely unused account — no balance history, stake, +# hotkeys, or locks. +btcli multisig show team-treasury + +# 2. Announce, committing to the multisig address. Costs 0.1 TAO and locks +# the old coldkey for the chain's delay (36,000 blocks, ~5 days) — only +# swap-related calls go through while it's pending. +btcli tx announce-coldkey-swap --new-coldkey 5Fmulti...sigAddress -w old-owner + +# 3. After the delay, execute. Balance, stake, locks, hotkeys, registrations, +# and subnet ownership all move to the multisig. Irreversible. +btcli tx swap-coldkey-announced --new-coldkey 5Fmulti...sigAddress -w old-owner +``` + +The delay exists so the real owner can catch a thief's announcement +([`dispute-coldkey-swap`](/docs/tx/dispute-coldkey-swap) freezes the key); +check a pending one with the +[`coldkey-swap-announcement`](/docs/query/coldkey-swap-announcement) read. +After the swap, every owner action goes through the multisig approval round — +for routine operations like hyperparameter changes, grant a scoped proxy from +the multisig instead (next section). + +## Day-to-day operations: pair it with a proxy + +An approval round for every hyperparameter tweak gets old fast. The standard +layering keeps the multisig as the high-impact control plane and delegates +the routine work: from the multisig, grant an operations key a narrowly +scoped [proxy](/docs/guides/proxies) — `Owner` for a subnet owner's identity +and hyperparameter calls, `Staking` for a treasury that manages positions. +The grant itself is just an inner call in the usual round: + +```bash +btcli tx multisig-execute \ + --threshold 2 \ + --other-signatories bob,carol \ + --call '{"op": "add_proxy", "delegate_ss58": "5F...opsKey", "proxy_type": "Owner", "delay": 0}' \ + -w alice +``` + +The ops key now handles routine changes alone (`--proxy-for` the multisig +address), but cannot transfer funds or rotate the owner — and if it leaks, +the multisig convenes once to revoke it (`{"op": "remove_proxy", ...}`) while +the principal never moves. The full pattern is in the +[proxy guide](/docs/guides/proxies). + +## Any call, including sudo: `btcli call --multisig` + +The `tx multisig-*` intents cover calls that have intents. For anything else — +raw pallet calls, or a chain whose sudo key is a multisig — the raw-call +escape hatch takes the same multisig flags: + +```bash +btcli call SubtensorModule.some_call --args '{"netuid": 3}' \ + --multisig team-treasury -w alice --yes +``` + +`--multisig NAME` pulls the threshold and signer set from your multisig book +(inline `--multisig-threshold 2 --other-signatories bob,carol` works too, and +`--sudo` wraps the call in `Sudo.sudo`). After each approval the CLI prints +`call_hash`, `call_data`, the timepoint, and the exact command for each +remaining co-signer — the same flow as above, for any call the chain exposes. + +## The SDK + +The high-level handle wraps the whole round. Each signatory calls `approve` +with the identical call; the approval that reaches the threshold executes it +and returns the inner call's events: + +```python +import bittensor as sub +from bittensor.wallet import Wallet + +async with sub.Client("test") as client: + ms = await client.multisig( + ["5Grw...alice", "5FHn...bob", "5DAA...carol"], + threshold=2, + ) + + call = sub.calls.Balances.transfer_keep_alive( + dest="5DevPayee...", + value=10 * 10**9, # raw calls take rao (1 TAO = 1e9 rao) + ) + + # on Alice's machine — opens the operation + result = await ms.approve(call, Wallet(name="alice")) + + # on Bob's machine — same call, reaches threshold, executes + result = await ms.approve(call, Wallet(name="bob")) + print(result.success, result.block_hash) +``` + +For the intent-shaped flow (human-unit arguments, `plan` preview, explicit +timepoints), the `Multisig*` intents mirror the CLI exactly: + +```python +intent = sub.MultisigExecute( + threshold=2, + other_signatories=["5FHn...bob", "5DAA...carol"], + call={"op": "transfer", "dest_ss58": "5DevPayee...", "amount_tao": 10}, + # timepoint={"height": ..., "index": ...} on every approval after the first +) +plan = await client.plan(intent, wallet) # fee, effects — nothing submitted +result = await client.execute(intent, wallet) +``` + +`sub.MultisigApprove`, `sub.MultisigCancel`, and `sub.MultisigThreshold1` are +the other three, and the executing approval surfaces `multisig_call_hash` and +`multisig_call_data` in `result.data`. Inspect pending state with the read: + +```python +pending = await client.read("multisig", account_ss58=ms.address, call_hash="0x...") +# → timepoint (when), approvals so far, depositor, reserved deposit +``` + +## Deposits and limits + +* Opening a pending operation reserves **0.132 TAO base + 0.032 TAO per unit + of threshold** from the opener, returned on execution or cancellation. +* A multisig can have at most **100 signatories**. +* Approving twice from the same signer, or with a mismatched timepoint, + threshold, or signatory set, fails — the (set, threshold, call-hash) triple + is the operation's identity. + +## Operating it safely + +* **Threshold ≥ 2, always, for anything valuable.** M=1 is a convenience + account, not a security boundary. 2-of-3 is the usual sweet spot: survives + one lost key *and* one stolen key. +* **Independent keys.** Signatories on the same laptop defeat the point. Give + each member key its own machine, and consider signing with a + [Ledger](/docs/guides/ledger) (`--ledger`) or a + [browser extension](/docs/guides/extension-signing) (`--signer extension`) + so member coldkeys never sit on the machine running `btcli` at all. +* **Verify the address independently.** Every member derives it themselves + (`btcli multisig show`) before anyone funds it. +* **Watch `pending`.** A pending operation nobody proposed is your compromise + alarm, and it fires *before* any funds move — that early warning is half + the value of a multisig. Check it on a schedule, or script it with + `--json`. +* **Verify before you co-sign.** The `pending` output decodes the target and + parameters — read them. Your approval is the security boundary. +* **Plan for membership change.** Swapping a member means a new address and a + funds migration, unless members are [pure proxies](/docs/guides/proxies) + with swappable controllers behind them. +* **Test the full round on testnet** — open, view, approve, cancel — before + moving real funds. Fees and deposits behave identically. diff --git a/docs/guides/proxies.mdx b/docs/guides/proxies.mdx new file mode 100644 index 0000000000..6855b64767 --- /dev/null +++ b/docs/guides/proxies.mdx @@ -0,0 +1,393 @@ +--- +title: Proxy accounts +description: Keep the coldkey offline and do daily work through scoped, revocable, optionally delayed delegate keys. +--- + +Every coldkey that sits on a working machine is one compromise away from a +total loss — and the loss is irreversible: nobody can claw back a drained +wallet. The **proxy** pallet exists so the coldkey holding your funds never +has to be that key. You register a *delegate* key that may sign on the real +account's behalf, scoped to a class of operations (**proxy type**) and +optionally forced through a time delay you can veto. The valuable key goes to +cold storage; the key that lives on your laptop or server is a limited, +revocable stand-in. + +What this buys you: + +* **Blast-radius control.** A leaked `Staking` proxy can shuffle your stake; + it cannot transfer a single TAO out. Revoke it, rotate, move on — your + principal never moved. +* **A veto window.** A delegation with `delay > 0` must announce each call + and wait; the real account can reject anything it doesn't recognize before + it executes. +* **An offline primary.** After a one-time setup, day-to-day operations never + need the primary coldkey on any networked machine. + +The related **pure proxy** is an account *nobody* has a key for — the chain +derives a fresh address controlled only through proxy relationships. Useful as +disposable role accounts and as swappable members of a +[multisig](/docs/guides/multisig). + +## How it works + +The real account signs [`add-proxy`](/docs/tx/add-proxy) once, naming a +delegate, a proxy type, and a delay. From then on the delegate submits +ordinary calls wrapped in `Proxy.proxy(real, ...)` — the CLI flag for this is +`--proxy-for`, the SDK keyword is `proxy_for=` — and the runtime checks each +call against the delegation's type before dispatching it *as the real +account*. Bookkeeping is paid with reserved deposits (returned on removal), +not fees. + +### Proxy types + +Prefer the narrowest type that covers the job: + +* **Any** — everything, including transfers. Avoid: leaking an `Any` proxy is + exactly as bad as leaking the coldkey. +* **NonTransfer** — everything *except* balance transfers, stake transfers, + and coldkey swaps. Notably it can manage the account's other proxies, which + makes it the natural "manager" proxy. +* **Transfer** — balance transfers and `transfer_stake` only. + **SmallTransfer** is the same but caps each transfer below 0.5 TAO + (0.5 alpha for stake transfers). +* **Staking** — stake add / remove / move / swap / unstake-all and their + limit variants, plus `set_root_claim_type`. Its allowlist does *not* + include `Utility.batch_all`, so batched staking through a Staking proxy + fails with `CallFiltered` — use NonTransfer for batched staking. +* **Registration** — neuron registration (`burned_register`, `register`, + `register_limit`). +* **ChildKeys** — `set_children` and `set_childkey_take`; + **RootClaim** — `claim_root` only. +* **Owner** — subnet-owner admin calls; **NonCritical** — everything except + registrations, coldkey swaps, and subnet dissolution; + **SubnetLeaseBeneficiary** — the lease-scoped subset of owner calls. + +`Triumvirate`, `Senate`, `Governance`, and `RootWeights` are deprecated on the +current runtime — they deny all calls. + +## Prerequisites + +```bash +uv venv && source .venv/bin/activate +uv pip install bittensor +``` + +One install gives you both `btcli` and the Python SDK. Practice on testnet +(`-n test` on every command, or `btcli config set network test`) before +mainnet. Two wallets for the walkthrough: + +* `safe` — the real account holding the funds. Its coldkey is the crown + jewel; on mainnet it should live in a hardware wallet or on an air-gapped + machine. +* `ops` — the delegate that will do daily work. Its coldkey lives on your + working machine and needs a little TAO for transaction fees. + +```bash +btcli wallet create -w safe +btcli wallet create -w ops +``` + +## Step 1 — grant the delegation + +The real account signs the grant — this is the one step that needs the `safe` +coldkey. Give `ops` staking powers with no delay: + +```bash +btcli proxy add --delegate ops --proxy-type Staking --delay 0 -w safe +``` + +`--delegate` accepts a wallet name, address-book name, or raw ss58. The same +operation exists as the [`add-proxy`](/docs/tx/add-proxy) intent +(`btcli tx add-proxy`), with `--dry-run` to preview the fee and reserved +deposit first. Multiple delegations can exist between the same pair of +accounts as long as each uses a different proxy type. + +**Keep the coldkey off this machine anyway.** The CLI can sign this grant on +a [Ledger](/docs/guides/ledger) (`--ledger`) or in a +[browser extension](/docs/guides/extension-signing) (`--signer extension` +with Talisman, Polkadot.js, SubWallet, ...), so even the initial `add-proxy` +never puts the `safe` mnemonic on a networked box: + +```bash +btcli proxy add --delegate ops --proxy-type Staking -w safe --ledger +``` + +After the first grant, a `NonTransfer` proxy can add and remove the account's +other proxies — so the primary coldkey is only ever needed once (see +[the recommended architecture](#a-recommended-architecture) below). + +## Step 2 — view delegations + +Straight from chain state — who may sign for the account, with what scope, +delay, and reserved deposit: + +```bash +btcli proxy list --coldkey safe +btcli query proxies --coldkey safe --json # same read, machine-readable +``` + +```python +import bittensor as sub + +async with sub.Client("test") as client: + delegations = await client.balances.proxies(coldkey_ss58="5F...safe") +``` + +For proxies you use often — especially ones on other machines or pure proxies +— the local **proxy book** gives them names that every `--proxy-for` and +address argument resolves: + +```bash +btcli proxy book add --name safe-staking --address 5F...ops \ + --proxy-type Staking --delay 0 --note "daily staking ops" +btcli proxy book list +``` + +(`update`, `remove`, and `clear` complete the group.) + +## Step 3 — act through the proxy + +Every `btcli tx` command takes `--proxy-for`. The wallet you sign with (`-w`) +is the *delegate*; `--proxy-for` names the *real account* being acted for: + +```bash +btcli tx add-stake --hotkey 5F...validator --netuid 1 --amount-tao 25 \ + -w ops --proxy-for safe --dry-run + +btcli tx add-stake --hotkey 5F...validator --netuid 1 --amount-tao 25 \ + -w ops --proxy-for safe +``` + +The stake moves from the `safe` account's balance; the `safe` coldkey was +never touched. `--force-proxy-type Staking` additionally requires the +delegation used to be exactly that type. In Python it's one keyword on +`execute`: + +```python +from bittensor.wallet import Wallet + +ops = Wallet(name="ops") + +async with sub.Client("test") as client: + intent = sub.AddStake(hotkey_ss58="5F...validator", netuid=1, amount_tao=25) + result = await client.execute(intent, ops, proxy_for="5F...safe") + if not result.success: + print(result.error.code, result.error.remediation) +``` + +A call outside the delegation's scope fails with `Unproxyable` / +`CallFiltered` — the runtime filter, not the CLI, is what enforces the scope. + +## Step 4 — delayed proxies: announce, wait, execute, veto + +For higher-risk powers, add a delay (in blocks; one block ≈ 12 seconds, so +300 blocks ≈ 1 hour). The delegate must then announce each call's hash and +wait out the delay before executing — and during that window the real account +(or its NonTransfer proxy) can veto: + +```bash +btcli proxy add --delegate ops --proxy-type Transfer --delay 300 -w safe +``` + +**Announce.** Announcing publishes the hash of the intended call +(blake2-256 of its SCALE encoding). Compose the call to get its hash, then +submit `Proxy.announce` as the delegate — via the raw-call escape hatch on +the CLI, or `submit_call` in Python: + +```python +ops = Wallet(name="ops") + +async with sub.Client("test") as client: + call = sub.calls.Balances.transfer_keep_alive( + dest="5DevPayee...", + value=10 * 10**9, # raw calls take rao (1 TAO = 1e9 rao) + ) + composed = await client.compose(call) + call_hash = "0x" + bytes(composed.call_hash).hex() + + await client.submit_call( + sub.calls.Proxy.announce(real="5F...safe", call_hash=call_hash), ops + ) +``` + +**Execute after the delay.** The announced call is rebuilt with byte-identical +parameters — anything else hashes differently and matches no announcement. +The convenient form takes an intent op and its args: + +```bash +btcli proxy execute \ + --delegate ops --real safe \ + --inner-op transfer \ + --inner-args '{"dest_ss58": "5DevPayee...", "amount_tao": 10}' \ + -w ops +``` + +(the same operation as the +[`execute-proxy-announced`](/docs/tx/execute-proxy-announced) intent, also +reachable as `btcli tx execute-proxy-announced` or `sub.ExecuteProxyAnnounced` +in Python). Executing before the delay elapses fails with `Unannounced`. + +**Monitor and veto.** A delay only protects you if you *watch* — check +pending announcements on a schedule shorter than the delay, otherwise the +window is only forensic. Announcements are keyed by delegate in the +`Proxy.Announcements` storage map: + +```python +async with sub.Client("test") as client: + for delegate, value in await client.query_map(sub.storage.Proxy.Announcements): + announcements, _deposit = value + for ann in announcements: + if str(ann["real"]) == "5F...safe": + print(delegate, ann["call_hash"], "announced at", ann["height"]) +``` + +Reject anything you don't recognize — rejection cancels the announcement +on-chain, signed by the real account or a `NonTransfer` proxy acting for it: + +```bash +btcli call Proxy.reject_announcement \ + --args '{"delegate": "5F...ops", "call_hash": "0x..."}' \ + -w safe +``` + +A delegate withdrawing its own mistaken announcement uses +`Proxy.remove_announcement` instead, signed by the delegate and passing the +*real* account: `--args '{"real": "5F...safe", "call_hash": "0x..."}'`. + +## Step 5 — pure proxies + +[`create-pure-proxy`](/docs/tx/create-pure-proxy) spawns a fresh account with +**no private key anywhere** — the spawner controls it purely through the +proxy relationship. That makes it a disposable, role-scoped account (a +staking-only treasury, a per-project operational account), and the standard +building block for multisigs with swappable members: make each multisig +member a pure proxy, and a departing teammate is handled by re-pointing one +pure proxy's delegate — the multisig address never changes. + +```bash +btcli proxy create --proxy-type Any --name treasury -w safe +``` + +`--name` saves the spawned address *and its creation block height / extrinsic +index* to the proxy book — record these; killing the account later requires +them. Fund the pure proxy, then act as it with the same `--proxy-for` flow, +signed by the spawner: + +```bash +btcli tx transfer --dest treasury --amount-tao 50 -w safe +btcli tx add-stake --hotkey 5F...validator --netuid 1 --amount-tao 20 \ + -w safe --proxy-for treasury +``` + +`btcli proxy list --coldkey treasury` shows the spawner as its delegate. +Additional delegates can be registered on the pure proxy itself by +dispatching `add-proxy` *through* it (`btcli tx add-proxy --delegate ... -w +safe --proxy-for treasury`). + +When it's no longer needed, empty it first, then destroy it. `kill` must be +dispatched through the pure proxy itself and must reproduce the exact +creation coordinates — which the proxy book entry supplies automatically: + +```bash +btcli tx transfer --dest safe --amount-tao all -w safe --proxy-for treasury +btcli proxy kill treasury -w safe +``` + +**Irreversible:** any funds left in a killed pure proxy are gone permanently. +And since the spawner relationship is the only control path, losing the +spawner key — or removing its delegation — strands the pure proxy and +everything it holds. See [`kill-pure-proxy`](/docs/tx/kill-pure-proxy). + +## Step 6 — revoke + +Removal must match the original grant's (delegate, type, delay) triple +exactly, and takes effect immediately regardless of the delegation's delay. +The deposit comes back: + +```bash +btcli proxy remove --delegate ops --proxy-type Staking --delay 0 -w safe +``` + +The panic switch drops every delegation at once +([`remove-proxies`](/docs/tx/remove-proxies)): + +```bash +btcli proxy remove --all -w safe +``` + +Careful with `--all` if the account spawned pure proxies — they are +controlled *through* delegations, so removing everything can strand them +permanently. Treat any leaked **zero-delay** proxy key as already spent: +revoke first, investigate second. + +## A recommended architecture + +The pattern the pieces are designed for, from a compromised-wallet +perspective: + +1. **Primary coldkey** in a hardware wallet or air-gapped machine. It signs + exactly one thing, once: `add-proxy` for a delayed **NonTransfer** manager + proxy (`--ledger` / `--signer extension` keep it off the CLI machine even + for that). +2. **Manager proxy** (`NonTransfer`, `delay > 0`) creates, removes, and + monitors all other proxies, and rejects hostile announcements. It cannot + move funds even if leaked, and its own actions are announced and delayed — + visible before they bite. +3. **Scoped daily proxies** (`Staking`, `Registration`, `ChildKeys`, ..., + `delay 0`) on working machines, one per job, revoked the moment they're + not actively needed. +4. **A monitor** — a cron job or agent polling `Proxy.Announcements` (and + your delegations via `btcli query proxies --json`) on a schedule shorter + than your shortest delay. + +With this in place, the key that can drain you touches a signer once in its +life, every routine key is individually expendable, and an attacker's move +announces itself before it can execute. For shared custody on top — +subnet-owner treasuries especially — put a [multisig](/docs/guides/multisig) +behind the real account. + +### Subnet owners specifically + +A subnet owner's coldkey controls the subnet's identity and owner-settable +hyperparameters — exactly the kind of authority that should never live in a +single key on an operational machine. The layering: + +* Make the owner account a [multisig](/docs/guides/multisig) from + registration (or migrate an existing owner to one via the announced + coldkey swap — see + [that guide](/docs/guides/multisig#migrate-an-existing-account-to-a-multisig); + a plain transfer moves TAO but *not* subnet ownership). +* From the owner, grant a dedicated operations key the narrow **Owner** proxy + type. It can manage subnet identity and hyperparameters but cannot transfer + funds or rotate the owner. Use it for all routine changes; the owner + account itself acts only to replace or revoke that proxy. +* Add an announcement delay on the Owner proxy when your operational cadence + permits, and monitor announcements more often than the delay. + +Crowd-funded subnets get a chain-native version of this model for free: a +crowdloan lease creates the lease-owner account itself and grants the +beneficiary a scoped `SubnetLeaseBeneficiary` proxy. + +## Deposits and limits + +* Adding a proxy reserves **0.06 TAO base + 0.033 TAO per delegation** from + the granting account, returned on removal. At most **20 proxies** per + account. +* Announcements reserve **0.036 TAO base + 0.068 TAO each** from the + delegate; at most **75 pending** per delegate. +* The delegate pays ordinary transaction fees on proxied calls, so keep a + little TAO on it. + +## Troubleshooting + +* `NotProxy` — no delegation matches; check `btcli proxy list` and that + you're signing with the delegate (`-w`) and naming the real account + (`--proxy-for`), not the reverse. +* `Unproxyable` / `CallFiltered` — the call is outside the delegation's proxy + type (remember `Staking` excludes `batch_all`). +* `Unannounced` — a delayed delegation executed without announcing, before + the delay elapsed, or with parameters that don't hash to the announcement. +* `Duplicate` — a delegation with the same (delegate, type, delay) already + exists. +* `TooMany` — over the 20-proxy or 75-announcement cap; remove unused + entries. diff --git a/docs/guides/staking.mdx b/docs/guides/staking.mdx index eb6000266f..fb4c940223 100644 --- a/docs/guides/staking.mdx +++ b/docs/guides/staking.mdx @@ -6,7 +6,9 @@ description: Back validators with TAO, manage positions across subnets, and clai Staking backs a validator (a **hotkey**) with your TAO. On a subnet, staking swaps TAO into the subnet's alpha at the pool price; your position's value then follows the pool price and the validator's performance. On the root network -(netuid 0) stake stays TAO-denominated. +(netuid 0) stake stays TAO-denominated. For how the pools themselves work — +price impact, fees, MEV — see +[staking and pools](/docs/concepts/staking-pools). ## Pick a validator diff --git a/docs/guides/subnets.mdx b/docs/guides/subnets.mdx index 2342e97c49..7119281b45 100644 --- a/docs/guides/subnets.mdx +++ b/docs/guides/subnets.mdx @@ -102,13 +102,13 @@ The important owner-settable parameters, with chain defaults: | Parameter | Default | What it does | | --- | --- | --- | -| `tempo` * | 360 | Blocks per epoch. Owner changes bounded 360–50,400. | +| `tempo` | 360 | Blocks per epoch. Owner changes bounded 360–50,400 and reset the epoch cycle. | | `immunity_period` | 4,096 | Blocks a fresh UID is protected from pruning and trimming. | | `min_burn` / `max_burn` | 0.0005 τ / 100 τ | Clamp on the neuron registration price. Read the live price with [`burn`](/docs/query/burn). | | `burn_half_life` | 360 | Blocks for the registration price to decay halfway toward `min_burn` when nobody registers. | | `burn_increase_mult` | 1.26 | Multiplier applied to the registration price after each successful registration. | | `max_allowed_uids` | 256 | UID slots. Floor 64; times mechanism count must stay ≤ 256. | -| `activity_cutoff_factor` * | 13,889 | Per-mille of tempo; effective cutoff = factor × tempo / 1000 blocks (5,000 at tempo 360; bounds 1,000–50,000). A validator that hasn't set weights within the cutoff sits out until next epoch. Replaces the deprecated `activity_cutoff` (5,000). | +| `activity_cutoff_factor` | 13,889 | Per-mille of tempo; effective cutoff = factor × tempo / 1000 blocks (5,000 at tempo 360; bounds 1,000–50,000). A validator that hasn't set weights within the cutoff sits out until next epoch. Replaces the deprecated `activity_cutoff` (5,000). | | `serving_rate_limit` | 50 | Minimum blocks between `serve-axon` / `serve-prometheus` calls per key. | | `commit_reveal_weights_enabled` | true | Weights are committed hashed, revealed later. | | `commit_reveal_period` | 1 | Tempos between commit and reveal. | diff --git a/docs/hyperparameters/activity-cutoff-factor.mdx b/docs/hyperparameters/activity-cutoff-factor.mdx new file mode 100644 index 0000000000..e20e4a95c6 --- /dev/null +++ b/docs/hyperparameters/activity-cutoff-factor.mdx @@ -0,0 +1,53 @@ +--- +title: activity_cutoff_factor +description: Tempo-relative activity cutoff — per-mille of tempo a validator can go without setting weights. +--- + +`activity_cutoff_factor` sets the inactivity window as a fraction of the +epoch length instead of an absolute block count: the effective +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) is +`factor × tempo / 1000` blocks. Because the window scales with +[`tempo`](/docs/hyperparameters/tempo), a subnet that changes its epoch +cadence keeps the same *number of epochs* of tolerance rather than a fixed +wall-clock window. + +## How it works + +`get_activity_cutoff_blocks` (`pallets/subtensor/src/utils/misc.rs`) computes +`factor_milli × tempo / 1000`, clamped to at least 1 block, and the epoch uses +that value to mask inactive validators out of consensus (see +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) for the masking +mechanics). + +The factor is per-mille: 1,000 means one full tempo, 13,889 (the default) +means ~13.9 tempos — 5,000 blocks (~16.7 hours) at the default tempo of 360, +matching the legacy absolute cutoff. Bounds are 1,000–50,000 (one to fifty +tempos). + +## Reading and setting + +Inspect with: + +``` +btcli sudo get --netuid N --name activity_cutoff_factor +``` + +Owner-settable: + +``` +btcli sudo set --netuid N --name activity_cutoff_factor --value 13889 +``` + +This dispatches `sudo_set_activity_cutoff_factor` (AdminUtils), owner-or-root: +the owner path is rate-limited (once per ~2 tempos by default) and respects +the admin freeze window; root bypasses both. It supersedes the legacy +absolute-blocks `sudo_set_activity_cutoff`, whose stored value the epoch +ignores. + +## Related + +[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) · +[`tempo`](/docs/hyperparameters/tempo) · +[`kappa`](/docs/hyperparameters/kappa) · +[`max_validators`](/docs/hyperparameters/max-validators) · +[`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) diff --git a/docs/hyperparameters/activity-cutoff.mdx b/docs/hyperparameters/activity-cutoff.mdx index 361df2d7fc..e6ee985bff 100644 --- a/docs/hyperparameters/activity-cutoff.mdx +++ b/docs/hyperparameters/activity-cutoff.mdx @@ -38,20 +38,23 @@ Inspect with: btcli sudo get --netuid N --name activity_cutoff ``` -This returns the effective block count. Owner-settable: +This returns the effective block count. It is not settable directly: the +epoch derives it from +[`activity_cutoff_factor`](/docs/hyperparameters/activity-cutoff-factor) +(per-mille of [`tempo`](/docs/hyperparameters/tempo)), so change the factor +instead: ``` -btcli sudo set --netuid N --name activity_cutoff --value 5000 +btcli sudo set --netuid N --name activity_cutoff_factor --value 13889 ``` -The value is a raw block count (12s blocks), floor 360. Note that this -dispatches the legacy absolute-blocks extrinsic; the epoch reads the -factor-derived value, so the tempo-relative `set_activity_cutoff_factor` -extrinsic (per-mille of [`tempo`](/docs/hyperparameters/tempo)) is the -authoritative way to change what the epoch actually uses. +A legacy absolute-blocks extrinsic (`sudo_set_activity_cutoff`) still exists +on chain, but the value it writes is ignored by the epoch and it will be +removed; don't use it. ## Related +[`activity_cutoff_factor`](/docs/hyperparameters/activity-cutoff-factor) · [`tempo`](/docs/hyperparameters/tempo) · [`kappa`](/docs/hyperparameters/kappa) · [`rho`](/docs/hyperparameters/rho) · diff --git a/docs/hyperparameters/index.mdx b/docs/hyperparameters/index.mdx index 0943865155..cc104281d0 100644 --- a/docs/hyperparameters/index.mdx +++ b/docs/hyperparameters/index.mdx @@ -14,14 +14,15 @@ Read them with `btcli sudo get --netuid N` (the [`subnet_hyperparameters`](/docs | [`immunity_period`](/docs/hyperparameters/immunity-period) | blocks (12s) | yes | prune-immunity window for new neurons | | [`min_allowed_weights`](/docs/hyperparameters/min-allowed-weights) | integer | yes | minimum weights per submission | | [`max_weights_limit`](/docs/hyperparameters/max-weights-limit) | fraction (u16, 65535 = 1.0) | root only | cap on a single miner's weight | -| [`tempo`](/docs/hyperparameters/tempo) | blocks (12s) | root only | blocks per consensus epoch | +| [`tempo`](/docs/hyperparameters/tempo) | blocks (12s) | yes | blocks per consensus epoch | | [`min_difficulty`](/docs/hyperparameters/min-difficulty) | PoW difficulty (u64) | root only | PoW registration difficulty floor | | [`max_difficulty`](/docs/hyperparameters/max-difficulty) | PoW difficulty (u64) | yes | PoW registration difficulty ceiling | | [`difficulty`](/docs/hyperparameters/difficulty) | PoW difficulty (u64) | root only | current PoW registration difficulty | | [`weights_version`](/docs/hyperparameters/weights-version) | integer | yes | minimum version key for set_weights | | [`weights_rate_limit`](/docs/hyperparameters/weights-rate-limit) | blocks (12s) | root only | wait between weight submissions | | [`adjustment_interval`](/docs/hyperparameters/adjustment-interval) | blocks (12s) | root only | difficulty/burn adjustment cadence | -| [`activity_cutoff`](/docs/hyperparameters/activity-cutoff) | blocks (12s) | yes | no-weights window before inactive | +| [`activity_cutoff`](/docs/hyperparameters/activity-cutoff) | blocks (12s) | root only | no-weights window before inactive | +| [`activity_cutoff_factor`](/docs/hyperparameters/activity-cutoff-factor) | integer | yes | activity cutoff, per-mille of tempo | | [`registration_allowed`](/docs/hyperparameters/registration-allowed) | flag | root only | new neuron registrations allowed | | [`network_pow_registration_allowed`](/docs/hyperparameters/network-pow-registration-allowed) | flag | yes | PoW registration toggle | | [`target_regs_per_interval`](/docs/hyperparameters/target-regs-per-interval) | integer | root only | registration-rate controller target | @@ -45,6 +46,9 @@ Read them with `btcli sudo get --netuid N` (the [`subnet_hyperparameters`](/docs | [`burn_increase_mult`](/docs/hyperparameters/burn-increase-mult) | multiplier (U64F64 bits / 2^64) | yes | burn cost bump per registration | | [`burn_half_life`](/docs/hyperparameters/burn-half-life) | blocks (12s) | yes | burn cost decay half-life | | [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) | flag | yes | yuma3 consensus variant toggle | +| [`yuma_version`](/docs/hyperparameters/yuma-version) | integer | root only | epoch consensus variant (2 or 3) | +| [`subnet_is_active`](/docs/hyperparameters/subnet-is-active) | flag | root only | subnet started (staking + emissions) | +| [`user_liquidity_enabled`](/docs/hyperparameters/user-liquidity-enabled) | flag | root only | legacy user-LP flag (always false) | | [`bonds_reset_enabled`](/docs/hyperparameters/bonds-reset-enabled) | flag | yes | bonds reset on metadata commit | | [`transfers_enabled`](/docs/hyperparameters/transfers-enabled) | flag | yes | stake transfers between coldkeys | | [`owner_cut_enabled`](/docs/hyperparameters/owner-cut-enabled) | flag | yes | owner emission cut toggle | diff --git a/docs/hyperparameters/meta.json b/docs/hyperparameters/meta.json index d3f36a6779..6434cf2e4b 100644 --- a/docs/hyperparameters/meta.json +++ b/docs/hyperparameters/meta.json @@ -15,6 +15,7 @@ "weights-rate-limit", "adjustment-interval", "activity-cutoff", + "activity-cutoff-factor", "registration-allowed", "network-pow-registration-allowed", "target-regs-per-interval", @@ -38,6 +39,9 @@ "burn-increase-mult", "burn-half-life", "yuma3-enabled", + "yuma-version", + "subnet-is-active", + "user-liquidity-enabled", "bonds-reset-enabled", "transfers-enabled", "owner-cut-enabled", diff --git a/docs/hyperparameters/subnet-is-active.mdx b/docs/hyperparameters/subnet-is-active.mdx new file mode 100644 index 0000000000..82616e82be --- /dev/null +++ b/docs/hyperparameters/subnet-is-active.mdx @@ -0,0 +1,64 @@ +--- +title: subnet_is_active +description: Whether the subnet has been started — staking, alpha trading, and emissions are live. +--- + +`subnet_is_active` reports whether the subnet's owner has fired the one-shot +[`start-call`](/docs/tx/start-call) that brings a registered subnet to life. +Before it flips to true the subnet is a shell: no one can stake into it, its +alpha cannot be traded, and it receives no emissions. Stakers should check it +before trying to enter a freshly registered subnet; owners watch it as the +line between "registered" and "launched." + +## How it works + +The value is the `SubtokenEnabled` storage map in +`pallets/subtensor/src/lib.rs` — "is subtoken trading enabled" — which +defaults to **false** for a newly registered subnet. `do_start_call` +(`pallets/subtensor/src/subnets/subnet.rs`) sets it to true, records the +subnet's first emission block, and can only be called by the subnet owner +once `StartCallDelay` blocks have passed since registration (the +[`subnet_start_schedule`](/docs/query/subnet-start-schedule) read shows the +earliest block). + +While the flag is false: + +- **All staking paths are closed.** `ensure_subtoken_enabled` guards + add/remove stake, limit orders, and alpha recycle/burn, and both the origin + and destination subnets are checked on move/swap/transfer + (`pallets/subtensor/src/staking/stake_utils.rs`). Every one of them fails + with `SubtokenDisabled`. +- **No emissions.** `get_subnets_to_emit_to` + (`pallets/subtensor/src/coinbase/subnet_emissions.rs`) only emits to + subnets with the flag on, a first-emission block set, and + [`registration_allowed`](/docs/hyperparameters/registration-allowed) true. +- **Childkeys apply immediately.** `set_children` skips the pending-cooldown + schedule before start and applies at once + (`pallets/subtensor/src/staking/set_children.rs`). + +Dissolving a subnet removes the entry. Root can also force the flag either +way with `sudo_set_subtoken_enabled` (AdminUtils), but in normal operation it +is written exactly once, by `start-call`. + +## Reading and setting + +``` +btcli sudo get --netuid N --name subnet_is_active +``` + +Not settable through `btcli sudo set` — the owner flips it by starting the +subnet: + +``` +btcli tx start-call --netuid N --dry-run +``` + +Check when the subnet becomes eligible with +`btcli query subnet-start-schedule --netuid N`. + +## Related + +[`registration_allowed`](/docs/hyperparameters/registration-allowed) · +[`transfers_enabled`](/docs/hyperparameters/transfers-enabled) · +[`start-call`](/docs/tx/start-call) · +[`subnet_start_schedule`](/docs/query/subnet-start-schedule) diff --git a/docs/hyperparameters/tempo.mdx b/docs/hyperparameters/tempo.mdx index 7c2d7fe1be..5eb592cd86 100644 --- a/docs/hyperparameters/tempo.mdx +++ b/docs/hyperparameters/tempo.mdx @@ -26,7 +26,9 @@ re-anchors `LastEpochBlock` to the current block), so the next epoch lands a full tempo after the change. The timeline below shows emission accruing block by block and paying out at -each epoch boundary — slide `tempo` to see the cadence in wall-clock time. +each epoch boundary — slide `tempo` across the full owner-settable range +(360 to 50,400 blocks, ~72 minutes to ~7 days) to see the cadence in +wall-clock time. @@ -38,16 +40,22 @@ Inspect with: btcli sudo get --netuid N --name tempo ``` -Not settable through `btcli sudo set` — root/governance only there -(`sudo_set_tempo` in AdminUtils requires the root origin and accepts any -u16). The subtensor pallet does expose an owner-side `set_tempo` extrinsic, -bounded to 360–50,400 blocks (~72 minutes to ~7 days) and rate-limited, -for owners using raw calls. +Owner-settable: + +``` +btcli sudo set --netuid N --name tempo --value 720 +``` + +This dispatches `sudo_set_tempo` (AdminUtils), which is owner-or-root: the +owner is bounded to 360–50,400 blocks (~72 minutes to ~7 days) and +rate-limited to one change per 360 blocks; root may set any u16. Both paths +respect the admin freeze window, and a successful change resets the epoch +cycle so the next epoch lands a full new tempo after the change. ## Related [`rho`](/docs/hyperparameters/rho) · [`kappa`](/docs/hyperparameters/kappa) · -[`activity_cutoff`](/docs/hyperparameters/activity-cutoff) · +[`activity_cutoff_factor`](/docs/hyperparameters/activity-cutoff-factor) · [`max_validators`](/docs/hyperparameters/max-validators) · [`commit_reveal_period`](/docs/hyperparameters/commit-reveal-period) diff --git a/docs/hyperparameters/user-liquidity-enabled.mdx b/docs/hyperparameters/user-liquidity-enabled.mdx new file mode 100644 index 0000000000..a3d20443b4 --- /dev/null +++ b/docs/hyperparameters/user-liquidity-enabled.mdx @@ -0,0 +1,41 @@ +--- +title: user_liquidity_enabled +description: Legacy flag for user-provided swap liquidity; always false since the balancer migration. +--- + +`user_liquidity_enabled` once gated whether users could open their own +liquidity positions in a subnet's swap pool. That feature is gone: the chain +migrated the swap to a balancer design, and the flag is now hardcoded to +**false** for every subnet. It remains in the hyperparameter listing only so +existing clients keep decoding a familiar field — treat it as a tombstone, +not a setting. + +## How it works + +Under swap v3, `EnabledUserLiquidity` in the Swap pallet controlled per-subnet +access to user LP calls (`add_liquidity`, `remove_liquidity`, +`modify_position`). The balancer migration +(`pallets/swap/src/pallet/migrations/migrate_swapv3_to_balancer.rs`) deleted +that storage outright, and each of those extrinsics — along with the +`toggle_user_liquidity` call that flipped the flag — now fails immediately +with `Deprecated` (`pallets/swap/src/pallet/mod.rs`). + +The hyperparameter getter reflects this: `get_subnet_hyperparams_v3` +(`pallets/subtensor/src/rpc_info/subnet_info.rs`) reports a literal `false` +with no storage read behind it. There is nothing to enable and no one who can +enable it. + +## Reading and setting + +``` +btcli sudo get --netuid N --name user_liquidity_enabled +``` + +Always false. Not settable by anyone — the calls that once toggled it are +deprecated on-chain. + +## Related + +[`transfers_enabled`](/docs/hyperparameters/transfers-enabled) · +[`subnet_is_active`](/docs/hyperparameters/subnet-is-active) · +[Money](/docs/concepts/money) — how the swap pool prices alpha today diff --git a/docs/hyperparameters/yuma-version.mdx b/docs/hyperparameters/yuma-version.mdx new file mode 100644 index 0000000000..bdb3b1236b --- /dev/null +++ b/docs/hyperparameters/yuma-version.mdx @@ -0,0 +1,39 @@ +--- +title: yuma_version +description: Which Yuma consensus variant the subnet's epoch runs — a derived reading of yuma3_enabled. +--- + +`yuma_version` names the consensus variant the subnet's epoch executes: **2** +for classic Yuma, **3** for the Yuma3 bond computation. It is a convenience +reading, not its own switch — the chain derives it from the +[`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) flag, and those are the +only two values it takes. Validators use it to know which bond math is paying +their dividends without decoding a boolean in their head. + +## How it works + +`get_subnet_hyperparams_v3` (`pallets/subtensor/src/rpc_info/subnet_info.rs`) +computes it inline: 3 when `Yuma3On` is set for the subnet, 2 otherwise. No +`YumaVersion` storage exists; the epoch itself branches on `Yuma3On` directly +(`pallets/subtensor/src/epoch/run_epoch.rs`). What the two variants actually +change — bond normalization, the EMA path, and whether liquid alpha applies — +is covered on the [`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) page. + +## Reading and setting + +``` +btcli sudo get --netuid N --name yuma_version +``` + +Not settable directly. The subnet owner switches variants through the flag: + +``` +btcli sudo set --netuid N --name yuma3_enabled --value true +``` + +## Related + +[`yuma3_enabled`](/docs/hyperparameters/yuma3-enabled) · +[`liquid_alpha_enabled`](/docs/hyperparameters/liquid-alpha-enabled) · +[`bonds_moving_avg`](/docs/hyperparameters/bonds-moving-avg) · +[Yuma Consensus overview](/docs/concepts/emissions#yuma-consensus) diff --git a/docs/internals/contributing.mdx b/docs/internals/contributing.mdx index 9be2fd6284..07492549a6 100644 --- a/docs/internals/contributing.mdx +++ b/docs/internals/contributing.mdx @@ -88,7 +88,7 @@ truth rendered to [bittensor.com/docs](https://bittensor.com/docs) by the website app (`website/apps/bittensor-website`). - User-facing concepts and guides: `docs/concepts/`, `docs/guides/` -- Generated SDK reference (`docs/tx/`, `docs/query/`, `docs/errors.mdx`): +- Generated SDK reference (`docs/tx/`, `docs/query/`, `docs/errors/`): never hand-edit; regenerate with `website/apps/bittensor-website/scripts/generate.py` - Runtime internals and contributor docs: `docs/internals/` diff --git a/docs/internals/repo-layout.mdx b/docs/internals/repo-layout.mdx index 2c137c9a04..fd3b1b7916 100644 --- a/docs/internals/repo-layout.mdx +++ b/docs/internals/repo-layout.mdx @@ -40,7 +40,7 @@ binding crate per language, and one product directory per language surface. | `sdk/bittensor-core/` | The chain-defined compute core for clients: sp-core key primitives, keyfiles, SCALE codec + runtime metadata engine, extrinsic assembly, RFC-0078 metadata digests, drand timelock, ML-KEM, Ledger transport — a cargo workspace member built against the same crate revisions as the runtime so client crypto and codec can never drift from the chain's | | `sdk/bittensor-core-py/` | PyO3 bindings for the core (bindings only, no logic) — published to PyPI as `bittensor-core` wheels ([Rust setup](/docs/internals/rust-setup)). Future surfaces add sibling binding crates (napi, uniffi) next to the core they mirror | | `sdk/python/` | The `bittensor` Python SDK and `btcli` — bindings generated from chain metadata ([SDK tests](/docs/internals/sdk-tests)) | -| `docs/` | This documentation — the single source of truth, rendered to bittensor.com/docs by the website app. `docs/tx/`, `docs/query/`, and `docs/errors.mdx` are generated; never hand-edit them | +| `docs/` | This documentation — the single source of truth, rendered to bittensor.com/docs by the website app. `docs/tx/`, `docs/query/`, and `docs/errors/` are generated; never hand-edit them | | `website/` | Yarn 4 + Turbo monorepo. `apps/bittensor-website` is the production site (marketing + these docs); `packages/` holds shared UI/API libraries | | `ink-contract/` | Standalone ink! contract source used by the wasm-contract tests | diff --git a/docs/query/index.mdx b/docs/query/index.mdx index 5031716dfa..1f8f0a82b8 100644 --- a/docs/query/index.mdx +++ b/docs/query/index.mdx @@ -137,7 +137,7 @@ Reads are free, unsigned, and safe to call at any time. Each CLI command is `btc | [`mechanism-emission-split`](/docs/query/mechanism-emission-split) | Emission split between mechanisms on a subnet. | | [`metagraph`](/docs/query/metagraph) | The full metagraph for a subnet in one call (stakes, ranks, emissions, axons, ...). | | [`subnet`](/docs/query/subnet) | Tempo, burn, and neuron count for one subnet (the three reads run concurrently). | -| [`subnet-hyperparameters`](/docs/query/subnet-hyperparameters) | All hyperparameters for a subnet (named fields; version-dependent set). | +| [`subnet-hyperparameters`](/docs/query/subnet-hyperparameters) | All hyperparameters for a subnet, as a flat name -> raw value mapping. | | [`subnet-identity`](/docs/query/subnet-identity) | The identity metadata of a subnet, or None. | | [`subnet-names`](/docs/query/subnet-names) | Registered name of every subnet that published an identity, keyed by netuid. | | [`subnet-registration-cost`](/docs/query/subnet-registration-cost) | Current cost to register a new subnet. | diff --git a/docs/query/metagraph.mdx b/docs/query/metagraph.mdx index 31efa10c70..7a5f27796b 100644 --- a/docs/query/metagraph.mdx +++ b/docs/query/metagraph.mdx @@ -5,7 +5,8 @@ description: "The full metagraph for a subnet in one call (stakes, ranks, emissi {/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} - +`name` and `symbol` are decoded to text (the wire carries them as +compact-u16 vectors of utf-8 bytes, unlike every other text field). **Category:** Subnets diff --git a/docs/query/subnet-hyperparameters.mdx b/docs/query/subnet-hyperparameters.mdx index 6721f51bce..d6b05ddd9d 100644 --- a/docs/query/subnet-hyperparameters.mdx +++ b/docs/query/subnet-hyperparameters.mdx @@ -1,11 +1,14 @@ --- title: "subnet-hyperparameters" -description: "All hyperparameters for a subnet (named fields; version-dependent set)." +description: "All hyperparameters for a subnet, as a flat name -> raw value mapping." --- {/* GENERATED by scripts/generate.py from the SDK registries — do not edit. */} - +The set of names is version-dependent; None if the subnet does not exist. +Uses the forward-compatible `get_subnet_hyperparams_v3` runtime API, so +newly added chain hyperparameters (e.g. `burn_half_life`) show up +without a client update. **Category:** Subnets diff --git a/docs/tx/set-hyperparameter.mdx b/docs/tx/set-hyperparameter.mdx index 869ed4962c..ab9c6c53ea 100644 --- a/docs/tx/set-hyperparameter.mdx +++ b/docs/tx/set-hyperparameter.mdx @@ -19,14 +19,14 @@ fail. Read current values back with the `subnet_hyperparameters` read. | Signer | Pallet | Wraps | | --- | --- | --- | -| `coldkey` | AdminUtils | `AdminUtils.sudo_set_immunity_period`, `AdminUtils.sudo_set_min_allowed_weights`, `AdminUtils.sudo_set_weights_version_key`, `AdminUtils.sudo_set_activity_cutoff`, `AdminUtils.sudo_set_min_burn`, `AdminUtils.sudo_set_max_burn`, `AdminUtils.sudo_set_bonds_moving_average`, `AdminUtils.sudo_set_bonds_penalty`, `AdminUtils.sudo_set_serving_rate_limit`, `AdminUtils.sudo_set_commit_reveal_weights_interval`, `AdminUtils.sudo_set_max_allowed_uids`, `AdminUtils.sudo_set_burn_increase_mult`, `AdminUtils.sudo_set_burn_half_life`, `AdminUtils.sudo_set_adjustment_alpha`, `AdminUtils.sudo_set_rho`, `AdminUtils.sudo_set_max_difficulty`, `AdminUtils.sudo_set_alpha_sigmoid_steepness`, `AdminUtils.sudo_set_min_childkey_take_per_subnet`, `AdminUtils.sudo_set_owner_immune_neuron_limit`, `AdminUtils.sudo_set_alpha_values`, `AdminUtils.sudo_set_commit_reveal_weights_enabled`, `AdminUtils.sudo_set_liquid_alpha_enabled`, `AdminUtils.sudo_set_network_pow_registration_allowed`, `AdminUtils.sudo_set_yuma3_enabled`, `AdminUtils.sudo_set_bonds_reset_enabled`, `AdminUtils.sudo_set_toggle_transfer`, `AdminUtils.sudo_set_owner_cut_enabled`, `AdminUtils.sudo_set_owner_cut_auto_lock_enabled` | +| `coldkey` | AdminUtils | `AdminUtils.sudo_set_tempo`, `AdminUtils.sudo_set_immunity_period`, `AdminUtils.sudo_set_min_allowed_weights`, `AdminUtils.sudo_set_weights_version_key`, `AdminUtils.sudo_set_activity_cutoff_factor`, `AdminUtils.sudo_set_min_burn`, `AdminUtils.sudo_set_max_burn`, `AdminUtils.sudo_set_bonds_moving_average`, `AdminUtils.sudo_set_bonds_penalty`, `AdminUtils.sudo_set_serving_rate_limit`, `AdminUtils.sudo_set_commit_reveal_weights_interval`, `AdminUtils.sudo_set_max_allowed_uids`, `AdminUtils.sudo_set_burn_increase_mult`, `AdminUtils.sudo_set_burn_half_life`, `AdminUtils.sudo_set_adjustment_alpha`, `AdminUtils.sudo_set_rho`, `AdminUtils.sudo_set_max_difficulty`, `AdminUtils.sudo_set_alpha_sigmoid_steepness`, `AdminUtils.sudo_set_min_childkey_take_per_subnet`, `AdminUtils.sudo_set_owner_immune_neuron_limit`, `AdminUtils.sudo_set_alpha_values`, `AdminUtils.sudo_set_commit_reveal_weights_enabled`, `AdminUtils.sudo_set_liquid_alpha_enabled`, `AdminUtils.sudo_set_network_pow_registration_allowed`, `AdminUtils.sudo_set_yuma3_enabled`, `AdminUtils.sudo_set_bonds_reset_enabled`, `AdminUtils.sudo_set_toggle_transfer`, `AdminUtils.sudo_set_owner_cut_enabled`, `AdminUtils.sudo_set_owner_cut_auto_lock_enabled` | ## Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `netuid` | integer | yes | Subnet to configure; the signer must be its owner. | -| `name` | string | yes | Hyperparameter to set. One of: activity_cutoff, adjustment_alpha, alpha_high, alpha_low, alpha_sigmoid_steepness, bonds_moving_avg, bonds_penalty, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, max_burn, max_difficulty, min_allowed_weights, min_burn, min_childkey_take, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, owner_immune_neuron_limit, rho, serving_rate_limit, transfers_enabled, weights_version, yuma3_enabled. | +| `name` | string | yes | Hyperparameter to set. One of: activity_cutoff_factor, adjustment_alpha, alpha_high, alpha_low, alpha_sigmoid_steepness, bonds_moving_avg, bonds_penalty, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, max_burn, max_difficulty, min_allowed_weights, min_burn, min_childkey_take, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, owner_immune_neuron_limit, rho, serving_rate_limit, tempo, transfers_enabled, weights_version, yuma3_enabled. | | `value` | integer \| number \| string | yes | New value. Give the raw on-chain integer, or the human form as a float or a string with a decimal point (a 0..1 fraction for normalized parameters, a TAO amount for rao parameters). Boolean parameters take true/false or 0/1. | Address parameters (`--hotkey`, `--coldkey`, `--dest`, ...) accept a raw ss58 diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index f71c59a90d..3c4db84727 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -218,6 +218,19 @@ mod benchmarks { _(RawOrigin::Root, 1u16.into()/*netuid*/, 361u16/*activity_cutoff*/)/*sudo_set_activity_cutoff*/; } + #[benchmark] + fn sudo_set_activity_cutoff_factor() { + // disable admin freeze window + pallet_subtensor::Pallet::::set_admin_freeze_window(0); + pallet_subtensor::Pallet::::init_new_network( + 1u16.into(), /*netuid*/ + 1u16, /*tempo*/ + ); + + #[extrinsic_call] + _(RawOrigin::Root, 1u16.into()/*netuid*/, 5_000u32/*factor_milli*/)/*sudo_set_activity_cutoff_factor*/; + } + #[benchmark] fn sudo_set_rho() { // disable admin freeze window @@ -348,28 +361,23 @@ mod benchmarks { _(RawOrigin::Root, 1u16.into()/*netuid*/, true/*registration_allowed*/)/*sudo_set_network_registration_allowed*/; } - /* - benchmark_sudo_set_tempo { - let netuid = NetUid::from(1); - let tempo_default: u16 = 1; <------- unused? - let tempo: u16 = 15; - let modality: u16 = 0; - - pallet_subtensor::Pallet::::init_new_network(netuid, tempo); - - }: sudo_set_tempo(RawOrigin::>::Root, netuid, tempo) - */ #[benchmark] fn sudo_set_tempo() { - // disable admin freeze window + let netuid = NetUid::from(1); + let owner: T::AccountId = account("owner", 0, 0); + + // Benchmark the heavier owner path (bounds check + rate-limit read/write), + // not the root path which bypasses both. pallet_subtensor::Pallet::::set_admin_freeze_window(0); - pallet_subtensor::Pallet::::init_new_network( - 1u16.into(), /*netuid*/ - 1u16, /*tempo*/ - ); + pallet_subtensor::Pallet::::init_new_network(netuid, pallet_subtensor::MIN_TEMPO); + pallet_subtensor::SubnetOwner::::insert(netuid, &owner); #[extrinsic_call] - _(RawOrigin::Root, 1u16.into()/*netuid*/, 1u16/*tempo*/)/*sudo_set_tempo*/; + _( + RawOrigin::Signed(owner), + netuid, + pallet_subtensor::MIN_TEMPO + 1, + ); } #[benchmark] diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 3238250130..50bd0a0056 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -650,6 +650,31 @@ pub mod pallet { Ok(()) } + /// The extrinsic sets the activity-cutoff factor for a subnet, in per-mille + /// (1/1000) of the tempo: the effective cutoff in blocks is + /// `(factor × tempo) / 1000`. Bounded to `[MinActivityCutoffFactorMilli, + /// MaxActivityCutoffFactorMilli]`. It is callable by the subnet owner + /// (rate-limited via `OwnerHyperparamUpdate`, respects the admin freeze + /// window) or the root account (bypasses both). This supersedes the + /// absolute-blocks `sudo_set_activity_cutoff`. + #[pallet::call_index(97)] + #[pallet::weight(::WeightInfo::sudo_set_activity_cutoff_factor())] + pub fn sudo_set_activity_cutoff_factor( + origin: OriginFor, + netuid: NetUid, + factor_milli: u32, + ) -> DispatchResult { + pallet_subtensor::Pallet::::do_set_activity_cutoff_factor( + origin, + netuid, + factor_milli, + )?; + log::debug!( + "ActivityCutoffFactorMilliSet( netuid: {netuid:?} factor_milli: {factor_milli:?} ) " + ); + Ok(()) + } + /// The extrinsic sets the network registration allowed for a subnet. /// It is only callable by the root account or subnet owner. /// The extrinsic will call the Subtensor pallet to set the network registration allowed. @@ -975,18 +1000,23 @@ pub mod pallet { } /// The extrinsic sets the tempo for a subnet. - /// It is only callable by the root account. - /// The extrinsic will call the Subtensor pallet to set the tempo. + /// It is callable by the subnet owner (bounded to `[MinTempo, MaxTempo]` and + /// rate-limited to one change per `MinTempo` blocks) or the root account (any + /// u16, no rate limit). Both respect the admin freeze window. A successful + /// change resets the epoch cycle (`LastEpochBlock = current_block`). #[pallet::call_index(30)] - #[pallet::weight(::WeightInfo::sudo_set_tempo())] + #[pallet::weight( + ::WeightInfo::sudo_set_tempo().max( + // Conservative floor from the retired owner-call `set_tempo` benchmark, + // plus the additional subnet-existence read performed by this call. + // Remove once weights are regenerated with the owner-path benchmark. + Weight::from_parts(44_877_000, 4_498) + .saturating_add(::DbWeight::get().reads(7_u64)) + .saturating_add(::DbWeight::get().writes(3_u64)) + ) + )] pub fn sudo_set_tempo(origin: OriginFor, netuid: NetUid, tempo: u16) -> DispatchResult { - ensure_root(origin)?; - pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; - ensure!( - pallet_subtensor::Pallet::::if_subnet_exist(netuid), - Error::::SubnetDoesNotExist - ); - pallet_subtensor::Pallet::::apply_tempo_with_cycle_reset(netuid, tempo); + pallet_subtensor::Pallet::::do_set_tempo(origin, netuid, tempo)?; log::debug!("TempoSet( netuid: {netuid:?} tempo: {tempo:?} ) "); Ok(()) } diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 4fc2532b16..a0bf21ed04 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -685,6 +685,138 @@ fn test_sudo_set_activity_cutoff() { }); } +#[test] +fn test_sudo_set_activity_cutoff_factor() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + add_network(netuid, 10); + let owner = U256::from(5); + SubnetOwner::::insert(netuid, owner); + SubtensorModule::set_admin_freeze_window(0); + + // A non-owner signed origin is rejected. + assert_eq!( + AdminUtils::sudo_set_activity_cutoff_factor( + <::RuntimeOrigin>::signed(U256::from(1)), + netuid, + 5_000 + ), + Err(DispatchError::BadOrigin) + ); + + // Out-of-bounds factors are rejected for owner and root alike. + assert_noop!( + AdminUtils::sudo_set_activity_cutoff_factor( + <::RuntimeOrigin>::root(), + netuid, + MAX_ACTIVITY_CUTOFF_FACTOR_MILLI + 1 + ), + SubtensorError::::ActivityCutoffFactorMilliOutOfBounds + ); + + // The owner can set a factor within bounds. + assert_ok!(AdminUtils::sudo_set_activity_cutoff_factor( + <::RuntimeOrigin>::signed(owner), + netuid, + 5_000 + )); + assert_eq!(ActivityCutoffFactorMilli::::get(netuid), 5_000); + + // A second owner change within the rate limit is rejected; root bypasses it. + assert_noop!( + AdminUtils::sudo_set_activity_cutoff_factor( + <::RuntimeOrigin>::signed(owner), + netuid, + 6_000 + ), + SubtensorError::::TxRateLimitExceeded + ); + assert_ok!(AdminUtils::sudo_set_activity_cutoff_factor( + <::RuntimeOrigin>::root(), + netuid, + 6_000 + )); + assert_eq!(ActivityCutoffFactorMilli::::get(netuid), 6_000); + }); +} + +#[test] +fn test_sudo_set_tempo_owner_and_root() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + add_network(netuid, 10); + let owner = U256::from(5); + SubnetOwner::::insert(netuid, owner); + SubtensorModule::set_admin_freeze_window(0); + + // A non-owner signed origin is rejected. + assert_eq!( + AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::signed(U256::from(1)), + netuid, + MIN_TEMPO + ), + Err(DispatchError::BadOrigin) + ); + + // A nonexistent subnet is rejected for root. + assert_noop!( + AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::root(), + netuid.next(), + MIN_TEMPO + ), + SubtensorError::::SubnetNotExists + ); + + // The owner is bounded to [MIN_TEMPO, MAX_TEMPO]. + assert_noop!( + AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::signed(owner), + netuid, + MIN_TEMPO - 1 + ), + SubtensorError::::TempoOutOfBounds + ); + assert_noop!( + AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::signed(owner), + netuid, + MAX_TEMPO + 1 + ), + SubtensorError::::TempoOutOfBounds + ); + + // Within bounds the owner change lands and resets the cycle. + assert_ok!(AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::signed(owner), + netuid, + MIN_TEMPO + )); + assert_eq!(Tempo::::get(netuid), MIN_TEMPO); + let now = SubtensorModule::get_current_block_as_u64(); + assert_eq!(LastEpochBlock::::get(netuid), now); + + // A second owner change within the MIN_TEMPO cooldown is rate-limited. + assert_noop!( + AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::signed(owner), + netuid, + MIN_TEMPO + 1 + ), + SubtensorError::::TxRateLimitExceeded + ); + + // Root bypasses the bounds and the rate limit. + assert_ok!(AdminUtils::sudo_set_tempo( + <::RuntimeOrigin>::root(), + netuid, + 10 + )); + assert_eq!(Tempo::::get(netuid), 10); + }); +} + #[test] fn test_sudo_set_target_registrations_per_interval() { new_test_ext().execute_with(|| { diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index bb29c2efb2..7bb37a0f6b 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -51,6 +51,7 @@ pub trait WeightInfo { fn sudo_set_adjustment_interval() -> Weight; fn sudo_set_target_registrations_per_interval() -> Weight; fn sudo_set_activity_cutoff() -> Weight; + fn sudo_set_activity_cutoff_factor() -> Weight; fn sudo_set_rho() -> Weight; fn sudo_set_kappa() -> Weight; fn sudo_set_min_allowed_uids() -> Weight; @@ -374,6 +375,31 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) + /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::Tempo` (r:1 w:0) + /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) + /// Proof: `SubtensorModule::PendingEpochAt` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::LastEpochBlock` (r:1 w:0) + /// Proof: `SubtensorModule::LastEpochBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::AdminFreezeWindow` (r:1 w:0) + /// Proof: `SubtensorModule::AdminFreezeWindow` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::OwnerHyperparamRateLimit` (r:1 w:0) + /// Proof: `SubtensorModule::OwnerHyperparamRateLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::LastRateLimitedBlock` (r:1 w:1) + /// Proof: `SubtensorModule::LastRateLimitedBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::ActivityCutoffFactorMilli` (r:0 w:1) + /// Proof: `SubtensorModule::ActivityCutoffFactorMilli` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn sudo_set_activity_cutoff_factor() -> Weight { + // Proof Size summary in bytes: + // Measured: `899` + // Estimated: `4364` + // Minimum execution time: 36_214_000 picoseconds. + Weight::from_parts(37_446_000, 4364) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } /// Storage: `SubtensorModule::Tempo` (r:1 w:0) /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) @@ -1340,6 +1366,31 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) + /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::Tempo` (r:1 w:0) + /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) + /// Proof: `SubtensorModule::PendingEpochAt` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::LastEpochBlock` (r:1 w:0) + /// Proof: `SubtensorModule::LastEpochBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::AdminFreezeWindow` (r:1 w:0) + /// Proof: `SubtensorModule::AdminFreezeWindow` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::OwnerHyperparamRateLimit` (r:1 w:0) + /// Proof: `SubtensorModule::OwnerHyperparamRateLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::LastRateLimitedBlock` (r:1 w:1) + /// Proof: `SubtensorModule::LastRateLimitedBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SubtensorModule::ActivityCutoffFactorMilli` (r:0 w:1) + /// Proof: `SubtensorModule::ActivityCutoffFactorMilli` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn sudo_set_activity_cutoff_factor() -> Weight { + // Proof Size summary in bytes: + // Measured: `899` + // Estimated: `4364` + // Minimum execution time: 36_214_000 picoseconds. + Weight::from_parts(37_446_000, 4364) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } /// Storage: `SubtensorModule::Tempo` (r:1 w:0) /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 87a9b579bd..ad73946035 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -2302,39 +2302,6 @@ mod pallet_benchmarks { ); } - #[benchmark] - fn set_tempo() { - let netuid = NetUid::from(1); - let coldkey: T::AccountId = account("Owner", 0, 1); - - Subtensor::::init_new_network(netuid, 1u16); - SubnetOwner::::insert(netuid, coldkey.clone()); - SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_commit_reveal_weights_enabled(netuid, false); - Subtensor::::set_admin_freeze_window(0); - - #[extrinsic_call] - _(RawOrigin::Signed(coldkey.clone()), netuid, MIN_TEMPO); - } - - #[benchmark] - fn set_activity_cutoff_factor() { - let netuid = NetUid::from(1); - let coldkey: T::AccountId = account("Owner", 0, 1); - - Subtensor::::init_new_network(netuid, 1u16); - SubnetOwner::::insert(netuid, coldkey.clone()); - SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_admin_freeze_window(0); - - #[extrinsic_call] - _( - RawOrigin::Signed(coldkey.clone()), - netuid, - INITIAL_ACTIVITY_CUTOFF_FACTOR_MILLI, - ); - } - #[benchmark] fn trigger_epoch() { let netuid = NetUid::from(1); diff --git a/pallets/subtensor/src/coinbase/tempo_control.rs b/pallets/subtensor/src/coinbase/tempo_control.rs index c43c53019e..98c0081114 100644 --- a/pallets/subtensor/src/coinbase/tempo_control.rs +++ b/pallets/subtensor/src/coinbase/tempo_control.rs @@ -8,28 +8,39 @@ use crate::system::pallet_prelude::OriginFor; use crate::utils::rate_limiting::{Hyperparameter, TransactionType}; impl Pallet { - /// Owner-side `set_tempo` implementation. + /// `set_tempo` implementation, dispatched by `AdminUtils::sudo_set_tempo`. + /// Callable by the subnet owner (bounded to `[MinTempo, MaxTempo]` and + /// cooled down by a fixed `MinTempo` blocks via `TransactionType::TempoUpdate`) + /// or by root (any u16, no rate limit). Both respect the admin freeze window + /// and reset the cycle (`LastEpochBlock = current_block`) on success. pub fn do_set_tempo(origin: OriginFor, netuid: NetUid, tempo: u16) -> DispatchResult { - let who = Self::ensure_subnet_owner(origin, netuid)?; + let maybe_who = Self::ensure_subnet_owner_or_root(origin, netuid)?; - ensure!( - (MIN_TEMPO..=MAX_TEMPO).contains(&tempo), - Error::::TempoOutOfBounds - ); + ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); + + if maybe_who.is_some() { + ensure!( + (MIN_TEMPO..=MAX_TEMPO).contains(&tempo), + Error::::TempoOutOfBounds + ); + } Self::ensure_admin_window_open(netuid)?; let tx = TransactionType::TempoUpdate; - ensure!( - tx.passes_rate_limit_on_subnet::(&who, netuid), - Error::::TxRateLimitExceeded - ); - - let now = Self::get_current_block_as_u64(); + if let Some(who) = maybe_who.as_ref() { + ensure!( + tx.passes_rate_limit_on_subnet::(who, netuid), + Error::::TxRateLimitExceeded + ); + } Self::apply_tempo_with_cycle_reset(netuid, tempo); - tx.set_last_block_on_subnet::(&who, netuid, now); + if let Some(who) = maybe_who.as_ref() { + let now = Self::get_current_block_as_u64(); + tx.set_last_block_on_subnet::(who, netuid, now); + } Ok(()) } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index ded0b72d74..096f296c0a 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1830,7 +1830,7 @@ pub mod pallet { #[pallet::storage] pub type Tempo = StorageMap<_, Identity, NetUid, u16, ValueQuery, DefaultTempo>; - /// Lower bound for owner-set tempo. Also the fixed cooldown for `set_tempo`. + /// Lower bound for owner-set tempo. Also the fixed cooldown for `sudo_set_tempo`. pub const MIN_TEMPO: u16 = 360; /// Upper bound for owner-set tempo (≈ 7 days at 12 s/block). pub const MAX_TEMPO: u16 = 50_400; @@ -1851,7 +1851,7 @@ pub mod pallet { /// MAP ( netuid ) --> last epoch attempt block (consumed slot). /// Drives normal-cadence scheduling and the admin freeze window. /// Advances on every `should_run_epoch == true` slot — including consistency-skipped slots — - /// and on a successful `set_tempo` (cycle reset). + /// and on a successful `sudo_set_tempo` (cycle reset). #[pallet::storage] pub type LastEpochBlock = StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultZeroU64>; diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 3907c29e01..b5ad36b531 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -2337,29 +2337,10 @@ mod dispatches { Self::do_set_perpetual_lock(&coldkey, netuid, enabled) } - /// Owner-side `set_tempo`. Validates `[MinTempo, MaxTempo]`, applies a fixed - /// `MinTempo`-block cooldown via `TransactionType::TempoUpdate`, respects the admin - /// freeze window, and resets the cycle (`LastEpochBlock = current_block`) on success. - #[pallet::call_index(139)] - #[pallet::weight(::WeightInfo::set_tempo())] - pub fn set_tempo(origin: OriginFor, netuid: NetUid, tempo: u16) -> DispatchResult { - Self::do_set_tempo(origin, netuid, tempo) - } - - /// `set_activity_cutoff_factor`. Per-mille (1/1000) units; `cutoff_blocks - /// = (factor × tempo) / 1000`. Validates `[MinActivityCutoffFactorMilli, - /// MaxActivityCutoffFactorMilli]`. Callable by the subnet owner (rate-limited - /// via `OwnerHyperparamUpdate`, respects the admin freeze window) or by root - /// (bypasses both). - #[pallet::call_index(140)] - #[pallet::weight(::WeightInfo::set_activity_cutoff_factor())] - pub fn set_activity_cutoff_factor( - origin: OriginFor, - netuid: NetUid, - factor_milli: u32, - ) -> DispatchResult { - Self::do_set_activity_cutoff_factor(origin, netuid, factor_milli) - } + // Call indices 139 (`set_tempo`) and 140 (`set_activity_cutoff_factor`) + // are retired: both moved to the AdminUtils pallet (`sudo_set_tempo`, + // `sudo_set_activity_cutoff_factor`) where the other owner-settable + // hyperparameters live. Do not reuse these indices. /// Owner-side `trigger_epoch`. Schedules an epoch to fire after `AdminFreezeWindow` /// blocks. Rate-limited via the existing `OwnerHyperparamUpdate` pattern. diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index 4e689237f3..4300f1a806 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -108,9 +108,9 @@ impl Pallet { // ==== Global Setters ==== // ======================== /// Unchecked tempo write used by tests, precompiles, and internal helpers. - /// Does NOT reset `LastEpochBlock` — that is the responsibility of the owner-side - /// `set_tempo` extrinsic and `sudo_set_tempo` (root), both of which perform the cycle - /// reset explicitly. + /// Does NOT reset `LastEpochBlock` — that is the responsibility of + /// `AdminUtils::sudo_set_tempo` (owner-or-root), which performs the cycle + /// reset explicitly via `apply_tempo_with_cycle_reset`. pub fn set_tempo_unchecked(netuid: NetUid, tempo: u16) { Tempo::::insert(netuid, tempo); Self::deposit_event(Event::TempoSet(netuid, tempo)); diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index ee9ad4ca90..575f5898a0 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -94,8 +94,6 @@ pub trait WeightInfo { fn lock_stake() -> Weight; fn move_lock() -> Weight; fn associate_evm_key() -> Weight; - fn set_tempo() -> Weight; - fn set_activity_cutoff_factor() -> Weight; fn trigger_epoch() -> Weight; fn check_coldkey_swap_extension() -> Weight; fn check_weights_extension() -> Weight; @@ -2471,52 +2469,6 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::Tempo` (r:1 w:1) - /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) - /// Proof: `SubtensorModule::PendingEpochAt` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::LastEpochBlock` (r:1 w:1) - /// Proof: `SubtensorModule::LastEpochBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::AdminFreezeWindow` (r:1 w:0) - /// Proof: `SubtensorModule::AdminFreezeWindow` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::TransactionKeyLastBlock` (r:1 w:1) - /// Proof: `SubtensorModule::TransactionKeyLastBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_tempo() -> Weight { - // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `4440` - // Minimum execution time: 43_154_000 picoseconds. - Weight::from_parts(44_877_000, 4440) - .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) - /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::Tempo` (r:1 w:0) - /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) - /// Proof: `SubtensorModule::PendingEpochAt` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::LastEpochBlock` (r:1 w:0) - /// Proof: `SubtensorModule::LastEpochBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::AdminFreezeWindow` (r:1 w:0) - /// Proof: `SubtensorModule::AdminFreezeWindow` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::OwnerHyperparamRateLimit` (r:1 w:0) - /// Proof: `SubtensorModule::OwnerHyperparamRateLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::LastRateLimitedBlock` (r:1 w:1) - /// Proof: `SubtensorModule::LastRateLimitedBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::ActivityCutoffFactorMilli` (r:0 w:1) - /// Proof: `SubtensorModule::ActivityCutoffFactorMilli` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_activity_cutoff_factor() -> Weight { - // Proof Size summary in bytes: - // Measured: `899` - // Estimated: `4364` - // Minimum execution time: 36_214_000 picoseconds. - Weight::from_parts(37_446_000, 4364) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) - } - /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) - /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SubtensorModule::CommitRevealWeightsEnabled` (r:1 w:0) /// Proof: `SubtensorModule::CommitRevealWeightsEnabled` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:1) @@ -5009,52 +4961,6 @@ impl WeightInfo for () { } /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::Tempo` (r:1 w:1) - /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) - /// Proof: `SubtensorModule::PendingEpochAt` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::LastEpochBlock` (r:1 w:1) - /// Proof: `SubtensorModule::LastEpochBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::AdminFreezeWindow` (r:1 w:0) - /// Proof: `SubtensorModule::AdminFreezeWindow` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::TransactionKeyLastBlock` (r:1 w:1) - /// Proof: `SubtensorModule::TransactionKeyLastBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_tempo() -> Weight { - // Proof Size summary in bytes: - // Measured: `975` - // Estimated: `4440` - // Minimum execution time: 43_154_000 picoseconds. - Weight::from_parts(44_877_000, 4440) - .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) - /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::Tempo` (r:1 w:0) - /// Proof: `SubtensorModule::Tempo` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:0) - /// Proof: `SubtensorModule::PendingEpochAt` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::LastEpochBlock` (r:1 w:0) - /// Proof: `SubtensorModule::LastEpochBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::AdminFreezeWindow` (r:1 w:0) - /// Proof: `SubtensorModule::AdminFreezeWindow` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::OwnerHyperparamRateLimit` (r:1 w:0) - /// Proof: `SubtensorModule::OwnerHyperparamRateLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::LastRateLimitedBlock` (r:1 w:1) - /// Proof: `SubtensorModule::LastRateLimitedBlock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SubtensorModule::ActivityCutoffFactorMilli` (r:0 w:1) - /// Proof: `SubtensorModule::ActivityCutoffFactorMilli` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn set_activity_cutoff_factor() -> Weight { - // Proof Size summary in bytes: - // Measured: `899` - // Estimated: `4364` - // Minimum execution time: 36_214_000 picoseconds. - Weight::from_parts(37_446_000, 4364) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) - } - /// Storage: `SubtensorModule::SubnetOwner` (r:1 w:0) - /// Proof: `SubtensorModule::SubnetOwner` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SubtensorModule::CommitRevealWeightsEnabled` (r:1 w:0) /// Proof: `SubtensorModule::CommitRevealWeightsEnabled` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SubtensorModule::PendingEpochAt` (r:1 w:1) diff --git a/precompiles/src/subnet.rs b/precompiles/src/subnet.rs index 32ecf82595..5948438471 100644 --- a/precompiles/src/subnet.rs +++ b/precompiles/src/subnet.rs @@ -505,7 +505,7 @@ where netuid: u16, factor_milli: u32, ) -> EvmResult<()> { - let call = pallet_subtensor::Call::::set_activity_cutoff_factor { + let call = pallet_admin_utils::Call::::sudo_set_activity_cutoff_factor { netuid: netuid.into(), factor_milli, }; diff --git a/runtime/src/proxy_filters/call_groups.rs b/runtime/src/proxy_filters/call_groups.rs index 6099b2ad65..07ca90ad4a 100644 --- a/runtime/src/proxy_filters/call_groups.rs +++ b/runtime/src/proxy_filters/call_groups.rs @@ -471,8 +471,6 @@ call_filter_group!( RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_min_childkey_take), RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_max_childkey_take), RuntimeCall::SubtensorModule(SubtensorCall::terminate_lease), - RuntimeCall::SubtensorModule(SubtensorCall::set_tempo), - RuntimeCall::SubtensorModule(SubtensorCall::set_activity_cutoff_factor), RuntimeCall::SubtensorModule(SubtensorCall::trigger_epoch), RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_num_root_claims), RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_root_claim_threshold), @@ -496,6 +494,8 @@ call_filter_group!( RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_min_allowed_weights), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_rho), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_activity_cutoff), + RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_activity_cutoff_factor), + RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_tempo), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_min_burn), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_max_burn), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_bonds_moving_average), @@ -545,7 +545,6 @@ call_filter_group!( RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_max_registrations_per_block), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_subnet_owner_cut), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_network_rate_limit), - RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_tempo), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_total_issuance), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_network_immunity_period), RuntimeCall::AdminUtils(AdminUtilsCall::sudo_set_network_min_lock_cost), diff --git a/runtime/src/proxy_filters/mod.rs b/runtime/src/proxy_filters/mod.rs index df1d936066..09bac7cb91 100644 --- a/runtime/src/proxy_filters/mod.rs +++ b/runtime/src/proxy_filters/mod.rs @@ -415,8 +415,10 @@ mod tests { assert!(owner.contains("AdminUtils::sudo_set_serving_rate_limit")); assert!(owner.contains("AdminUtils::sudo_set_max_difficulty")); assert!(owner.contains("SubtensorModule::set_subnet_identity")); + // Owner-or-root tempo control lives in AdminUtils. + assert!(owner.contains("AdminUtils::sudo_set_tempo")); + assert!(owner.contains("AdminUtils::sudo_set_activity_cutoff_factor")); // Root-only admin is not owner-settable (gated by `ensure_root`). - assert!(!owner.contains("AdminUtils::sudo_set_tempo")); assert!(!owner.contains("AdminUtils::sudo_set_kappa")); assert!(!owner.contains("AdminUtils::sudo_set_total_issuance")); assert!(!owner.contains("AdminUtils::swap_authorities")); diff --git a/sdk/python/bittensor/_generated/calls.py b/sdk/python/bittensor/_generated/calls.py index 31084b8998..ce5935daa7 100644 --- a/sdk/python/bittensor/_generated/calls.py +++ b/sdk/python/bittensor/_generated/calls.py @@ -420,11 +420,6 @@ def serve_prometheus(netuid: 'NetUid', version: 'u32', ip: 'u128', port: 'u16', 'Set prometheus information for the neuron. # Arguments * `origin`: The signature of the calling hotkey. * `netuid`: The u16 network identifier. * `version`: The bittensor version identifier. * `ip`: The prometheus ip information as a u128 encoded integer. * `port`: The prometheus port information as a u16 encoded integer. * `ip_type`: The ip type v4 or v6.' return Call('SubtensorModule', 'serve_prometheus', {'netuid': netuid, 'version': version, 'ip': ip, 'port': port, 'ip_type': ip_type}) - @staticmethod - def set_activity_cutoff_factor(netuid: 'NetUid', factor_milli: 'u32') -> Call: - '`set_activity_cutoff_factor`. Per-mille (1/1000) units; `cutoff_blocks = (factor × tempo) / 1000`. Validates `[MinActivityCutoffFactorMilli, MaxActivityCutoffFactorMilli]`. Callable by the subnet owner (rate-limited via `OwnerHyperparamUpdate`, respects the admin freeze window) or by root (bypasses both).' - return Call('SubtensorModule', 'set_activity_cutoff_factor', {'netuid': netuid, 'factor_milli': factor_milli}) - @staticmethod def set_auto_parent_delegation_enabled(hotkey: 'AccountId32', enabled: 'bool') -> Call: 'Allows a root validator to toggle auto parent delegation for new subnets owner hotkey' @@ -480,11 +475,6 @@ def set_subnet_identity(netuid: 'NetUid', subnet_name: 'Any', github_repo: 'Any' 'Set the identity information for a subnet. # Arguments * `origin`: The signature of the calling coldkey, which must be the owner of the subnet. * `netuid`: The unique network identifier of the subnet. * `subnet_name`: The name of the subnet. * `github_repo`: The GitHub repository associated with the subnet identity. * `subnet_contact`: The contact information for the subnet.' return Call('SubtensorModule', 'set_subnet_identity', {'netuid': netuid, 'subnet_name': subnet_name, 'github_repo': github_repo, 'subnet_contact': subnet_contact, 'subnet_url': subnet_url, 'discord': discord, 'description': description, 'logo_url': logo_url, 'additional': additional}) - @staticmethod - def set_tempo(netuid: 'NetUid', tempo: 'u16') -> Call: - 'Owner-side `set_tempo`. Validates `[MinTempo, MaxTempo]`, applies a fixed `MinTempo`-block cooldown via `TransactionType::TempoUpdate`, respects the admin freeze window, and resets the cycle (`LastEpochBlock = current_block`) on success.' - return Call('SubtensorModule', 'set_tempo', {'netuid': netuid, 'tempo': tempo}) - @staticmethod def set_weights(netuid: 'NetUid', dests: 'Any', weights: 'Any', version_key: 'u64') -> Call: 'Sets the caller weights for the incentive mechanism. The call can be made from the hotkey account so is potentially insecure, however, the damage of changing weights is minimal if caught early. This function includes all the checks that the passed weights meet the requirements. Stored as u16s they represent rational values in the range [0,1] which sum to 1 and can be interpreted as probabilities. The specific weights determine how inflation propagates outward from this peer. # Note The 16 bit integers weights should represent 1.0 as the max u16. However, the function normalizes all integers to u16_max anyway. This means that if the sum of all elements is larger or smaller than the amount of elements * u16_max, all elements will be corrected for this deviation. # Arguments * `origin`: The caller, a hotkey who wishes to set their weights. * `netuid`: The network uid we are setting these weights on. * `dests`: The edge endpoint for the weight, i.e. j for w_ij. * `weights`: The u16 integer encoded weights. Interpreted as rational values in the range [0,1]. They must sum to in32::MAX. * `version_key`: The network version key to check if the validator is up to date. # Events * `WeightsSet`: On successfully setting the weights on chain. # Errors * `MechanismDoesNotExist`: Attempting to set weights on a non-existent network. * `NotRegistered`: Attempting to set weights from a non registered account. * `WeightVecNotEqualSize`: Attempting to set weights with uids not of same length. * `DuplicateUids`: Attempting to set weights with duplicate uids. * `UidsLengthExceedUidsInSubNet`: Attempting to set weights above the max allowed uids. * `UidVecContainInvalidOne`: Attempting to set weights with invalid uids. * `WeightVecLengthIsLow`: Attempting to set weights with fewer weights than min. * `MaxWeightExceeded`: Attempting to set weights with max value exceeding limit.' @@ -867,6 +857,11 @@ def sudo_set_activity_cutoff(netuid: 'NetUid', activity_cutoff: 'u16') -> Call: 'The extrinsic sets the activity cutoff for a subnet. It is only callable by the root account or subnet owner. The extrinsic will call the Subtensor pallet to set the activity cutoff.' return Call('AdminUtils', 'sudo_set_activity_cutoff', {'netuid': netuid, 'activity_cutoff': activity_cutoff}) + @staticmethod + def sudo_set_activity_cutoff_factor(netuid: 'NetUid', factor_milli: 'u32') -> Call: + 'The extrinsic sets the activity-cutoff factor for a subnet, in per-mille (1/1000) of the tempo: the effective cutoff in blocks is `(factor × tempo) / 1000`. Bounded to `[MinActivityCutoffFactorMilli, MaxActivityCutoffFactorMilli]`. It is callable by the subnet owner (rate-limited via `OwnerHyperparamUpdate`, respects the admin freeze window) or the root account (bypasses both). This supersedes the absolute-blocks `sudo_set_activity_cutoff`.' + return Call('AdminUtils', 'sudo_set_activity_cutoff_factor', {'netuid': netuid, 'factor_milli': factor_milli}) + @staticmethod def sudo_set_adjustment_alpha(netuid: 'NetUid', adjustment_alpha: 'u64') -> Call: 'The extrinsic sets the adjustment alpha for a subnet. It is only callable by the root account or subnet owner. The extrinsic will call the Subtensor pallet to set the adjustment alpha.' @@ -1209,7 +1204,7 @@ def sudo_set_target_registrations_per_interval(netuid: 'NetUid', target_registra @staticmethod def sudo_set_tempo(netuid: 'NetUid', tempo: 'u16') -> Call: - 'The extrinsic sets the tempo for a subnet. It is only callable by the root account. The extrinsic will call the Subtensor pallet to set the tempo.' + 'The extrinsic sets the tempo for a subnet. It is callable by the subnet owner (bounded to `[MinTempo, MaxTempo]` and rate-limited to one change per `MinTempo` blocks) or the root account (any u16, no rate limit). Both respect the admin freeze window. A successful change resets the epoch cycle (`LastEpochBlock = current_block`).' return Call('AdminUtils', 'sudo_set_tempo', {'netuid': netuid, 'tempo': tempo}) @staticmethod diff --git a/sdk/python/bittensor/cli/main.py b/sdk/python/bittensor/cli/main.py index 911d3890be..d17de29373 100644 --- a/sdk/python/bittensor/cli/main.py +++ b/sdk/python/bittensor/cli/main.py @@ -24,8 +24,8 @@ from ..config import get as config_default from ..error_descriptions import DESCRIPTIONS from ..intents import list_tools -from ..result import EXPLANATIONS, REMEDIATION, ErrorCode, classify_error -from ..settings import DEFAULT_NETWORK +from ..result import EXPLANATIONS, REMEDIATION, ChainError, ErrorCode, classify_error +from ..settings import DEFAULT_NETWORK, chain_error_docs_url, error_docs_url from . import globals as g from . import help_theme # noqa: F401 (restyles typer's --help at import) from .call import call as call_command @@ -328,7 +328,16 @@ def _chain_error_matches(query: str) -> list[dict[str, str]]: "code": code.value, "docs": info.docs, "description": DESCRIPTIONS.get(info.name, ""), - "help": REMEDIATION[code], + # Same remediation a failure would print (per-name overrides + # like SlippageTooHigh's tolerance flags included). + "help": ChainError("", name=info.name).remediation, + # The exact name's page when it is classified (and thus has + # one), the semantic code's page otherwise. + "docs_url": ( + chain_error_docs_url(info.name) + if info.name in DESCRIPTIONS + else error_docs_url(code.value) + ), } ) return matches @@ -349,6 +358,9 @@ def _chain_error_catalog(out: Output, pallet: Optional[str]) -> None: "name": info.name, "code": classify_error(info.docs, info.name).value, "description": info.docs, + "docs_url": ( + chain_error_docs_url(info.name) if info.name in DESCRIPTIONS else None + ), } for info in ERRORS.values() if pallet is None or info.pallet.lower() == pallet.lower() diff --git a/sdk/python/bittensor/cli/metagraph_view.py b/sdk/python/bittensor/cli/metagraph_view.py index 1967c84630..3ef561c3cb 100644 --- a/sdk/python/bittensor/cli/metagraph_view.py +++ b/sdk/python/bittensor/cli/metagraph_view.py @@ -4,7 +4,8 @@ primary, dim readings beside them — the hyperparameters convention); the per-uid arrays collapse into one tree branch per neuron, largest stake first, hotkeys labeled with their local wallet name when one exists, else their -on-chain identity name. JSON carries the raw metagraph record untouched. +on-chain identity name. JSON carries the runtime record as the read returns +it (untouched except `name`/`symbol`, which the read decodes to text). """ from __future__ import annotations diff --git a/sdk/python/bittensor/cli/output.py b/sdk/python/bittensor/cli/output.py index 49f8b1dc15..945c4549cb 100644 --- a/sdk/python/bittensor/cli/output.py +++ b/sdk/python/bittensor/cli/output.py @@ -27,7 +27,12 @@ from ..balance import Balance from ..intents import Plan from ..result import ErrorCode, ExtrinsicResult -from ..settings import explorer_account_url, explorer_extrinsic_url, explorer_subnet_url +from ..settings import ( + error_docs_url, + explorer_account_url, + explorer_extrinsic_url, + explorer_subnet_url, +) from . import multisig_helpers as ms_helpers # Stripe-muted palette: almost monochrome — dim for structure (titles, keys, @@ -427,23 +432,65 @@ def detail( return self._print_fields(fields) - def _print_fields(self, fields: dict[str, Any]) -> None: - """Aligned key/value block: dim keys, values colored by semantic role.""" - width = max((len(k) for k in fields), default=0) - for key, value in fields.items(): - # Built with Text (not markup) so values containing "[" render as-is. - line = Text(" ") - line.append(key.rjust(width), style=STYLE_KEY) + def _print_fields(self, fields: dict[str, Any], indent: int = 2) -> None: + """Aligned key/value block: dim keys, values colored by semantic role. + + Structured values stay legible instead of printing as raw reprs: dict + values recurse as indented sub-blocks, lists of records render one + compact line per record, and lists of scalars join with commas. + """ + # Reads like subnet_names / weights key by int; coerce for display only. + labels = [(str(key), value) for key, value in fields.items()] + width = max((len(label) for label, _ in labels), default=0) + for label, value in labels: + # Built with Text (not markup) so values containing "[" render + # as-is; never wrapped (addresses and hashes are copy targets). + line = Text(" " * indent, overflow="ignore", no_wrap=True) + line.append(label.rjust(width), style=STYLE_KEY) + if isinstance(value, (dict, list)) and not value: + line.append(" ") + line.append("none", style="dim") + self._out.print(line) + continue + if isinstance(value, dict): + self._out.print(line) + self._print_fields(value, indent + 2) + continue + if isinstance(value, list) and all(isinstance(item, dict) for item in value): + self._out.print(line) + for item in value: + self._out.print(self._record_line(item, indent + 2), soft_wrap=True) + continue line.append(" ") - if key.endswith("netuid") and str(value).isdigit(): + if isinstance(value, list): + value = ", ".join(str(item) for item in value) + if label.endswith("netuid") and str(value).isdigit(): line.append_text(self.subnet_text(value)) else: line.append_text( self._linked_text( - str(value), _value_style(key, value), _address_kind_for_key(key) + str(value), + _value_style(label, value), + _address_kind_for_key(label), ) ) - self._out.print(line) + self._out.print(line, soft_wrap=True) + + def _record_line(self, record: dict[str, Any], indent: int) -> Text: + """One record as a compact ``key value key value`` line (list items + inside a detail block, e.g. proxies or stake positions).""" + line = Text(" " * indent, overflow="ignore", no_wrap=True) + for index, (key, value) in enumerate(record.items()): + label = str(key) + if index: + line.append(" ") + line.append(f"{label} ", style=STYLE_KEY) + line.append_text( + self._linked_text( + str(value), _value_style(label, value), _address_kind_for_key(label) + ) + ) + return line def hyperparameters( self, @@ -1515,6 +1562,8 @@ def _print_failure(self, result: ExtrinsicResult) -> None: if error.description: self._sub_diag("note", error.description) self._sub_diag("help", error.remediation) + if error.docs_url: + self._sub_diag("see", error.docs_url) if result.explorer_url: self._sub_diag("see", result.explorer_url) # The exact chain name gives the most specific explanation; the semantic @@ -1532,13 +1581,21 @@ def _print_failure(self, result: ExtrinsicResult) -> None: def explain(self, code: str, explanation: str, help_text: str) -> None: """Long-form explanation of one error code (`rustc --explain` convention).""" if self.json_mode: - self._json({"code": code, "explanation": explanation, "help": help_text}) + self._json( + { + "code": code, + "explanation": explanation, + "help": help_text, + "see": error_docs_url(code), + } + ) return self._out.print(Text(f"error[{code}]", style=STYLE_ERROR)) self._out.print() self._out.print(_prose(explanation)) self._out.print() self._sub_diag("help", help_text, console=self._out) + self._sub_diag("see", error_docs_url(code), console=self._out) def error_catalog(self, title: str, records: list[dict[str, str]]) -> None: """The chain error catalog as a gh-style listing: one dim pallet header @@ -1559,7 +1616,8 @@ def error_catalog(self, title: str, records: list[dict[str, str]]) -> None: self._out.print() self._out.print(Text(pallet, style=STYLE_KEY)) line = Text(" ", overflow="ignore", no_wrap=True) - line.append(record["name"].ljust(width)) + url = record.get("docs_url") + line.append(record["name"].ljust(width), style=f"link {url}" if url else "") line.append(" ") line.append(record["code"], style=STYLE_KEY) self._out.print(line, soft_wrap=True) @@ -1592,6 +1650,8 @@ def explain_chain(self, matches: list[dict[str, str]]) -> None: self._out.print(_prose(_diagnostic(body))) self._out.print() self._sub_diag("help", match["help"], console=self._out) + see = match.get("docs_url") or error_docs_url(match["code"]) + self._sub_diag("see", see, console=self._out) for code in dict.fromkeys(match["code"] for match in matches): tail = _prose(f"for more information about this code, run `btcli explain {code}`") tail.style = STYLE_HINT diff --git a/sdk/python/bittensor/cli/query.py b/sdk/python/bittensor/cli/query.py index 688b7cadc1..b620ba4127 100644 --- a/sdk/python/bittensor/cli/query.py +++ b/sdk/python/bittensor/cli/query.py @@ -15,9 +15,10 @@ import typer from ..balance import Balance -from ..reads import REGISTRY +from ..reads import REGISTRY, Grouped, Matrix from . import globals as g from .context import address_cli_name, ctx_of, ss58_param_help +from .output import Output _TYPES = {"string": str, "integer": int, "number": float, "boolean": bool} @@ -37,6 +38,22 @@ def _jsonable(obj: Any) -> Any: return obj +def _records_table(output: Output, name: str, records: list[dict]) -> None: + """Render a list of records as a table, hiding opaque columns. + + Columns whose values are themselves dicts/lists (e.g. the neurons read's + ``raw`` blob) are unreadable in a table cell, so they are dropped from the + human view — ``--json`` carries the full records. + """ + if not records: + output.detail(name, {}) # title + the dim `none` convention + return + cols = [c for c, v in records[0].items() if not isinstance(v, (dict, list))] + cols = cols or list(records[0].keys()) + rows = [[r.get(c) for c in cols] for r in records] + output.table(name, cols, rows, records) + + def _make_command(name: str, spec): array_params = [p for p, t in spec.params.items() if t == "array"] @@ -50,16 +67,35 @@ def command(ctx: typer.Context, **kwargs: Any) -> None: kwargs[pname] = app_ctx.resolve_address(pname, kwargs.get(pname)) result = app_ctx.run(lambda client: client.read(name, **kwargs)) payload = _jsonable(result) - if app_ctx.output.json_mode: - app_ctx.output.value(payload) - elif isinstance(payload, list) and payload and isinstance(payload[0], dict): - cols = list(payload[0].keys()) - rows = [[r.get(c) for c in cols] for r in payload] - app_ctx.output.table(name, cols, rows, payload) + output = app_ctx.output + if output.json_mode: + output.value(payload) + elif payload is None or (isinstance(payload, (list, dict)) and not payload): + output.detail(name, {}) # title + the dim `none` convention + elif isinstance(spec.render, Grouped): + key = spec.render.key + _records_table( + output, + name, + [{key: group, **item} for group, items in payload.items() for item in items or []], + ) + elif isinstance(spec.render, Matrix): + hint = spec.render + _records_table( + output, + name, + [ + {hint.row: row, hint.col: col, hint.value: value} + for row, cells in payload.items() + for col, value in cells.items() + ], + ) + elif isinstance(payload, list) and isinstance(payload[0], dict): + _records_table(output, name, payload) elif isinstance(payload, dict): - app_ctx.output.detail(name, payload) + output.detail(name, payload) else: - app_ctx.output.value(payload) + output.value(payload) params = [ inspect.Parameter("ctx", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=typer.Context) diff --git a/sdk/python/bittensor/error_descriptions.py b/sdk/python/bittensor/error_descriptions.py index b1219e8f72..ff039ad6bc 100644 --- a/sdk/python/bittensor/error_descriptions.py +++ b/sdk/python/bittensor/error_descriptions.py @@ -1634,8 +1634,9 @@ "`SYMBOLS` list and choose a valid entry." ), "TempoOutOfBounds": ( - "`set_tempo` was given a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range. Check " - "the tempo argument against those chain constants and pick a value inside the bounds." + "The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to " + "MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain " + "constants and pick a value inside the bounds; only root may set a tempo outside them." ), "TooManyChildren": ( "`set_children` was called with more than 5 child hotkeys for a parent on the subnet. " diff --git a/sdk/python/bittensor/hyperparams.py b/sdk/python/bittensor/hyperparams.py index 71253db6f1..f1333a2e3d 100644 --- a/sdk/python/bittensor/hyperparams.py +++ b/sdk/python/bittensor/hyperparams.py @@ -128,7 +128,9 @@ class Hyperparam: ), "tempo": Hyperparam( "blocks", - "Blocks per epoch: how often the subnet runs consensus and distributes emissions.", + "Blocks per epoch: how often the subnet runs consensus and distributes " + "emissions. Owner changes are bounded to 360-50,400 blocks, rate-limited " + "to one per 360 blocks, and reset the epoch cycle.", short="blocks per consensus epoch", ), "min_difficulty": Hyperparam( @@ -168,9 +170,17 @@ class Hyperparam: "activity_cutoff": Hyperparam( "blocks", "Blocks without setting weights after which a validator is considered " - "inactive and excluded from consensus.", + "inactive and excluded from consensus. Read-only: the epoch derives it " + "as activity_cutoff_factor x tempo / 1000.", short="no-weights window before inactive", ), + "activity_cutoff_factor": Hyperparam( + "int", + "Activity cutoff as per-mille of tempo (1000 = one tempo, bounds " + "1,000-50,000): the effective cutoff is factor x tempo / 1000 blocks. " + "Supersedes the absolute-blocks activity_cutoff.", + short="activity cutoff, per-mille of tempo", + ), "registration_allowed": Hyperparam( "bool", "Whether new neuron registrations are currently accepted on this subnet.", @@ -296,6 +306,25 @@ class Hyperparam: "Whether the Yuma3 consensus variant is enabled for this subnet.", short="yuma3 consensus variant toggle", ), + "yuma_version": Hyperparam( + "int", + "Consensus variant the epoch runs: 2 for classic Yuma, 3 when " + "yuma3_enabled is set. Derived from that flag, not stored on chain.", + short="epoch consensus variant (2 or 3)", + ), + "subnet_is_active": Hyperparam( + "bool", + "Whether the owner's one-shot start_call has fired: staking, alpha " + "trading, and emissions are live. False for a registered-but-unstarted " + "subnet.", + short="subnet started (staking + emissions)", + ), + "user_liquidity_enabled": Hyperparam( + "bool", + "Legacy swap-v3 flag for user-provided liquidity positions; always " + "false since the balancer migration deprecated all user LP calls.", + short="legacy user-LP flag (always false)", + ), "bonds_reset_enabled": Hyperparam( "bool", "Whether validator bonds are reset on certain subnet events.", @@ -338,6 +367,7 @@ class Hyperparam: "weights_rate_limit": st.SubtensorModule.WeightsSetRateLimit, "adjustment_interval": st.SubtensorModule.AdjustmentInterval, "activity_cutoff": st.SubtensorModule.ActivityCutoff, + "activity_cutoff_factor": st.SubtensorModule.ActivityCutoffFactorMilli, "registration_allowed": st.SubtensorModule.NetworkRegistrationAllowed, "network_pow_registration_allowed": st.SubtensorModule.NetworkPowRegistrationAllowed, "target_regs_per_interval": st.SubtensorModule.TargetRegistrationsPerInterval, diff --git a/sdk/python/bittensor/intents/hyperparameters.py b/sdk/python/bittensor/intents/hyperparameters.py index 59d0bce79e..d4acbda580 100644 --- a/sdk/python/bittensor/intents/hyperparameters.py +++ b/sdk/python/bittensor/intents/hyperparameters.py @@ -8,6 +8,10 @@ chain and keeps the other side. Root-only params, the enum-valued ``recycle_or_burn``, and ``sn_owner_hotkey`` are left to the raw-call escape hatch. +``activity_cutoff`` is read-only here: the epoch derives the effective cutoff +from ``activity_cutoff_factor`` (per-mille of tempo), so the legacy +absolute-blocks setter is deliberately not exposed. + Read current values back with the ``subnet_hyperparameters`` read. """ @@ -25,10 +29,11 @@ # name -> (AdminUtils setter, value is boolean). Every setter takes (netuid, value), # except the alpha pair below, which shares the two-value sudo_set_alpha_values. OWNER_HYPERPARAMETERS: dict[str, tuple[str, bool]] = { + "tempo": ("sudo_set_tempo", False), "immunity_period": ("sudo_set_immunity_period", False), "min_allowed_weights": ("sudo_set_min_allowed_weights", False), "weights_version": ("sudo_set_weights_version_key", False), - "activity_cutoff": ("sudo_set_activity_cutoff", False), + "activity_cutoff_factor": ("sudo_set_activity_cutoff_factor", False), "min_burn": ("sudo_set_min_burn", False), "max_burn": ("sudo_set_max_burn", False), "bonds_moving_avg": ("sudo_set_bonds_moving_average", False), diff --git a/sdk/python/bittensor/namespaces.pyi b/sdk/python/bittensor/namespaces.pyi index 8155e026ca..e51da52500 100644 --- a/sdk/python/bittensor/namespaces.pyi +++ b/sdk/python/bittensor/namespaces.pyi @@ -430,8 +430,14 @@ class Subnets(_ReadNamespace): async def subnet(self, netuid: int, *, block: Optional[int] = None) -> SubnetInfo: """Tempo, burn, and neuron count for one subnet (the three reads run concurrently).""" - async def subnet_hyperparameters(self, netuid: int, *, block: Optional[int] = None) -> dict: - """All hyperparameters for a subnet (named fields; version-dependent set).""" + async def subnet_hyperparameters(self, netuid: int, *, block: Optional[int] = None) -> Optional[dict]: + """All hyperparameters for a subnet, as a flat name -> raw value mapping. + + The set of names is version-dependent; None if the subnet does not exist. + Uses the forward-compatible `get_subnet_hyperparams_v3` runtime API, so + newly added chain hyperparameters (e.g. `burn_half_life`) show up + without a client update. + """ async def subnet_identity(self, netuid: int, *, block: Optional[int] = None) -> Optional[dict]: """The identity metadata of a subnet, or None.""" diff --git a/sdk/python/bittensor/reads/__init__.py b/sdk/python/bittensor/reads/__init__.py index 7c0c64ad2f..eec7989f8c 100644 --- a/sdk/python/bittensor/reads/__init__.py +++ b/sdk/python/bittensor/reads/__init__.py @@ -29,7 +29,7 @@ weights, ) from .accounts import balance, balances, existential_deposit -from .base import REGISTRY, ReadSpec, dispatch, list_reads, read +from .base import REGISTRY, Grouped, Matrix, ReadSpec, dispatch, list_reads, read from .delegation import DelegatedStake, DelegateInfo from .identity import Commitment from .neurons import Neuron @@ -42,6 +42,8 @@ "Commitment", "DelegateInfo", "DelegatedStake", + "Grouped", + "Matrix", "Neuron", "ReadSpec", "StakePosition", diff --git a/sdk/python/bittensor/reads/base.py b/sdk/python/bittensor/reads/base.py index e76c85ad8a..d8c24a3f26 100644 --- a/sdk/python/bittensor/reads/base.py +++ b/sdk/python/bittensor/reads/base.py @@ -23,7 +23,31 @@ import inspect from dataclasses import dataclass -from typing import Any, Awaitable, Callable, Optional +from typing import Any, Awaitable, Callable, Optional, Union + + +@dataclass(frozen=True) +class Grouped: + """Render hint for ``{group: [record, ...]}`` results: flatten to a table + with ``key`` as the leading column (e.g. epoch for weight commits).""" + + key: str + + +@dataclass(frozen=True) +class Matrix: + """Render hint for ``{row: {col: value}}`` results: flatten to a long-form + three-column table with these column names.""" + + row: str + col: str + value: str + + +# A read whose result isn't naturally a flat record/list declares its shape +# here, and the generated `query` command renders it as a table instead of +# falling back to a key/value dump of the raw mapping. +RenderHint = Union[Grouped, Matrix] @dataclass @@ -34,6 +58,7 @@ class ReadSpec: fetch: Callable[..., Awaitable[Any]] category: str # topical grouping, rendered as a help panel by `query --help` param_docs: dict[str, str] # param name -> meaning, for --help and the catalog + render: Optional[RenderHint] = None # table shape for non-record results @property def summary(self) -> str: @@ -49,12 +74,15 @@ def read( *, category: str, param_docs: Optional[dict[str, str]] = None, + render: Optional[RenderHint] = None, ): """Register a read under a stable machine name. ``param_docs`` documents what each param means; it feeds the generated ``query`` command's option help and the agent catalog. Address params (``*_ss58``) get their accepted-input-shapes note appended automatically. + ``render`` declares the table shape for results that aren't flat records + (see :data:`RenderHint`). """ def decorate(fn: Callable[..., Awaitable[Any]]) -> Callable[..., Awaitable[Any]]: @@ -64,7 +92,7 @@ def decorate(fn: Callable[..., Awaitable[Any]]) -> Callable[..., Awaitable[Any]] unknown = set(param_docs or {}) - set(params or {}) if unknown: raise ValueError(f"param_docs for unknown params of read {name!r}: {sorted(unknown)}") - REGISTRY[name] = ReadSpec(name, doc, params or {}, fn, category, param_docs or {}) + REGISTRY[name] = ReadSpec(name, doc, params or {}, fn, category, param_docs or {}, render) return fn return decorate @@ -108,9 +136,16 @@ async def fetch(view, netuid: Optional[int] = None) -> int: def utf8_text(value: Any) -> Any: - """Decode chain byte-strings (hex or bytes) to text where possible.""" + """Decode chain byte-strings (hex, bytes, or byte-value lists) to text + where possible. Compact-u16 vectors (e.g. the metagraph's ``name`` and + ``symbol``) arrive as lists of ints carrying utf-8 bytes.""" if isinstance(value, str) and value.startswith("0x"): value = bytes.fromhex(value[2:]) + if isinstance(value, (list, tuple)): + try: + value = bytes(int(b) for b in value) + except (TypeError, ValueError): + return value if isinstance(value, (bytes, bytearray)): try: return value.decode("utf-8") diff --git a/sdk/python/bittensor/reads/subnets.py b/sdk/python/bittensor/reads/subnets.py index 87f7fff1d9..b24c38942b 100644 --- a/sdk/python/bittensor/reads/subnets.py +++ b/sdk/python/bittensor/reads/subnets.py @@ -94,15 +94,36 @@ async def commit_reveal_enabled(view, netuid: int) -> bool: return bool(value) +def _hyperparam_value(tagged: dict) -> object: + """Flatten one v3 ``{type_tag: payload}`` value to its raw payload. + + Fixed-point newtypes (U64F64/I32F32) decode as ``{'bits': raw}``; the raw + bits are the value `sudo set` writes and `hyperparams.annotate` reads. + """ + ((_tag, payload),) = tagged.items() + if isinstance(payload, dict) and set(payload) == {"bits"}: + return payload["bits"] + return payload + + @read( "subnet_hyperparameters", {"netuid": "integer"}, category="Subnets", param_docs={"netuid": "Subnet to query."}, ) -async def subnet_hyperparameters(view, netuid: int) -> dict: - """All hyperparameters for a subnet (named fields; version-dependent set).""" - return await view.runtime(api.SubnetInfoRuntimeApi.get_subnet_hyperparams, [netuid]) +async def subnet_hyperparameters(view, netuid: int) -> Optional[dict]: + """All hyperparameters for a subnet, as a flat name -> raw value mapping. + + The set of names is version-dependent; None if the subnet does not exist. + Uses the forward-compatible ``get_subnet_hyperparams_v3`` runtime API, so + newly added chain hyperparameters (e.g. ``burn_half_life``) show up + without a client update. + """ + entries = await view.runtime(api.SubnetInfoRuntimeApi.get_subnet_hyperparams_v3, [netuid]) + if entries is None: + return None + return {entry["name"]: _hyperparam_value(entry["value"]) for entry in entries} @read( @@ -112,8 +133,17 @@ async def subnet_hyperparameters(view, netuid: int) -> dict: param_docs={"netuid": "Subnet whose metagraph to fetch."}, ) async def metagraph(view, netuid: int) -> dict: - """The full metagraph for a subnet in one call (stakes, ranks, emissions, axons, ...).""" - return await view.runtime(api.SubnetInfoRuntimeApi.get_metagraph, [netuid]) + """The full metagraph for a subnet in one call (stakes, ranks, emissions, axons, ...). + + `name` and `symbol` are decoded to text (the wire carries them as + compact-u16 vectors of utf-8 bytes, unlike every other text field). + """ + graph = await view.runtime(api.SubnetInfoRuntimeApi.get_metagraph, [netuid]) + if isinstance(graph, dict): + for key in ("name", "symbol"): + if key in graph: + graph[key] = utf8_text(graph[key]) + return graph @read( diff --git a/sdk/python/bittensor/reads/weights.py b/sdk/python/bittensor/reads/weights.py index 3fed42351f..6080d5ae74 100644 --- a/sdk/python/bittensor/reads/weights.py +++ b/sdk/python/bittensor/reads/weights.py @@ -6,7 +6,7 @@ from .._generated import storage as st from ..hyperparams import ratio_fraction from ..settings import GLOBAL_MAX_SUBNET_COUNT -from .base import read +from .base import Grouped, Matrix, read def _mechanism_index(netuid: int, mechid: int) -> int: @@ -27,6 +27,7 @@ def _mechanism_index(netuid: int, mechid: int) -> int: "netuid": "Subnet whose weight matrix to fetch.", "mechid": _MECHID_DOC, }, + render=Matrix("validator", "miner", "weight"), ) async def weights(view, netuid: int, mechid: int = 0) -> dict[int, dict[int, float]]: """Validator weight rows as ``{validator_uid: {miner_uid: fraction}}``, each row summing to 1. @@ -53,6 +54,7 @@ async def weights(view, netuid: int, mechid: int = 0) -> dict[int, dict[int, flo "netuid": "Subnet whose bond matrix to fetch.", "mechid": _MECHID_DOC, }, + render=Matrix("validator", "miner", "bond"), ) async def bonds(view, netuid: int, mechid: int = 0) -> dict[int, dict[int, float]]: """Validator bond rows as ``{validator_uid: {miner_uid: bond}}``, scaled to 0..1. @@ -82,6 +84,7 @@ async def bonds(view, netuid: int, mechid: int = 0) -> dict[int, dict[int, float "netuid": "Subnet whose pending weight commits to list.", "mechid": _MECHID_DOC, }, + render=Grouped("epoch"), ) async def timelocked_weight_commits(view, netuid: int, mechid: int = 0) -> dict[int, list[dict]]: """Pending (still-encrypted) commit-reveal weight commits, grouped by epoch. diff --git a/sdk/python/bittensor/result.py b/sdk/python/bittensor/result.py index f1c5d27945..ca298e9a3c 100644 --- a/sdk/python/bittensor/result.py +++ b/sdk/python/bittensor/result.py @@ -15,6 +15,7 @@ from .error_descriptions import DESCRIPTIONS as _DESCRIPTIONS from .error_map import NAME_TO_CODE as _NAME_TO_CODE from .error_map import ErrorCode +from .settings import chain_error_docs_url, error_docs_url class BittensorError(Exception): @@ -328,8 +329,21 @@ def to_dict(self) -> dict[str, Any]: } if self.description: payload["description"] = self.description + if docs_url := self.docs_url: + payload["docs_url"] = docs_url return payload + @property + def docs_url(self) -> Optional[str]: + """The most specific docs page for this failure: the exact chain + error's page when the name is classified, the semantic code's page + otherwise, None when nothing more specific than unknown is known.""" + if self.name and self.name in _NAME_TO_CODE: + return chain_error_docs_url(self.name) + if self.code is not ErrorCode.UNKNOWN: + return error_docs_url(self.code.value) + return None + def chain_error_from_substrate_request(error: Exception) -> ChainError: """Build a ChainError from a transport-layer request failure.""" diff --git a/sdk/python/bittensor/settings.py b/sdk/python/bittensor/settings.py index 59a25ed6d8..bb603e7d53 100644 --- a/sdk/python/bittensor/settings.py +++ b/sdk/python/bittensor/settings.py @@ -104,6 +104,18 @@ def resolve_endpoint(network: str) -> tuple[str, str]: # output link here). DOCS_URL = "https://www.bittensor.com/docs" + +def error_docs_url(code_value: str) -> str: + """Docs explainer page for a semantic error code (e.g. insufficient_balance).""" + return f"{DOCS_URL}/errors/{code_value.replace('_', '-')}" + + +def chain_error_docs_url(name: str) -> str: + """Docs explainer page for an exact chain error name (e.g. SlippageTooHigh). + + The docs keep the on-chain CamelCase name in the URL, so no mangling.""" + return f"{DOCS_URL}/errors/chain/{name}" + # Public block-explorer pages for an extrinsic, keyed by network label. ``{id}`` # is the on-chain extrinsic identifier "block_number-index" (index zero-padded # to 4 digits), the format both taostats and taomarketcap use. taomarketcap is diff --git a/sdk/python/codegen/check.py b/sdk/python/codegen/check.py index 83c419b572..130cbd5bb8 100644 --- a/sdk/python/codegen/check.py +++ b/sdk/python/codegen/check.py @@ -80,11 +80,9 @@ def check_drift(endpoint: str) -> int: "sudo_set_root_claim_threshold", "sudo_set_tx_childkey_take_rate_limit", "sudo_set_voting_power_ema_alpha", - "set_tempo", "trigger_epoch", "dissolve_network", "root_dissolve_network", - "set_activity_cutoff_factor", # legacy / superseded weight paths (mechanism variants are wrapped; # reveal_weights is wrapped by the RevealWeights intent for salt commits) "set_weights", @@ -215,6 +213,10 @@ def check_drift(endpoint: str) -> int: # Enumerated explicitly (not computed) so a newly added unwrapped call is # flagged as missing and requires a deliberate wrap-or-raw-only decision. "schedule_grandpa_change", + # legacy absolute-blocks cutoff — superseded by the owner-settable + # `sudo_set_activity_cutoff_factor` (per-mille of tempo), which the + # SetHyperparameter intent wraps as `activity_cutoff_factor` + "sudo_set_activity_cutoff", "sudo_set_adjustment_interval", "sudo_set_admin_freeze_window", "sudo_set_ck_burn", @@ -257,7 +259,6 @@ def check_drift(endpoint: str) -> int: "sudo_set_tao_flow_normalization_exponent", "sudo_set_tao_flow_smoothing_factor", "sudo_set_target_registrations_per_interval", - "sudo_set_tempo", "sudo_set_total_issuance", "sudo_set_tx_delegate_take_rate_limit", "sudo_set_tx_rate_limit", diff --git a/sdk/python/tests/unit/test_reads_table.py b/sdk/python/tests/unit/test_reads_table.py index 44c4bf2b73..d2f332a664 100644 --- a/sdk/python/tests/unit/test_reads_table.py +++ b/sdk/python/tests/unit/test_reads_table.py @@ -38,7 +38,7 @@ def seeded_substrate() -> FakeSubstrate: ("NeuronInfoRuntimeApi", "get_neurons", []), ("SubnetInfoRuntimeApi", "get_all_dynamic_info", []), ("SubnetInfoRuntimeApi", "get_dynamic_info", None), - ("SubnetInfoRuntimeApi", "get_subnet_hyperparams_v2", None), + ("SubnetInfoRuntimeApi", "get_subnet_hyperparams_v3", None), ("SubnetInfoRuntimeApi", "get_subnet_state", None), ("StakeInfoRuntimeApi", "get_stake_info_for_coldkey", []), ("StakeInfoRuntimeApi", "get_stake_info_for_coldkeys", []), diff --git a/website/apps/bittensor-website/README.md b/website/apps/bittensor-website/README.md index 423d1267b8..3bac9034f9 100644 --- a/website/apps/bittensor-website/README.md +++ b/website/apps/bittensor-website/README.md @@ -12,7 +12,7 @@ anything on Bittensor. That folder is the single source of truth for all docs: user-facing concepts and guides, the generated reference, and runtime/contributor internals (`docs/internals/`). -The reference section (`docs/tx`, `docs/query`, `docs/errors.mdx`) and the +The reference section (`docs/tx`, `docs/query`, `docs/errors`) and the JSON catalogs (`public/catalog/`) are **generated** from the SDK's own registries — never edit them by hand: diff --git a/website/apps/bittensor-website/public/catalog/errors.json b/website/apps/bittensor-website/public/catalog/errors.json index f657e64cab..af92ff95f2 100644 --- a/website/apps/bittensor-website/public/catalog/errors.json +++ b/website/apps/bittensor-website/public/catalog/errors.json @@ -1,1436 +1,1843 @@ { "codes": { - "insufficient_balance": "fund the signing account or reduce the amount; check with `btcli wallet balance`", - "insufficient_liquidity": "the pool cannot absorb this trade; reduce the amount or split it into smaller steps", - "rate_limited": "wait for the rate-limit window to pass, then retry", - "not_registered": "register the hotkey on this subnet first with `btcli subnets register`", - "not_authorized": "sign with the key or origin that owns the target object, then retry", - "already_exists": "the object or state already exists; treat the goal as met or pick a different target", - "not_found": "the referenced object is not on-chain; check the identifier", - "subnet_not_exists": "use an existing netuid; `btcli subnets list` shows valid ones", - "subtoken_disabled": "the subnet is not active yet; wait for start_call", - "disabled": "this call or feature is switched off on this network", - "too_early": "the required window has not opened yet; wait some blocks and retry", - "expired": "the window has closed; restart the flow with fresh state", - "limit_exceeded": "a chain-side capacity limit was hit; reduce the size or count of the request", - "unit_mismatch": "match the Balance netuid to the operation's currency", - "invalid_argument": "check the argument values against the operation schema", - "policy_violation": "the action exceeds a configured safety policy", - "internal": "a chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists", - "unknown": "inspect the message for details" + "insufficient_balance": { + "remediation": "fund the signing account or reduce the amount; check with `btcli wallet balance`", + "docs_url": "/docs/errors/insufficient-balance" + }, + "insufficient_liquidity": { + "remediation": "the pool cannot absorb this trade; reduce the amount or split it into smaller steps", + "docs_url": "/docs/errors/insufficient-liquidity" + }, + "rate_limited": { + "remediation": "wait for the rate-limit window to pass, then retry", + "docs_url": "/docs/errors/rate-limited" + }, + "not_registered": { + "remediation": "register the hotkey on this subnet first with `btcli subnets register`", + "docs_url": "/docs/errors/not-registered" + }, + "not_authorized": { + "remediation": "sign with the key or origin that owns the target object, then retry", + "docs_url": "/docs/errors/not-authorized" + }, + "already_exists": { + "remediation": "the object or state already exists; treat the goal as met or pick a different target", + "docs_url": "/docs/errors/already-exists" + }, + "not_found": { + "remediation": "the referenced object is not on-chain; check the identifier", + "docs_url": "/docs/errors/not-found" + }, + "subnet_not_exists": { + "remediation": "use an existing netuid; `btcli subnets list` shows valid ones", + "docs_url": "/docs/errors/subnet-not-exists" + }, + "subtoken_disabled": { + "remediation": "the subnet is not active yet; wait for start_call", + "docs_url": "/docs/errors/subtoken-disabled" + }, + "disabled": { + "remediation": "this call or feature is switched off on this network", + "docs_url": "/docs/errors/disabled" + }, + "too_early": { + "remediation": "the required window has not opened yet; wait some blocks and retry", + "docs_url": "/docs/errors/too-early" + }, + "expired": { + "remediation": "the window has closed; restart the flow with fresh state", + "docs_url": "/docs/errors/expired" + }, + "limit_exceeded": { + "remediation": "a chain-side capacity limit was hit; reduce the size or count of the request", + "docs_url": "/docs/errors/limit-exceeded" + }, + "unit_mismatch": { + "remediation": "match the Balance netuid to the operation's currency", + "docs_url": "/docs/errors/unit-mismatch" + }, + "invalid_argument": { + "remediation": "check the argument values against the operation schema", + "docs_url": "/docs/errors/invalid-argument" + }, + "policy_violation": { + "remediation": "the action exceeds a configured safety policy", + "docs_url": "/docs/errors/policy-violation" + }, + "internal": { + "remediation": "a chain-side invariant failed; nothing to fix client-side \u2014 report it if it persists", + "docs_url": "/docs/errors/internal" + }, + "unknown": { + "remediation": "inspect the message for details", + "docs_url": "/docs/errors/unknown" + } }, "chain_errors": { "AccountNotAllowedCommit": { "code": "not_authorized", - "description": "Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet." + "description": "Raised by `set_commitment` when the runtime commit check fails: the subnet must exist and the signing hotkey must be registered on it. Verify the `netuid` and that the hotkey has a UID on that subnet.", + "docs_url": "/docs/errors/chain/AccountNotAllowedCommit" }, "AccountRejectsLockedAlpha": { "code": "invalid_argument", - "description": "Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying." + "description": "Locked alpha was being transferred to a coldkey whose `AccountFlags` do not have the accept-locked-alpha bit set, e.g. during a lock transfer or coldkey swap of locks. Check the destination coldkey's `AccountFlags` storage and have the recipient opt in to receiving locked alpha before retrying.", + "docs_url": "/docs/errors/chain/AccountRejectsLockedAlpha" }, "ActiveLockExists": { "code": "already_exists", - "description": "The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first." + "description": "The destination coldkey already holds a lock with nonzero locked mass on that subnet, so a new or transferred lock cannot be created there. Inspect the `Lock` storage for the (coldkey, netuid, hotkey) triple and wait for the existing lock to unlock or remove it first.", + "docs_url": "/docs/errors/chain/ActiveLockExists" }, "ActivityCutoffFactorMilliOutOfBounds": { "code": "invalid_argument", - "description": "The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting." + "description": "The `factor_milli` argument to set the activity-cutoff factor was outside the allowed 1000-50000 per-mille range (1 to 50 tempos). Adjust the argument to fall within those bounds before resubmitting.", + "docs_url": "/docs/errors/chain/ActivityCutoffFactorMilliOutOfBounds" }, "ActivityCutoffTooLow": { "code": "invalid_argument", - "description": "An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `." + "description": "An admin tried to set the subnet's activity cutoff below the chain-wide minimum. Compare the requested value against the `MinActivityCutoff` storage item and current `activity_cutoff` in `btcli sudo get --netuid `.", + "docs_url": "/docs/errors/chain/ActivityCutoffTooLow" }, "AddStakeBurnRateLimitExceeded": { "code": "rate_limited", - "description": "The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes." + "description": "The add-stake-and-burn operation was submitted again before its per-key rate-limit window elapsed. Wait some blocks and retry; no active raise site exists in current code, so this mainly appears on older runtimes.", + "docs_url": "/docs/errors/chain/AddStakeBurnRateLimitExceeded" }, "AdminActionProhibitedDuringWeightsWindow": { "code": "too_early", - "description": "An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires." + "description": "An owner or admin hyperparameter change was attempted inside the protected freeze window just before the subnet's epoch runs. Check `AdminFreezeWindow` and the blocks remaining until the next epoch (subnet tempo), then retry after the epoch fires.", + "docs_url": "/docs/errors/chain/AdminActionProhibitedDuringWeightsWindow" }, "AllNetworksInImmunity": { "code": "too_early", - "description": "Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity." + "description": "Creating a new subnet required pruning an existing one, but every candidate subnet is still inside its network immunity period so none can be dissolved. Check `NetworkImmunityPeriod` and each subnet's `NetworkRegisteredAt`, and retry once a subnet leaves immunity.", + "docs_url": "/docs/errors/chain/AllNetworksInImmunity" }, "AlphaHighTooLow": { "code": "invalid_argument", - "description": "The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid." + "description": "The `alpha_high` argument to set liquid-alpha values was below the minimum of roughly 0.025 (1638/65535 in u16 units). Raise `alpha_high` in the `sudo_set_alpha_values` call; current values are in the `AlphaValues` storage per netuid.", + "docs_url": "/docs/errors/chain/AlphaHighTooLow" }, "AlphaLowOutOfRange": { "code": "invalid_argument", - "description": "The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid." + "description": "The `alpha_low` argument to set liquid-alpha values was below the ~0.025 minimum (1638/65535) or greater than `alpha_high`. Choose alpha_low within that range and not exceeding alpha_high; current settings are in the `AlphaValues` storage for the netuid.", + "docs_url": "/docs/errors/chain/AlphaLowOutOfRange" }, "AlreadyApproved": { "code": "already_exists", - "description": "The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list." + "description": "The sender has already approved this multisig call, so a repeat approval is redundant. Check the `Multisigs` entry for the call hash: the sender's account already appears in its `approvals` list.", + "docs_url": "/docs/errors/chain/AlreadyApproved" }, "AlreadyDeposited": { "code": "already_exists", - "description": "The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason." + "description": "The account calling safe-mode `enter` or `extend` already has a safe-mode deposit on hold, so another cannot be placed. Check the account's `Deposits` entries and its balance held under the `EnterOrExtend` hold reason.", + "docs_url": "/docs/errors/chain/AlreadyDeposited" }, "AlreadyFinalized": { "code": "already_exists", - "description": "The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`." + "description": "The crowdloan's `finalized` flag is already true, so withdraw, finalize, refund, dissolve, and the update calls are all rejected. Check the `finalized` field of the `Crowdloans` entry for the given `crowdloan_id`.", + "docs_url": "/docs/errors/chain/AlreadyFinalized" }, "AlreadyFinalizing": { "code": "already_exists", - "description": "A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying." + "description": "A `finalize` call was made while another finalization is still in progress, i.e. the dispatched call from a previous finalize has not cleared. Check that the `CurrentCrowdloanId` storage value is empty before retrying.", + "docs_url": "/docs/errors/chain/AlreadyFinalizing" }, "AlreadyNoted": { "code": "already_exists", - "description": "The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again." + "description": "The preimage for this hash has already been noted on-chain, so `note_preimage` has nothing to add. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash before submitting the bytes again.", + "docs_url": "/docs/errors/chain/AlreadyNoted" }, "AlreadyStored": { "code": "already_exists", - "description": "The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again." + "description": "The call data supplied for storage is already stored on-chain for this multisig operation. Check whether the call bytes were previously stored for this call hash before submitting them again.", + "docs_url": "/docs/errors/chain/AlreadyStored" }, "AmountTooLow": { "code": "invalid_argument", - "description": "A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount." + "description": "A stake, unstake, move or swap amount was zero or its TAO equivalent fell below the minimum stake threshold after fees and slippage. Compare the amount against the `DefaultMinStake` storage item and the subnet's alpha price before retrying with a larger amount.", + "docs_url": "/docs/errors/chain/AmountTooLow" }, "AnnouncedColdkeyHashDoesNotMatch": { "code": "invalid_argument", - "description": "The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to." + "description": "The `new_coldkey` passed to `coldkey_swap` hashes to a different value than the hash committed in the earlier `announce_coldkey_swap`. Verify the announced hash in the `ColdkeySwapAnnouncements` storage matches the BlakeTwo256 hash of the coldkey you are swapping to.", + "docs_url": "/docs/errors/chain/AnnouncedColdkeyHashDoesNotMatch" }, "AnnouncementDepositInvariantViolated": { "code": "internal", - "description": "Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input." + "description": "Internal invariant failure in `announce`: recomputing the announcement deposit returned nothing after the pending announcements were updated. Inspect the caller's `Announcements` entry and the announcement deposit constants; this indicates a pallet bug rather than bad input.", + "docs_url": "/docs/errors/chain/AnnouncementDepositInvariantViolated" }, "ArithmeticOverflow": { "code": "internal", - "description": "Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts." + "description": "Converting a TAO amount to alpha during batched order execution overflowed the fixed-point range, typically when the pool price is tiny relative to the batch's total buy TAO. Check the subnet's current alpha price against the batch's aggregate buy amounts.", + "docs_url": "/docs/errors/chain/ArithmeticOverflow" }, "AutoEpochAlreadyImminent": { "code": "already_exists", - "description": "`trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire." + "description": "`trigger_epoch` was called when the next automatic epoch is closer than the `AdminFreezeWindow`, so a manual trigger would have no effect. Check the subnet's tempo and blocks until the next epoch, and simply wait for it to fire.", + "docs_url": "/docs/errors/chain/AutoEpochAlreadyImminent" }, "BadEncKeyLen": { "code": "invalid_argument", - "description": "The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing." + "description": "The `enc_key` passed to `announce_next_key` is not the exact ML-KEM-768 encapsulation key length (1184 bytes). Check the byte length of the `enc_key` argument before announcing.", + "docs_url": "/docs/errors/chain/BadEncKeyLen" }, "BalanceLow": { "code": "insufficient_balance", - "description": "The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price." + "description": "The sender's mapped account cannot cover the transaction's value plus maximum gas fee, detected during validation or when withdrawing the fee. Check the account balance against `value` plus `gas_limit` times the effective gas price.", + "docs_url": "/docs/errors/chain/BalanceLow" }, "BalanceWithdrawalError": { "code": "insufficient_balance", - "description": "The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up." + "description": "The requested TAO could not be withdrawn from the coldkey's free balance, typically due to insufficient funds, the existential deposit, or frozen/reserved balance. Check the coldkey's balance with `btcli wallet balance` and reduce the amount or top up.", + "docs_url": "/docs/errors/chain/BalanceWithdrawalError" }, "BeneficiaryDoesNotOwnHotkey": { "code": "not_authorized", - "description": "When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns." + "description": "When ending a subnet lease, the hotkey passed for the ownership handover is not owned by the lease's beneficiary coldkey. Check the `Owner` storage for that hotkey and pass a hotkey the beneficiary coldkey actually owns.", + "docs_url": "/docs/errors/chain/BeneficiaryDoesNotOwnHotkey" }, "BlockDurationTooLong": { "code": "invalid_argument", - "description": "The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`." + "description": "The requested `end` block is more than `MaximumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MaximumBlockDuration` pallet constant when calling `create` or `update_end`.", + "docs_url": "/docs/errors/chain/BlockDurationTooLong" }, "BlockDurationTooShort": { "code": "invalid_argument", - "description": "The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`." + "description": "The requested `end` block is fewer than `MinimumBlockDuration` blocks after the current block. Compare `end` minus the current block number against the `MinimumBlockDuration` pallet constant when calling `create` or `update_end`.", + "docs_url": "/docs/errors/chain/BlockDurationTooShort" }, "BondsMovingAverageMaxReached": { "code": "limit_exceeded", - "description": "A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root." + "description": "A subnet owner called `sudo_set_bonds_moving_average` with a value above 975000, the cap for owner-set values; root is exempt. Lower the `bonds_moving_average` argument or submit the call as root.", + "docs_url": "/docs/errors/chain/BondsMovingAverageMaxReached" }, "CallDisabled": { "code": "disabled", - "description": "The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version." + "description": "The extrinsic has been switched off in the current runtime and cannot be dispatched. There is no active raise site in current code; if seen, check release notes for whether the call was re-enabled in a newer runtime version.", + "docs_url": "/docs/errors/chain/CallDisabled" }, "CallFiltered": { "code": "not_authorized", - "description": "The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect." + "description": "The runtime's origin call filter (e.g. `BaseCallFilter` or a restricted origin) rejected this call before dispatch. Check whether the specific call is permitted for the origin you used, including any proxy or safe-mode filtering in effect.", + "docs_url": "/docs/errors/chain/CallFiltered" }, "CallUnavailable": { "code": "not_found", - "description": "During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet." + "description": "During `finalize` the crowdloan's stored call could not be fetched from preimage storage, so nothing was dispatched. Check that the preimage referenced by the `call` field of the `Crowdloans` entry still exists in the preimage pallet.", + "docs_url": "/docs/errors/chain/CallUnavailable" }, "CanNotSetRootNetworkWeights": { "code": "invalid_argument", - "description": "`set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism." + "description": "`set_weights` was called with netuid 0, the root network, where normal weight setting is not allowed. Use a non-root `netuid` argument; root weights are handled by a separate mechanism.", + "docs_url": "/docs/errors/chain/CanNotSetRootNetworkWeights" }, "CannotAddSelfAsDelegateDependency": { "code": "invalid_argument", - "description": "A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash." + "description": "A contract called `lock_delegate_dependency` with its own code hash, which is not permitted. Check the code hash argument passed to the delegate dependency API against the contract's own code hash.", + "docs_url": "/docs/errors/chain/CannotAddSelfAsDelegateDependency" }, "CannotAffordLockCost": { "code": "insufficient_balance", - "description": "The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet." + "description": "The coldkey's free balance cannot cover the current dynamic subnet-creation lock cost. Compare `btcli subnets lock-cost` (or `get_network_lock_cost`) against the coldkey balance from `btcli wallet balance` before registering a subnet.", + "docs_url": "/docs/errors/chain/CannotAffordLockCost" }, "CannotBurnOrRecycleOnRootSubnet": { "code": "invalid_argument", - "description": "`recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn." + "description": "`recycle_alpha` or `burn_alpha` was called with netuid 0, and TAO on the root subnet cannot be burned or recycled. Pass a non-root `netuid` argument for the subnet whose alpha you want to recycle or burn.", + "docs_url": "/docs/errors/chain/CannotBurnOrRecycleOnRootSubnet" }, "CannotEndInPast": { "code": "invalid_argument", - "description": "The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater." + "description": "The `end` block passed to `create` or `update_end` is not after the current block. Compare the `end` argument against the current block number; it must be strictly greater.", + "docs_url": "/docs/errors/chain/CannotEndInPast" }, "CannotReleaseYet": { "code": "too_early", - "description": "`release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config." + "description": "`release_deposit` was called too early: the current block must exceed the deposit's block plus `ReleaseDelay`, and safe-mode must be exited. Check the block key of the entry in `Deposits` against the `ReleaseDelay` config.", + "docs_url": "/docs/errors/chain/CannotReleaseYet" }, "CannotUseSystemAccount": { "code": "not_authorized", - "description": "The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`." + "description": "The hotkey supplied for registration, hotkey swap, or subnet-owner-hotkey assignment is a reserved subnet system account. Use a regular user-generated hotkey instead; system accounts are derived per-subnet and rejected by `is_subnet_account_id`.", + "docs_url": "/docs/errors/chain/CannotUseSystemAccount" }, "CapNotRaised": { "code": "too_early", - "description": "`finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing." + "description": "`finalize` was called before the crowdloan's `raised` amount equals its `cap`. Compare the `raised` and `cap` fields of the `Crowdloans` entry; contribute the remainder or lower the cap with `update_cap` before finalizing.", + "docs_url": "/docs/errors/chain/CapNotRaised" }, "CapRaised": { "code": "limit_exceeded", - "description": "A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`." + "description": "A contribution was attempted on a crowdloan whose `raised` amount has already reached its `cap`, so no further contributions are accepted. Compare the `raised` and `cap` fields of the `Crowdloans` entry for the `crowdloan_id`.", + "docs_url": "/docs/errors/chain/CapRaised" }, "CapTooLow": { "code": "invalid_argument", - "description": "On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry." + "description": "On `create` the `cap` is not strictly greater than the initial `deposit`, or on `update_cap` the new cap is below the amount already raised. Compare the cap argument against the `deposit` or the `raised` field of the `Crowdloans` entry.", + "docs_url": "/docs/errors/chain/CapTooLow" }, "ChainIdMismatch": { "code": "invalid_argument", - "description": "The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed." + "description": "The order payload's `chain_id` field differs from this chain's configured EVM chain id, e.g. an order signed for testnet was submitted to mainnet. Compare the order's `chain_id` with the runtime's `pallet_evm_chain_id` value and re-sign if needed.", + "docs_url": "/docs/errors/chain/ChainIdMismatch" }, "ChangePending": { "code": "already_exists", - "description": "A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first." + "description": "A GRANDPA authority-set change has already been signalled and is still pending, so a new change cannot be scheduled. Check the Grandpa `PendingChange` and `State` storage and wait for the pending change to be applied first.", + "docs_url": "/docs/errors/chain/ChangePending" }, "ChildParentInconsistency": { "code": "invalid_argument", - "description": "A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap." + "description": "A `set_children` or parent-delegation call would make the same hotkey appear as both a child and a parent, or referenced a child missing from the proposed mapping. Inspect the `ChildKeys` and `ParentKeys` storage for the hotkeys involved and remove the overlap.", + "docs_url": "/docs/errors/chain/ChildParentInconsistency" }, "CodeInUse": { "code": "invalid_argument", - "description": "`remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal." + "description": "`remove_code` was refused because at least one contract instance still references the code hash. Check the code's reference count and terminate or `set_code` the contracts using it before removal.", + "docs_url": "/docs/errors/chain/CodeInUse" }, "CodeInfoNotFound": { "code": "not_found", - "description": "No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed." + "description": "No `CodeInfoOf` entry exists for the supplied code hash, so its owner and deposit metadata cannot be read. Verify the code hash argument and that the code was uploaded and not since removed.", + "docs_url": "/docs/errors/chain/CodeInfoNotFound" }, "CodeNotFound": { "code": "not_found", - "description": "No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed." + "description": "No uploaded WASM binary exists under the supplied code hash. Verify the `code_hash` argument used in instantiation, `set_code`, or a delegate call, and that the code was uploaded via `upload_code` and not removed.", + "docs_url": "/docs/errors/chain/CodeNotFound" }, "CodeRejected": { "code": "invalid_argument", - "description": "The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason." + "description": "The uploaded WASM failed validation, most often because it imports a host API the node does not support, e.g. newer ink! against an older node. Rerun the node with `-lruntime::contracts=debug` to see the detailed rejection reason.", + "docs_url": "/docs/errors/chain/CodeRejected" }, "CodeTooLarge": { "code": "limit_exceeded", - "description": "The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract." + "description": "The code blob passed to `instantiate_with_code` or `upload_code` exceeds the maximum code length in the pallet's schedule. Compare the WASM binary size against the schedule's code length limit and shrink the contract.", + "docs_url": "/docs/errors/chain/CodeTooLarge" }, "ColdKeyAlreadyAssociated": { "code": "already_exists", - "description": "The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead." + "description": "The destination coldkey of a coldkey swap already has staking hotkeys associated with it, so it cannot receive the swapped identity. Check the `StakingHotkeys` storage for the new coldkey and swap to a fresh, unused coldkey instead.", + "docs_url": "/docs/errors/chain/ColdKeyAlreadyAssociated" }, "ColdkeySwapAlreadyDisputed": { "code": "already_exists", - "description": "`dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed." + "description": "`dispute_coldkey_swap` was called for a coldkey whose pending swap announcement is already under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; no further dispute action is needed.", + "docs_url": "/docs/errors/chain/ColdkeySwapAlreadyDisputed" }, "ColdkeySwapAnnounced": { "code": "already_exists", - "description": "The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement." + "description": "The coldkey has a pending swap announcement, so all but a small allow-list of extrinsics are blocked until the swap completes or is cleared. Check the `ColdkeySwapAnnouncements` storage for the coldkey and either finish the swap with `coldkey_swap` or clear the announcement.", + "docs_url": "/docs/errors/chain/ColdkeySwapAnnounced" }, "ColdkeySwapAnnouncementNotFound": { "code": "not_found", - "description": "`coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first." + "description": "`coldkey_swap`, `dispute_coldkey_swap`, or `clear_coldkey_swap_announcement` was called for a coldkey with no pending announcement. Check the `ColdkeySwapAnnouncements` storage; you must call `announce_coldkey_swap` first.", + "docs_url": "/docs/errors/chain/ColdkeySwapAnnouncementNotFound" }, "ColdkeySwapClearTooEarly": { "code": "too_early", - "description": "The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later." + "description": "The swap announcement cannot be cleared until the reannouncement delay after the announcement's execution block has passed. Compare the current block with the `when` stored in `ColdkeySwapAnnouncements` plus `ColdkeySwapReannouncementDelay` and retry later.", + "docs_url": "/docs/errors/chain/ColdkeySwapClearTooEarly" }, "ColdkeySwapDisputed": { "code": "not_authorized", - "description": "All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact." + "description": "All extrinsics from this coldkey are blocked because its pending coldkey swap is under dispute. Check the `ColdkeySwapDisputes` storage for the coldkey; the dispute must be resolved by root before the account can transact.", + "docs_url": "/docs/errors/chain/ColdkeySwapDisputed" }, "ColdkeySwapReannouncedTooEarly": { "code": "too_early", - "description": "`announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later." + "description": "`announce_coldkey_swap` was called again before the reannouncement delay after the previous announcement's execution block elapsed. Compare the current block with the stored announcement time plus `ColdkeySwapReannouncementDelay` and retry later.", + "docs_url": "/docs/errors/chain/ColdkeySwapReannouncedTooEarly" }, "ColdkeySwapTooEarly": { "code": "too_early", - "description": "`coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then." + "description": "`coldkey_swap` was executed before the announcement delay had elapsed since `announce_coldkey_swap`. Check the execution block stored in `ColdkeySwapAnnouncements` (announcement time plus `ColdkeySwapAnnouncementDelay`) and wait until then.", + "docs_url": "/docs/errors/chain/ColdkeySwapTooEarly" }, "CommitRevealDisabled": { "code": "disabled", - "description": "A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled." + "description": "A weight commit or reveal was submitted on a subnet where commit-reveal is turned off. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid (`btcli sudo get`); use plain `set_weights` instead when it is disabled.", + "docs_url": "/docs/errors/chain/CommitRevealDisabled" }, "CommitRevealEnabled": { "code": "disabled", - "description": "Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`." + "description": "Plain `set_weights` was called on a subnet where commit-reveal is enabled, which requires the commit/reveal flow instead. Check the `commit_reveal_weights_enabled` hyperparameter for the netuid and switch to `commit_weights`/`reveal_weights`.", + "docs_url": "/docs/errors/chain/CommitRevealEnabled" }, "CommittingWeightsTooFast": { "code": "rate_limited", - "description": "The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait." + "description": "The neuron committed weights again before the per-UID rate limit elapsed since its last commit on that subnet. Compare blocks since the last commit against the `weights_rate_limit` hyperparameter (`btcli sudo get --netuid `) and wait.", + "docs_url": "/docs/errors/chain/CommittingWeightsTooFast" }, "ContractNotFound": { "code": "not_found", - "description": "No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated." + "description": "No contract instance exists at the destination address; the account has no `ContractInfoOf` entry. Verify the `dest` address and that the contract was instantiated and has not been terminated.", + "docs_url": "/docs/errors/chain/ContractNotFound" }, "ContractReverted": { "code": "internal", - "description": "The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value." + "description": "The contract ran to completion but returned with the REVERT flag set, rolling back its state changes; only extrinsics surface this as an error. Dry-run the call via RPC and decode the returned output data for the contract's error value.", + "docs_url": "/docs/errors/chain/ContractReverted" }, "ContractTrapped": { "code": "internal", - "description": "The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations." + "description": "The contract aborted with a WASM trap, e.g. a panic, unreachable instruction, or memory violation, instead of returning normally. Dry-run the call with debug messages enabled and check the input data against the contract's expectations.", + "docs_url": "/docs/errors/chain/ContractTrapped" }, "ContributionPeriodEnded": { "code": "expired", - "description": "A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized." + "description": "A contribution was made at or after the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry with the current block number; the creator can extend it with `update_end` while the crowdloan is not finalized.", + "docs_url": "/docs/errors/chain/ContributionPeriodEnded" }, "ContributionPeriodNotEnded": { "code": "too_early", - "description": "The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number." + "description": "The operation requires the crowdloan's contribution period to be over, but the current block is still before the crowdloan's `end` block. Compare the `end` field of the `Crowdloans` entry for the `crowdloan_id` with the current block number.", + "docs_url": "/docs/errors/chain/ContributionPeriodNotEnded" }, "ContributionTooLow": { "code": "invalid_argument", - "description": "The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount." + "description": "The `amount` passed to `contribute` is below the crowdloan's configured minimum contribution. Check the `min_contribution` field of the `Crowdloans` entry for the `crowdloan_id` and contribute at least that amount.", + "docs_url": "/docs/errors/chain/ContributionTooLow" }, "CreateOriginNotAllowed": { "code": "not_authorized", - "description": "A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list." + "description": "A CREATE, or a CALL that performs a nested CREATE, was attempted from an EVM address not permitted to deploy contracts. Check whether the deploying address is in the chain's allowed-deployers list.", + "docs_url": "/docs/errors/chain/CreateOriginNotAllowed" }, "CurrencyError": { "code": "internal", - "description": "A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason." + "description": "A balance hold, release, or burn inside pallet-safe-mode failed while managing an enter/extend deposit. Check the account's free balance and existing holds under the safe-mode `EnterOrExtend` hold reason.", + "docs_url": "/docs/errors/chain/CurrencyError" }, "DeadAccount": { "code": "not_found", - "description": "The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs." + "description": "The beneficiary account does not exist and this operation is not allowed to create it. Check `System.Account` for the destination: it must already hold at least the existential deposit before the operation runs.", + "docs_url": "/docs/errors/chain/DeadAccount" }, "DecodingFailed": { "code": "invalid_argument", - "description": "Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API." + "description": "Input bytes passed to a contract API host function could not be SCALE-decoded into the expected type. Check the encoding of the call's input data or the argument bytes the contract passes to the runtime API.", + "docs_url": "/docs/errors/chain/DecodingFailed" }, "DelegateDependencyAlreadyExists": { "code": "already_exists", - "description": "The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it." + "description": "The contract called `lock_delegate_dependency` for a code hash it has already locked. Check the contract's recorded delegate dependencies before adding, and unlock the old entry first if replacing it.", + "docs_url": "/docs/errors/chain/DelegateDependencyAlreadyExists" }, "DelegateDependencyNotFound": { "code": "not_found", - "description": "`unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info." + "description": "`unlock_delegate_dependency` was called for a code hash that is not among the contract's locked delegate dependencies. Check the code hash argument against the dependencies recorded in the contract's info.", + "docs_url": "/docs/errors/chain/DelegateDependencyNotFound" }, "DelegateTakeTooHigh": { "code": "invalid_argument", - "description": "The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it." + "description": "The `take` argument exceeds the maximum delegate take allowed by the chain (18% by default). Compare the requested value against the `MaxDelegateTake` storage item and lower it.", + "docs_url": "/docs/errors/chain/DelegateTakeTooHigh" }, "DelegateTakeTooLow": { "code": "invalid_argument", - "description": "The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item." + "description": "The `take` argument was below the `MinDelegateTake` minimum, or `increase_take`/`decrease_take` was not strictly increasing/decreasing relative to the current take. Check the hotkey's current take in the `Delegates` storage and the `MinDelegateTake` storage item.", + "docs_url": "/docs/errors/chain/DelegateTakeTooLow" }, "DelegateTxRateLimitExceeded": { "code": "rate_limited", - "description": "The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later." + "description": "The delegate changed its take again before the per-hotkey take-change rate limit elapsed. Compare blocks since the hotkey's last take transaction against the `TxDelegateTakeRateLimit` storage item and retry later.", + "docs_url": "/docs/errors/chain/DelegateTxRateLimitExceeded" }, "DeltaZero": { "code": "invalid_argument", - "description": "The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount." + "description": "The issuance adjustment was called with a delta of zero, which is meaningless. Check the `delta` argument to `force_adjust_total_issuance` and pass a strictly positive amount.", + "docs_url": "/docs/errors/chain/DeltaZero" }, "DepositCannotBeWithdrawn": { "code": "invalid_argument", - "description": "The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry." + "description": "The creator called `withdraw` but holds nothing above the initial deposit, which stays locked until the crowdloan is dissolved. Compare the creator's `Contributions` entry with the `deposit` field of the `Crowdloans` entry.", + "docs_url": "/docs/errors/chain/DepositCannotBeWithdrawn" }, "DepositTooLow": { "code": "invalid_argument", - "description": "The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit." + "description": "The `deposit` argument to `create` is below the pallet's required minimum. Check the `MinimumDeposit` pallet constant and create the crowdloan with at least that initial deposit.", + "docs_url": "/docs/errors/chain/DepositTooLow" }, "Deprecated": { "code": "disabled", - "description": "The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`)." + "description": "The extrinsic has been removed and always fails, e.g. `schedule_swap_coldkey`, the swap pallet's user-liquidity calls, or `sudo_set_total_issuance`. Migrate to the replacement call noted in the deprecation (for coldkey swaps, `announce_coldkey_swap` plus `coldkey_swap`).", + "docs_url": "/docs/errors/chain/Deprecated" }, "DisabledTemporarily": { "code": "disabled", - "description": "The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled." + "description": "The operation has been temporarily switched off in the runtime, usually as a hotfix measure. There is no active raise site in current code; if encountered, check the runtime version and release notes for when the feature is re-enabled.", + "docs_url": "/docs/errors/chain/DisabledTemporarily" }, "DrandConnectionFailure": { "code": "internal", - "description": "Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints." + "description": "Declared for failures reaching the drand HTTP API, but pulse fetching happens in the offchain worker, which logs errors instead of raising this. Check the node's offchain worker logs and outbound connectivity to the drand endpoints.", + "docs_url": "/docs/errors/chain/DrandConnectionFailure" }, "Duplicate": { "code": "already_exists", - "description": "This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple." + "description": "This delegate is already registered as a proxy for the delegator with the same proxy type and delay. Check the delegator's `Proxies` entry before calling `add_proxy` with the same (delegate, proxy type, delay) tuple.", + "docs_url": "/docs/errors/chain/Duplicate" }, "DuplicateChild": { "code": "invalid_argument", - "description": "The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid." + "description": "The children list passed to `set_children` contains the same child hotkey more than once. Deduplicate the `children` argument; current relations are visible in the `ChildKeys` storage for the parent hotkey and netuid.", + "docs_url": "/docs/errors/chain/DuplicateChild" }, "DuplicateContract": { "code": "already_exists", - "description": "Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address." + "description": "Instantiation would create a contract at an address already occupied by an existing contract. Check the derived contract address and vary the `salt` argument to obtain a fresh address.", + "docs_url": "/docs/errors/chain/DuplicateContract" }, "DuplicateOffenceReport": { "code": "already_exists", - "description": "The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again." + "description": "The equivocation proof is valid but this offence has already been reported and recorded. Check whether an equivocation report for the same offender, session, and round was previously submitted before reporting again.", + "docs_url": "/docs/errors/chain/DuplicateOffenceReport" }, "DuplicateOrderInBatch": { "code": "invalid_argument", - "description": "Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`." + "description": "Two entries in one `execute_batched_orders` call hash to the same order id, meaning the identical signed payload was included twice, which hard-fails the batch. Deduplicate by the blake2-256 hash of each SCALE-encoded `VersionedOrder`.", + "docs_url": "/docs/errors/chain/DuplicateOrderInBatch" }, "DuplicateUids": { "code": "invalid_argument", - "description": "The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector." + "description": "The `uids` vector passed to `set_weights` (or a reveal) contains the same UID more than once. Deduplicate the uids/values pairs before submitting; each target neuron may appear only once per weight vector.", + "docs_url": "/docs/errors/chain/DuplicateUids" }, "DynamicTempoBlockedByCommitReveal": { "code": "disabled", - "description": "`trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs." + "description": "`trigger_epoch` is refused while commit-reveal is enabled on the subnet, because an out-of-band epoch would desync the CRv3 reveal window from the Drand schedule and drop committed weights. Check the `commit_reveal_weights_enabled` hyperparameter; disable it before manually triggering epochs.", + "docs_url": "/docs/errors/chain/DynamicTempoBlockedByCommitReveal" }, "Entered": { "code": "already_exists", - "description": "Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages." + "description": "Safe-mode is currently active, so `enter` or `force_enter` cannot activate it again and `release_deposit` is blocked until it exits. Check `EnteredUntil` for the block at which safe-mode disengages.", + "docs_url": "/docs/errors/chain/Entered" }, "EpochTriggerAlreadyPending": { "code": "already_exists", - "description": "`trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again." + "description": "`trigger_epoch` was called while a previously triggered epoch is still queued for this subnet. Check the `PendingEpochAt` storage for the netuid and wait for the pending epoch to fire before triggering again.", + "docs_url": "/docs/errors/chain/EpochTriggerAlreadyPending" }, "EvmKeyAssociateRateLimitExceeded": { "code": "rate_limited", - "description": "`associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later." + "description": "`associate_evm_key` was called again before the per-UID rate limit since the last association elapsed. Compare blocks since the association recorded in the `AssociatedEvmAddress` storage against the `EvmKeyAssociateRateLimit` runtime constant and retry later.", + "docs_url": "/docs/errors/chain/EvmKeyAssociateRateLimitExceeded" }, "EvmKeyAssociationLimitExceeded": { "code": "limit_exceeded", - "description": "The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address." + "description": "The EVM address is already associated with the maximum number of UIDs allowed on this subnet. Inspect the `AssociatedUidsByEvmAddress` storage for the (netuid, evm_key) pair and free a slot or use a different EVM address.", + "docs_url": "/docs/errors/chain/EvmKeyAssociationLimitExceeded" }, "ExistentialDeposit": { "code": "insufficient_balance", - "description": "The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant." + "description": "The amount is too small to create the destination account: its resulting balance would sit below the existential deposit. Compare the transfer value plus the destination's current free balance against the `ExistentialDeposit` constant.", + "docs_url": "/docs/errors/chain/ExistentialDeposit" }, "ExistingVestingSchedule": { "code": "already_exists", - "description": "A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule." + "description": "A vesting schedule already exists for the target account and this call cannot add another. Check the account's `Vesting` storage entry before attempting to set a new vested transfer or schedule.", + "docs_url": "/docs/errors/chain/ExistingVestingSchedule" }, "Exited": { "code": "already_exists", - "description": "Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting." + "description": "Safe-mode is not currently active, so `extend`, `force_extend`, or `force_exit` have nothing to act on. Check that `EnteredUntil` contains a value before extending or exiting.", + "docs_url": "/docs/errors/chain/Exited" }, "ExpectedBeneficiaryOrigin": { "code": "not_authorized", - "description": "A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey." + "description": "A lease operation such as terminating a subnet lease was signed by an account other than the lease's beneficiary coldkey. Check the beneficiary recorded in the `SubnetLeases` storage for the lease id and sign with that coldkey.", + "docs_url": "/docs/errors/chain/ExpectedBeneficiaryOrigin" }, "Expendability": { "code": "insufficient_balance", - "description": "The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable." + "description": "The transfer or payment would drop the sender below the existential deposit and kill the account while keep-alive semantics are required. Compare the sender's free balance minus the amount and fees against `ExistentialDeposit`, or use `transfer_allow_death` if reaping is acceptable.", + "docs_url": "/docs/errors/chain/Expendability" }, "ExpiredWeightCommit": { "code": "expired", - "description": "The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time." + "description": "The hash supplied to `reveal_weights` matches a commit whose reveal window has already passed, so it can no longer be revealed. Check the `commit_reveal_period` hyperparameter and reveal within the allowed epochs after committing; re-commit and reveal on time.", + "docs_url": "/docs/errors/chain/ExpiredWeightCommit" }, "FailedToExtractRuntimeVersion": { "code": "invalid_argument", - "description": "The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly." + "description": "The new runtime code passed to `set_code` did not yield a readable version: calling `Core_version` or decoding `RuntimeVersion` failed. Check that the submitted blob is a valid, complete runtime wasm and not truncated or compressed incorrectly.", + "docs_url": "/docs/errors/chain/FailedToExtractRuntimeVersion" }, "FailedToSchedule": { "code": "internal", - "description": "The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated." + "description": "The scheduler could not place the call into the agenda, typically because the target block's agenda is full or the schedule parameters are unusable. Check `Agenda` at the target block against `MaxScheduledPerBlock` and pick a different block if it is saturated.", + "docs_url": "/docs/errors/chain/FailedToSchedule" }, "FaucetDisabled": { "code": "disabled", - "description": "The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead." + "description": "The `faucet` extrinsic was called on a runtime built without the pow-faucet feature, i.e. any real network. The faucet only works on local test chains compiled with that feature; use a funded wallet or testnet TAO instead.", + "docs_url": "/docs/errors/chain/FaucetDisabled" }, "FeeOverflow": { "code": "internal", - "description": "Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction." + "description": "Fee arithmetic overflowed, either multiplying the fee per gas by `gas_limit` or converting the EVM fee into Substrate balance decimals. Check for absurdly large `gas_limit` or fee-per-gas values in the transaction.", + "docs_url": "/docs/errors/chain/FeeOverflow" }, "FeeRateTooHigh": { "code": "invalid_argument", - "description": "`set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting." + "description": "`set_fee_rate` was called with a rate above the swap pallet's `MaxFeeRate` config constant. Compare the `rate` argument (u16-scaled fraction) against `MaxFeeRate` before submitting.", + "docs_url": "/docs/errors/chain/FeeRateTooHigh" }, "FirstEmissionBlockNumberAlreadySet": { "code": "already_exists", - "description": "`start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed." + "description": "`start_call` was issued for a subnet whose emissions have already been started. Check the `FirstEmissionBlockNumber` storage for the netuid; a non-empty value means the subnet is already emitting and no action is needed.", + "docs_url": "/docs/errors/chain/FirstEmissionBlockNumberAlreadySet" }, "GasLimitTooHigh": { "code": "invalid_argument", - "description": "The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it." + "description": "The transaction's `gas_limit` exceeds the block gas limit configured for the EVM. Compare the `gas_limit` argument against the chain's block gas limit and lower it.", + "docs_url": "/docs/errors/chain/GasLimitTooHigh" }, "GasLimitTooLow": { "code": "invalid_argument", - "description": "The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result." + "description": "The transaction's `gas_limit` is below the intrinsic gas required, or too small to cover the weight and proof-size base cost. Raise the `gas_limit` argument, comparing against an `eth_estimateGas` result.", + "docs_url": "/docs/errors/chain/GasLimitTooLow" }, "GasPriceTooLow": { "code": "invalid_argument", - "description": "The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee." + "description": "The offered fee cannot satisfy the current base fee: `max_fee_per_gas` is below the block base fee, the priority fee exceeds the max fee, or the fee inputs are inconsistent. Check `max_fee_per_gas` and `max_priority_fee_per_gas` against the chain's base fee.", + "docs_url": "/docs/errors/chain/GasPriceTooLow" }, "HotKeyAccountNotExists": { "code": "not_registered", - "description": "The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first." + "description": "The hotkey has no on-chain account, meaning it was never created through registration, so staking or delegation operations cannot reference it. Check the `Owner` storage for the hotkey or `btcli wallet overview`; register the hotkey on a subnet first.", + "docs_url": "/docs/errors/chain/HotKeyAccountNotExists" }, "HotKeyAlreadyDelegate": { "code": "already_exists", - "description": "`become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed." + "description": "`become_delegate` was called for a hotkey that is already a delegate. Check the `Delegates` storage for the hotkey; if it has a take entry it is already delegating and no action is needed.", + "docs_url": "/docs/errors/chain/HotKeyAlreadyDelegate" }, "HotKeyAlreadyRegisteredInSubNet": { "code": "already_exists", - "description": "A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid." + "description": "A registration or hotkey swap targeted a hotkey that already holds a UID on the subnet (or, for a swap without a netuid, on any subnet). Check the `Uids` storage for the (netuid, hotkey) pair or `btcli wallet overview`; use a different hotkey or netuid.", + "docs_url": "/docs/errors/chain/HotKeyAlreadyRegisteredInSubNet" }, "HotKeyNotRegisteredInNetwork": { "code": "not_registered", - "description": "The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first." + "description": "The hotkey is not registered on the relevant subnet, raised by `serve_axon`/`serve_prometheus` for the serving netuid or by identity calls requiring registration on any subnet. Verify registration with `btcli subnets show --netuid ` and register via `btcli subnets register` first.", + "docs_url": "/docs/errors/chain/HotKeyNotRegisteredInNetwork" }, "HotKeyNotRegisteredInSubNet": { "code": "not_registered", - "description": "The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed." + "description": "The hotkey holds no UID on the given netuid, so weight setting, commits, or UID lookups fail there. Check the `Uids` storage for the (netuid, hotkey) pair or `btcli subnets show --netuid `; confirm the netuid argument and register the hotkey if needed.", + "docs_url": "/docs/errors/chain/HotKeyNotRegisteredInSubNet" }, "HotKeySetTxRateLimitExceeded": { "code": "rate_limited", - "description": "The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks." + "description": "The coldkey attempted a hotkey set/swap before `TxRateLimit` blocks had passed since its last such transaction. Check the coldkey's last transaction block against the `TxRateLimit` storage value and wait the remaining blocks.", + "docs_url": "/docs/errors/chain/HotKeySetTxRateLimitExceeded" }, "HotKeySwapOnSubnetIntervalNotPassed": { "code": "rate_limited", - "description": "A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval." + "description": "A hotkey swap on a subnet was attempted before `HotkeySwapOnSubnetInterval` blocks passed since the coldkey's last swap on that netuid. Compare `LastHotkeySwapOnNetuid` for the coldkey with the current block and retry after the interval.", + "docs_url": "/docs/errors/chain/HotKeySwapOnSubnetIntervalNotPassed" }, "IncorrectCommitRevealVersion": { "code": "invalid_argument", - "description": "The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version." + "description": "The `commit_reveal_version` argument does not match the chain's current commit-reveal weights version. Query the `CommitRevealWeightsVersion` storage item and upgrade or configure the client to commit with that version.", + "docs_url": "/docs/errors/chain/IncorrectCommitRevealVersion" }, "IncorrectPartialFillAmount": { "code": "invalid_argument", - "description": "The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`." + "description": "The `partial_fill` amount is zero or exceeds the order's remaining unfilled amount, or a full execution was submitted against an order already partially filled. Compare `partial_fill` with `order.amount` minus the filled amount recorded in `Orders`.", + "docs_url": "/docs/errors/chain/IncorrectPartialFillAmount" }, "IncorrectWeightVersionKey": { "code": "invalid_argument", - "description": "The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key." + "description": "The `version_key` supplied with set_weights is older than the subnet's required weights version. Compare it against the `WeightsVersionKey` hyperparameter (`btcli subnets hyperparameters`) and update the validator software or the key.", + "docs_url": "/docs/errors/chain/IncorrectWeightVersionKey" }, "Indeterministic": { "code": "invalid_argument", - "description": "Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically." + "description": "Code flagged as non-deterministic (e.g. using floating point) was used where determinism is enforced, such as on-chain instantiation or calls. Check the determinism mode the code was uploaded with and rebuild the contract deterministically.", + "docs_url": "/docs/errors/chain/Indeterministic" }, "InputForwarded": { "code": "invalid_argument", - "description": "The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards." + "description": "The contract forwarded its input to a callee via `seal_call` with the FORWARD_INPUT flag and then tried to read or forward it again. Check the call flags used; use CLONE_INPUT when the input is still needed afterwards.", + "docs_url": "/docs/errors/chain/InputForwarded" }, "InputLengthsUnequal": { "code": "invalid_argument", - "description": "A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length." + "description": "A batch weights call passed vectors of different lengths, e.g. netuids vs commit hashes, or uids vs values, salts and version_keys in batch reveal. Check that every parallel vector argument in the batch extrinsic has the same length.", + "docs_url": "/docs/errors/chain/InputLengthsUnequal" }, "InsufficientBalance": { "code": "insufficient_balance", - "description": "The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved." + "description": "The caller's spendable balance is below what the operation needs, whether a plain transfer, a stake operation, a crowdloan deposit or contribution, or a swap. Compare the account's free balance in `System.Account` (net of holds, freezes, and fees) against the amount being moved.", + "docs_url": "/docs/errors/chain/InsufficientBalance" }, "InsufficientInputAmount": { "code": "invalid_argument", - "description": "Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output." + "description": "Declared for swap inputs too small to execute, but no current code path raises it since the user-liquidity code was removed. If seen on an older runtime, check that the swap input amount is nonzero and large enough to produce output.", + "docs_url": "/docs/errors/chain/InsufficientInputAmount" }, "InsufficientLiquidity": { "code": "insufficient_liquidity", - "description": "The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount." + "description": "The pool cannot absorb the operation: the swap simulation failed, reserves are smaller than the payout, or the amount exceeds the pool's supported input. Check the subnet pool reserves `SubnetTAO`, `SubnetAlphaIn` and `SubnetAlphaOut` against the amount.", + "docs_url": "/docs/errors/chain/InsufficientLiquidity" }, "InsufficientStakeForLock": { "code": "insufficient_balance", - "description": "The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first." + "description": "The requested lock amount exceeds the coldkey's total alpha stake on that subnet (existing locked mass included). Compare the amount against the coldkey's stake on the netuid, e.g. via `btcli stake list`, and lock less or add stake first.", + "docs_url": "/docs/errors/chain/InsufficientStakeForLock" }, "InvalidCallFlags": { "code": "invalid_argument", - "description": "The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values." + "description": "The flags bitmask given to `seal_call` or `seal_delegate_call` contains an unknown or disallowed combination; delegate calls accept only a restricted flag set. Check the flags argument against the supported `CallFlags` bit values.", + "docs_url": "/docs/errors/chain/InvalidCallFlags" }, "InvalidChainId": { "code": "invalid_argument", - "description": "The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction." + "description": "The EIP-155 chain id encoded in the signed transaction does not match this chain's configured chain id. Compare the transaction's chain id with the value returned by `eth_chainId` and re-sign the transaction.", + "docs_url": "/docs/errors/chain/InvalidChainId" }, "InvalidChild": { "code": "invalid_argument", - "description": "The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved." + "description": "The children or parents list includes the pivot hotkey itself (a self-loop), including during a hotkey swap when the new hotkey is already a child or parent of the old one. Check the `children` argument and `ChildKeys`/`ParentKeys` for the hotkeys involved.", + "docs_url": "/docs/errors/chain/InvalidChild" }, "InvalidChildkeyTake": { "code": "invalid_argument", - "description": "The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds." + "description": "The childkey take is outside the allowed range for the subnet: below the effective minimum or above `MaxChildkeyTake`. Query `MinChildkeyTake` and `MaxChildkeyTake` and pick a `take` value within those bounds.", + "docs_url": "/docs/errors/chain/InvalidChildkeyTake" }, "InvalidCrowdloanId": { "code": "not_found", - "description": "No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued." + "description": "No crowdloan exists in the `Crowdloans` storage map for the given `crowdloan_id`; it was never created or has been dissolved. Check `Crowdloans` for the id and `NextCrowdloanId` for the range of ids ever issued.", + "docs_url": "/docs/errors/chain/InvalidCrowdloanId" }, "InvalidDerivedAccount": { "code": "invalid_argument", - "description": "Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation." + "description": "Deriving the sub-account for `as_derivative` failed to decode into a valid account id from the (caller, index) entropy. Check the `index` argument and the caller account used for derivation.", + "docs_url": "/docs/errors/chain/InvalidDerivedAccount" }, "InvalidDerivedAccountId": { "code": "invalid_argument", - "description": "Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one)." + "description": "Deriving the pure proxy account id from the provided entropy failed to decode into a valid account. Check the spawner, `proxy_type`, and `index` arguments used with `create_pure` (or the equivalent lookup when destroying one).", + "docs_url": "/docs/errors/chain/InvalidDerivedAccountId" }, "InvalidDifficulty": { "code": "invalid_argument", - "description": "The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block." + "description": "The submitted proof-of-work hash does not meet the required difficulty (the faucet uses a fixed 1,000,000; PoW registration uses the subnet's difficulty). Check the `Difficulty` storage for the netuid and regenerate work against the current block.", + "docs_url": "/docs/errors/chain/InvalidDifficulty" }, "InvalidEquivocationProof": { "code": "invalid_argument", - "description": "The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set." + "description": "The submitted GRANDPA equivocation proof does not demonstrate a real double-vote: the two votes may be identical, from different rounds or set ids, or badly signed. Verify the proof contains two distinct votes by the same authority in the same round and authority set.", + "docs_url": "/docs/errors/chain/InvalidEquivocationProof" }, "InvalidFinalizationConfig": { "code": "invalid_argument", - "description": "Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry." + "description": "Exactly one of `call` or `target_address` must be set, but both or neither were provided to `create`, or the stored crowdloan holds an inconsistent pair at `finalize` time. Check those two fields on the `create` arguments or the `Crowdloans` entry.", + "docs_url": "/docs/errors/chain/InvalidFinalizationConfig" }, "InvalidIdentity": { "code": "invalid_argument", - "description": "The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity." + "description": "The submitted coldkey or subnet identity failed validation, typically a field exceeding its allowed byte length or malformed data. Check each identity field's length against the limits enforced by the chain before calling set_identity or set_subnet_identity.", + "docs_url": "/docs/errors/chain/InvalidIdentity" }, "InvalidIpAddress": { "code": "invalid_argument", - "description": "The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed." + "description": "The `ip` argument to serve_axon or serve_prometheus is not a valid address for the declared `ip_type` (prometheus additionally rejects the zero address). Verify the IP encodes correctly as IPv4 or IPv6 and matches the `ip_type` passed.", + "docs_url": "/docs/errors/chain/InvalidIpAddress" }, "InvalidIpType": { "code": "invalid_argument", - "description": "The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted." + "description": "The `ip_type` argument to serve_axon or serve_prometheus is not 4 or 6. Check the value being sent by the miner or client; only IPv4 (4) and IPv6 (6) are accepted.", + "docs_url": "/docs/errors/chain/InvalidIpType" }, "InvalidKeyOwnershipProof": { "code": "invalid_argument", - "description": "The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report." + "description": "The key ownership proof does not establish that the offending GRANDPA key belonged to the claimed validator at that session. Regenerate the proof via the `generate_key_ownership_proof` runtime API for the exact set id and authority id in the report.", + "docs_url": "/docs/errors/chain/InvalidKeyOwnershipProof" }, "InvalidLeaseBeneficiary": { "code": "invalid_argument", - "description": "The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey." + "description": "The account registering a leased network is not the creator of the crowdloan currently being finalized. Check the crowdloan's `creator` field in the crowdloan pallet storage and submit the call from that coldkey.", + "docs_url": "/docs/errors/chain/InvalidLeaseBeneficiary" }, "InvalidLiquidityValue": { "code": "invalid_argument", - "description": "Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`." + "description": "Legacy error from the removed V3 user-liquidity code, raised when an added or removed liquidity amount was below the pallet's `MinimumLiquidity`. Not raised on current runtimes; on older ones compare the `liquidity` argument to `MinimumLiquidity`.", + "docs_url": "/docs/errors/chain/InvalidLiquidityValue" }, "InvalidNonce": { "code": "invalid_argument", - "description": "The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`." + "description": "The transaction nonce does not match the sender's current account nonce, being either too low (already used) or too high. Compare the transaction's `nonce` with the sender's on-chain nonce from `eth_getTransactionCount`.", + "docs_url": "/docs/errors/chain/InvalidNonce" }, "InvalidNumRootClaim": { "code": "invalid_argument", - "description": "The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number." + "description": "The value passed to sudo_set_num_root_claims exceeds the compile-time maximum number of root claims. Check the `new_value` argument against the chain's `MAX_NUM_ROOT_CLAIMS` constant and pass a smaller number.", + "docs_url": "/docs/errors/chain/InvalidNumRootClaim" }, "InvalidOrigin": { "code": "not_authorized", - "description": "The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`." + "description": "The caller is not the crowdloan's creator, which is required for `finalize`, `refund`, `dissolve`, and the update calls. Compare the signing account with the `creator` field of the `Crowdloans` entry for the `crowdloan_id`.", + "docs_url": "/docs/errors/chain/InvalidOrigin" }, "InvalidPort": { "code": "invalid_argument", - "description": "The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port." + "description": "The `port` argument to serve_axon or serve_prometheus is 0, which is rejected. Check the miner or client axon configuration and serve on a non-zero port.", + "docs_url": "/docs/errors/chain/InvalidPort" }, "InvalidRecoveredPublicKey": { "code": "invalid_argument", - "description": "The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format)." + "description": "The EVM key association signature recovered to a public key whose keccak hash does not equal the supplied `evm_key`. Verify the signature was produced by the claimed EVM key over the hotkey plus block hash message (EIP-191 format).", + "docs_url": "/docs/errors/chain/InvalidRecoveredPublicKey" }, "InvalidRevealCommitHashNotMatch": { "code": "invalid_argument", - "description": "The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid." + "description": "The revealed uids, values, salt and version_key hash to a value that matches none of the hotkey's pending non-expired commits. Check that the reveal parameters and salt exactly match what was committed, and inspect `WeightCommits` for the hotkey and netuid.", + "docs_url": "/docs/errors/chain/InvalidRevealCommitHashNotMatch" }, "InvalidRevealRound": { "code": "expired", - "description": "A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number." + "description": "A timelocked weights commit specified a `reveal_round` older than the latest stored DRAND round, so it could be decrypted immediately. Query the drand pallet's `LastStoredRound` and commit with a future round number.", + "docs_url": "/docs/errors/chain/InvalidRevealRound" }, "InvalidRootClaimThreshold": { "code": "invalid_argument", - "description": "The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid." + "description": "The value passed to set the root claim threshold exceeds the chain's maximum allowed threshold. Check the `new_value` argument against the `MAX_ROOT_CLAIM_THRESHOLD` constant and the current `RootClaimableThreshold` for the netuid.", + "docs_url": "/docs/errors/chain/InvalidRootClaimThreshold" }, "InvalidRoundNumber": { "code": "invalid_argument", - "description": "A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`." + "description": "A submitted drand pulse has an unacceptable round: the first pulse ever stored must have a round greater than zero, and each later pulse must be exactly `LastStoredRound` plus one. Compare the pulse round against `LastStoredRound`.", + "docs_url": "/docs/errors/chain/InvalidRoundNumber" }, "InvalidSchedule": { "code": "invalid_argument", - "description": "The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments." + "description": "The pallet's schedule is misconfigured, e.g. a zero weight or zero `ref_time_by_fuel` for a basic operation, making gas conversion impossible. This is a runtime configuration issue; inspect the `Schedule` constant rather than call arguments.", + "docs_url": "/docs/errors/chain/InvalidSchedule" }, "InvalidSeal": { "code": "invalid_argument", - "description": "The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit." + "description": "The seal hash recomputed from the supplied `block_number`, `nonce` and key does not equal the submitted `work`. Verify the PoW solver built the seal for the same key and block it submits, and that the work bytes were not corrupted in transit.", + "docs_url": "/docs/errors/chain/InvalidSeal" }, "InvalidSignature": { "code": "invalid_argument", - "description": "Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed." + "description": "Signature verification failed: the sender of an Ethereum or EVM transaction could not be recovered from its signature, or a limit order's Sr25519 signature does not match the order payload and signer. Check the signing key, chain id, and the exact payload bytes that were signed.", + "docs_url": "/docs/errors/chain/InvalidSignature" }, "InvalidSpecName": { "code": "invalid_argument", - "description": "The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one." + "description": "The new runtime's `spec_name` does not match the current runtime, so `set_code` refuses the upgrade. Check the `RuntimeVersion` embedded in the new wasm and ensure the spec name is identical to the chain's current one.", + "docs_url": "/docs/errors/chain/InvalidSpecName" }, "InvalidSubnetNumber": { "code": "invalid_argument", - "description": "A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit." + "description": "A root-claim call passed an empty subnet set or more subnets than the per-call maximum (claim_root, or KeepSubnets in set_root_claim_type). Check the `subnets` argument is non-empty and within the `MAX_SUBNET_CLAIMS` limit.", + "docs_url": "/docs/errors/chain/InvalidSubnetNumber" }, "InvalidTickRange": { "code": "invalid_argument", - "description": "Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones." + "description": "Legacy error from the removed V3 user-liquidity code, raised when `tick_low` was not below `tick_high` or a tick failed to convert to a sqrt price. Not raised on current runtimes; check the tick range arguments on older ones.", + "docs_url": "/docs/errors/chain/InvalidTickRange" }, "InvalidValue": { "code": "invalid_argument", - "description": "A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`)." + "description": "A generic out-of-range parameter on an admin or sudo call, e.g. mechanism counts, emission splits summing away from 65535, max UIDs or take bounds. Check the specific argument against the min/max storage items the extrinsic validates (e.g. `MinAllowedUids`, `MaxMechanismCount`).", + "docs_url": "/docs/errors/chain/InvalidValue" }, "InvalidVotingPowerEmaAlpha": { "code": "invalid_argument", - "description": "The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid." + "description": "The alpha passed to set the voting power EMA exceeds 10^18, which represents 1.0. Check the `alpha` argument to sudo_set_voting_power_ema_alpha; it must be at most 10^18, and the current value is in `VotingPowerEmaAlpha` per netuid.", + "docs_url": "/docs/errors/chain/InvalidVotingPowerEmaAlpha" }, "InvalidWorkBlock": { "code": "invalid_argument", - "description": "The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block." + "description": "The `block_number` in the proof-of-work submission is in the future or more than 3 blocks old, so the work is stale. Compare the submitted block number with the current chain height and regenerate the PoW against a fresh block.", + "docs_url": "/docs/errors/chain/InvalidWorkBlock" }, "IssuanceDeactivated": { "code": "disabled", - "description": "Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again." + "description": "Total issuance cannot be adjusted because issuance has already been deactivated. Check the Balances `InactiveIssuance` state before calling `force_adjust_total_issuance` again.", + "docs_url": "/docs/errors/chain/IssuanceDeactivated" }, "LeaseCannotEndInThePast": { "code": "invalid_argument", - "description": "The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease." + "description": "The `end_block` supplied when registering a leased network is not after the current block. Check the current chain height and pass an `end_block` in the future, or omit it for a perpetual lease.", + "docs_url": "/docs/errors/chain/LeaseCannotEndInThePast" }, "LeaseDoesNotExist": { "code": "not_found", - "description": "The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated." + "description": "The `lease_id` argument does not correspond to any stored lease. Query the `SubnetLeases` storage map to confirm the lease id and whether it was already terminated.", + "docs_url": "/docs/errors/chain/LeaseDoesNotExist" }, "LeaseHasNoEndBlock": { "code": "invalid_argument", - "description": "The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id." + "description": "The lease being terminated is perpetual (its `end_block` is None), so it can never be ended this way. Check the lease's `end_block` field in `SubnetLeases` for the given lease id.", + "docs_url": "/docs/errors/chain/LeaseHasNoEndBlock" }, "LeaseHasNotEnded": { "code": "too_early", - "description": "The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes." + "description": "The lease termination was attempted before the lease's `end_block` was reached. Compare the current block height with the `end_block` stored in `SubnetLeases` for the lease id and retry after it passes.", + "docs_url": "/docs/errors/chain/LeaseHasNotEnded" }, "LeaseNetuidNotFound": { "code": "not_found", - "description": "After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete." + "description": "After registering the leased network, no subnet owned by the lease's derived coldkey could be found, so the netuid lookup failed. Inspect `SubnetOwner` entries for the lease coldkey; this usually indicates the registration did not complete.", + "docs_url": "/docs/errors/chain/LeaseNetuidNotFound" }, "LimitOrdersDisabled": { "code": "disabled", - "description": "Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet." + "description": "Order execution was attempted while the pallet's global switch is off. Check the `LimitOrdersEnabled` storage value; root must call `set_pallet_status` with true to enable the pallet.", + "docs_url": "/docs/errors/chain/LimitOrdersDisabled" }, "LiquidAlphaDisabled": { "code": "disabled", - "description": "Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first." + "description": "Setting `alpha_low`/`alpha_high` was attempted while liquid alpha is disabled on the subnet. Check the `LiquidAlphaOn` hyperparameter (`btcli subnets hyperparameters`) and have the subnet owner enable liquid alpha first.", + "docs_url": "/docs/errors/chain/LiquidAlphaDisabled" }, "LiquidityRestrictions": { "code": "insufficient_balance", - "description": "The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal." + "description": "The withdrawal is blocked by locks or freezes on the account even though the raw balance looks sufficient. Check the account's `Locks` and `Freezes` entries and compare the frozen amount against what would remain after the withdrawal.", + "docs_url": "/docs/errors/chain/LiquidityRestrictions" }, "LockHotkeyMismatch": { "code": "invalid_argument", - "description": "The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first." + "description": "The coldkey already has a conviction lock on this subnet bound to a different hotkey, and locks for one coldkey per subnet must target a single hotkey. Check the existing lock's hotkey in the lock storage for the coldkey and netuid, or move the lock first.", + "docs_url": "/docs/errors/chain/LockHotkeyMismatch" }, "LockIdOverFlow": { "code": "limit_exceeded", - "description": "The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem." + "description": "The global network-registration lock id counter reached its u32 maximum while queueing a subnet registration, so no new lock could be created. Check the `NetworkRegistrationLockId` storage value; this indicates lock id exhaustion, not a balance problem.", + "docs_url": "/docs/errors/chain/LockIdOverFlow" }, "MaxAllowedUIdsLessThanCurrentUIds": { "code": "invalid_argument", - "description": "`sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid." + "description": "`sudo_set_max_allowed_uids` was given a value below the number of neurons already registered on the subnet. Compare the `max_allowed_uids` argument against `SubnetworkN` for that netuid.", + "docs_url": "/docs/errors/chain/MaxAllowedUIdsLessThanCurrentUIds" }, "MaxAllowedUidsGreaterThanDefaultMaxAllowedUids": { "code": "invalid_argument", - "description": "`sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value." + "description": "`sudo_set_max_allowed_uids` was given a value above the chain-wide ceiling. Compare the `max_allowed_uids` argument against the `DefaultMaxAllowedUids` storage value.", + "docs_url": "/docs/errors/chain/MaxAllowedUidsGreaterThanDefaultMaxAllowedUids" }, "MaxAllowedUidsLessThanMinAllowedUids": { "code": "invalid_argument", - "description": "`sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid." + "description": "`sudo_set_max_allowed_uids` was given a value below the subnet's configured minimum. Compare the `max_allowed_uids` argument against `MinAllowedUids` for that netuid.", + "docs_url": "/docs/errors/chain/MaxAllowedUidsLessThanMinAllowedUids" }, "MaxCallDepthReached": { "code": "limit_exceeded", - "description": "A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth." + "description": "A nested contract call would exceed the maximum call stack depth defined in the pallet schedule. Inspect the cross-contract call chain for deep or unbounded recursion and flatten it or raise the configured depth.", + "docs_url": "/docs/errors/chain/MaxCallDepthReached" }, "MaxContributionReached": { "code": "limit_exceeded", - "description": "The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`." + "description": "The contributor's cumulative contribution already equals the crowdloan's per-contributor cap, so further contributions are rejected. Compare their `Contributions` entry with the `MaxContributions` value for the `crowdloan_id`.", + "docs_url": "/docs/errors/chain/MaxContributionReached" }, "MaxContributorsReached": { "code": "limit_exceeded", - "description": "The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant." + "description": "The crowdloan already has the maximum number of distinct contributors, so accounts without an existing contribution are rejected. Compare the `contributors_count` field of the `Crowdloans` entry with the `MaxContributors` pallet constant.", + "docs_url": "/docs/errors/chain/MaxContributorsReached" }, "MaxDelegateDependenciesReached": { "code": "limit_exceeded", - "description": "`lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first." + "description": "`lock_delegate_dependency` failed because the contract already holds the maximum number of delegate dependencies allowed by the runtime. Check the `MaxDelegateDependencies` config value and unlock unused dependencies first.", + "docs_url": "/docs/errors/chain/MaxDelegateDependenciesReached" }, "MaxValidatorsLargerThanMaxUIds": { "code": "invalid_argument", - "description": "`sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid." + "description": "`sudo_set_max_allowed_validators` was given a value exceeding the subnet's UID capacity. Compare the `max_allowed_validators` argument against `MaxAllowedUids` for that netuid.", + "docs_url": "/docs/errors/chain/MaxValidatorsLargerThanMaxUIds" }, "MaxWeightExceeded": { "code": "limit_exceeded", - "description": "After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting." + "description": "After normalization, one of the submitted weights exceeds the subnet's maximum weight limit (self-weight is exempt). Check the `MaxWeightsLimit` hyperparameter (`btcli subnets hyperparameters`) and flatten the weight vector before setting.", + "docs_url": "/docs/errors/chain/MaxWeightExceeded" }, "MaxWeightTooLow": { "code": "invalid_argument", - "description": "The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`." + "description": "The `max_weight` argument supplied with the final multisig approval is lower than the actual weight of the call being dispatched. Compute the call's real dispatch weight and pass a `max_weight` at least that large to `as_multi`.", + "docs_url": "/docs/errors/chain/MaxWeightTooLow" }, "MaximumContributionTooLow": { "code": "invalid_argument", - "description": "The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry." + "description": "The `new_max_contribution` passed to `set_max_contribution` is below the crowdloan's `min_contribution` or below the creator's existing contribution. Check both against the `Crowdloans` entry and the creator's `Contributions` entry.", + "docs_url": "/docs/errors/chain/MaximumContributionTooLow" }, "MechanismDoesNotExist": { "code": "subnet_not_exists", - "description": "The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet." + "description": "The target subnet or its sub-mechanism does not exist: the netuid is unknown, the mechanism index is at or above `MechanismCountCurrent`, or a non-dynamic `mechid` was requested. Check the netuid with `btcli subnets list` and the mechanism count for that subnet.", + "docs_url": "/docs/errors/chain/MechanismDoesNotExist" }, "MigrationInProgress": { "code": "too_early", - "description": "A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it." + "description": "A multi-block storage migration of the contracts pallet is still running, so other extrinsics of the pallet are rejected until it completes. Check the migration status in storage and retry once done, or submit `migrate` calls to advance it.", + "docs_url": "/docs/errors/chain/MigrationInProgress" }, "MinAllowedUidsGreaterThanCurrentUids": { "code": "invalid_argument", - "description": "`sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid." + "description": "`sudo_set_min_allowed_uids` was given a value not strictly below the number of neurons currently registered on the subnet. Compare the `min_allowed_uids` argument against `SubnetworkN` for that netuid.", + "docs_url": "/docs/errors/chain/MinAllowedUidsGreaterThanCurrentUids" }, "MinAllowedUidsGreaterThanMaxAllowedUids": { "code": "invalid_argument", - "description": "`sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid." + "description": "`sudo_set_min_allowed_uids` was given a value not strictly below the subnet's maximum UID capacity. Compare the `min_allowed_uids` argument against `MaxAllowedUids` for that netuid.", + "docs_url": "/docs/errors/chain/MinAllowedUidsGreaterThanMaxAllowedUids" }, "MinimumContributionTooHigh": { "code": "invalid_argument", - "description": "The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`." + "description": "The `new_min_contribution` passed to `update_min_contribution` exceeds the crowdloan's configured per-contributor maximum. Compare it with the `MaxContributions` entry for the `crowdloan_id`.", + "docs_url": "/docs/errors/chain/MinimumContributionTooHigh" }, "MinimumContributionTooLow": { "code": "invalid_argument", - "description": "The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value." + "description": "The minimum contribution given to `create` or `update_min_contribution` is below the chain-wide floor. Check the `AbsoluteMinimumContribution` pallet constant and raise the `min_contribution` argument to at least that value.", + "docs_url": "/docs/errors/chain/MinimumContributionTooLow" }, "MinimumThreshold": { "code": "invalid_argument", - "description": "The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case." + "description": "The multisig `threshold` argument was below 2, which these calls do not accept. Pass a threshold of 2 or more, or use `as_multi_threshold_1` for the single-approval case.", + "docs_url": "/docs/errors/chain/MinimumThreshold" }, "MultiBlockMigrationsOngoing": { "code": "too_early", - "description": "Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade." + "description": "Runtime code replacement is blocked while a multi-block migration is still executing. Wait for the ongoing migrations to complete (check the multi-block migrations cursor) before retrying `set_code` or the authorized upgrade.", + "docs_url": "/docs/errors/chain/MultiBlockMigrationsOngoing" }, "Named": { "code": "invalid_argument", - "description": "An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map." + "description": "An unnamed scheduler function was used on a task that was scheduled with a name. Use the named variants (`cancel_named`, `schedule_named`) with the task's id, which you can find via the `Lookup` storage map.", + "docs_url": "/docs/errors/chain/Named" }, "NeedWaitingMoreBlocksToStarCall": { "code": "too_early", - "description": "The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens." + "description": "The subnet owner called start_call before enough blocks had passed since the subnet was registered. Compare the current block with `NetworkRegisteredAt` for the netuid plus the start-call delay and retry once the window opens.", + "docs_url": "/docs/errors/chain/NeedWaitingMoreBlocksToStarCall" }, "NegativeSigmoidSteepness": { "code": "invalid_argument", - "description": "A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root." + "description": "A non-root caller (subnet owner) passed a negative value to `sudo_set_alpha_sigmoid_steepness`; negative steepness values are reserved for the root origin. Use a non-negative `steepness` or submit the call as root.", + "docs_url": "/docs/errors/chain/NegativeSigmoidSteepness" }, "NetworkDissolveAlreadyQueued": { "code": "already_exists", - "description": "The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request." + "description": "The subnet is already in the dissolve cleanup queue, so it cannot be queued for dissolution again. Check the `DissolveCleanupQueue` storage value for the netuid before submitting another dissolve request.", + "docs_url": "/docs/errors/chain/NetworkDissolveAlreadyQueued" }, "NetworkTxRateLimitExceeded": { "code": "rate_limited", - "description": "The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks." + "description": "The coldkey attempted register_network again before the network registration rate limit elapsed since its previous registration. Check the coldkey's last register-network block against the `NetworkRateLimit` storage value and wait the remaining blocks.", + "docs_url": "/docs/errors/chain/NetworkTxRateLimitExceeded" }, "NeuronNoValidatorPermit": { "code": "not_authorized", - "description": "The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator." + "description": "The hotkey tried to set weights on other neurons without holding a validator permit on that subnet. Check `ValidatorPermit` for the neuron's uid (e.g. via the metagraph or `btcli subnets metagraph`) and whether its stake ranks it as a validator.", + "docs_url": "/docs/errors/chain/NeuronNoValidatorPermit" }, "NewColdKeyIsHotkey": { "code": "invalid_argument", - "description": "The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey." + "description": "The proposed new coldkey in a coldkey swap is already an existing hotkey account, which is not allowed. Check the `Owner` storage for the candidate key to confirm it is not registered as a hotkey, and pick a fresh coldkey.", + "docs_url": "/docs/errors/chain/NewColdKeyIsHotkey" }, "NewHotKeyIsSameWithOld": { "code": "invalid_argument", - "description": "swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey." + "description": "swap_hotkey was called with `new_hotkey` equal to the current hotkey, so there is nothing to swap. Check the extrinsic arguments and supply a different destination hotkey.", + "docs_url": "/docs/errors/chain/NewHotKeyIsSameWithOld" }, "NewHotKeyNotCleanForRootSwap": { "code": "invalid_argument", - "description": "The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey." + "description": "The destination hotkey has pending root claimable dividends, non-zero root stake, or root-claimed history, so root accounting cannot merge safely. Check `RootClaimable` and root-subnet stake for the new hotkey; claim or clear them, or use a fresh hotkey.", + "docs_url": "/docs/errors/chain/NewHotKeyNotCleanForRootSwap" }, "NoApprovalsNeeded": { "code": "invalid_argument", - "description": "The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it." + "description": "The multisig call does not need any more approvals; it is only waiting for final execution with the full call data. Instead of another `approve_as_multi`, submit `as_multi` with the complete call to dispatch it.", + "docs_url": "/docs/errors/chain/NoApprovalsNeeded" }, "NoChainExtension": { "code": "disabled", - "description": "The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against." + "description": "The contract invoked `call_chain_extension` but this runtime registers no chain extension; such code is normally rejected at upload. Check that the target chain provides the chain extension the contract was built against.", + "docs_url": "/docs/errors/chain/NoChainExtension" }, "NoContribution": { "code": "not_found", - "description": "The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question." + "description": "The account has no contribution recorded for this crowdloan, so `withdraw` has nothing to pay out (or `dissolve` finds no creator contribution). Check the `Contributions` double map under the `crowdloan_id` for the account in question.", + "docs_url": "/docs/errors/chain/NoContribution" }, "NoDeposit": { "code": "not_found", - "description": "No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block." + "description": "No safe-mode deposit exists for the given account and block combination, so nothing can be released or slashed. Check the `Deposits` storage map for an entry under that account and deposit block.", + "docs_url": "/docs/errors/chain/NoDeposit" }, "NoExistingLock": { "code": "not_found", - "description": "move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey." + "description": "move_lock was called but no conviction lock exists for the signing coldkey on that subnet. Check the lock storage for the coldkey and netuid, and create a lock before attempting to move it to another hotkey.", + "docs_url": "/docs/errors/chain/NoExistingLock" }, "NoMigrationPerformed": { "code": "invalid_argument", - "description": "A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument." + "description": "A `migrate` call ran but no migration step executed, either because no migration is pending or the supplied `weight_limit` is too small for one step. Check the in-progress migration status and increase the weight limit argument.", + "docs_url": "/docs/errors/chain/NoMigrationPerformed" }, "NoNeuronIdAvailable": { "code": "limit_exceeded", - "description": "Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire." + "description": "Registration could not obtain a uid: the subnet's `MaxAllowedUids` is 0, or the subnet is full and every neuron is immune from pruning. Check `SubnetworkN` versus `MaxAllowedUids` for the netuid and retry after immunity periods expire.", + "docs_url": "/docs/errors/chain/NoNeuronIdAvailable" }, "NoPermission": { "code": "not_authorized", - "description": "The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments." + "description": "The proxy pallet refused the action: the proxied call could escalate privileges, or the caller lacks authority over the pure proxy (e.g. `kill_pure` by a non-spawner). Check the proxy type's call filter and the original `create_pure` arguments.", + "docs_url": "/docs/errors/chain/NoPermission" }, "NoSelfProxy": { "code": "invalid_argument", - "description": "An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account." + "description": "An account attempted to register itself as its own proxy, which is not allowed. Check the `delegate` argument to `add_proxy` and ensure it differs from the calling (delegator) account.", + "docs_url": "/docs/errors/chain/NoSelfProxy" }, "NoTimepoint": { "code": "invalid_argument", - "description": "No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`." + "description": "No timepoint was supplied but this multisig operation is already underway, so the approval cannot be matched to it. Read the operation's `when` field from the `Multisigs` entry for the call hash and pass that height and index as `maybe_timepoint`.", + "docs_url": "/docs/errors/chain/NoTimepoint" }, "NoWeightsCommitFound": { "code": "not_found", - "description": "A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window." + "description": "A weights reveal was submitted but no pending (non-expired) commit exists for the hotkey and netuid, possibly because it already expired. Query the `WeightCommits` storage map for the hotkey and check the commit hasn't passed the reveal window.", + "docs_url": "/docs/errors/chain/NoWeightsCommitFound" }, "NonAssociatedColdKey": { "code": "not_authorized", - "description": "The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it." + "description": "The signing coldkey does not own the hotkey it is trying to operate on (stake, swap, serve, children or take changes). Check the `Owner` storage entry for the hotkey, e.g. via `btcli wallet overview`, and sign with the coldkey that registered it.", + "docs_url": "/docs/errors/chain/NonAssociatedColdKey" }, "NonDefaultComposite": { "code": "invalid_argument", - "description": "The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way." + "description": "The account cannot be killed because its composite account data is not in the default state. Check the account's `System.Account` entry; all balance and data fields must be default before the account can be removed this way.", + "docs_url": "/docs/errors/chain/NonDefaultComposite" }, "NonZeroRefCount": { "code": "invalid_argument", - "description": "The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first." + "description": "The account cannot be purged because other pallets still reference it. Check the `consumers`, `providers`, and `sufficients` counters in the account's `System.Account` record; all references must be released first.", + "docs_url": "/docs/errors/chain/NonZeroRefCount" }, "NoneValue": { "code": "not_found", - "description": "Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization." + "description": "Template leftover in the drand pallet meaning a storage value was read before ever being set; no current code path raises it. If seen, inspect the drand pallet's storage items for missing initialization.", + "docs_url": "/docs/errors/chain/NoneValue" }, "NotAllowed": { "code": "not_authorized", - "description": "Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value." + "description": "Contract deployment was blocked because the source address is not in the `WhitelistedCreators` list while the whitelist check is enabled. Check the deployer address against `WhitelistedCreators` and the `DisableWhitelistCheck` storage value.", + "docs_url": "/docs/errors/chain/NotAllowed" }, "NotAuthorized": { "code": "not_authorized", - "description": "The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`." + "description": "The caller is not permitted to manage this preimage; unnoting or unrequesting requires the pallet's manager origin or the account that originally deposited it. Check which origin noted or requested the preimage and use that origin or the configured `ManagerOrigin`.", + "docs_url": "/docs/errors/chain/NotAuthorized" }, "NotConfigured": { "code": "disabled", - "description": "The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants." + "description": "The permissionless safe-mode operation is disabled because its config option is `None`: `EnterDepositAmount` for `enter`, `ExtendDepositAmount` for `extend`, or `ReleaseDelay` for `release_deposit`. Check the runtime config or use the root-only force variants.", + "docs_url": "/docs/errors/chain/NotConfigured" }, "NotEnoughAlphaOutToRecycle": { "code": "insufficient_liquidity", - "description": "A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount." + "description": "A recycle or burn of alpha requested more than the subnet's outstanding alpha supply. Compare the amount against the `SubnetAlphaOut` storage value for the netuid and reduce the recycle amount.", + "docs_url": "/docs/errors/chain/NotEnoughAlphaOutToRecycle" }, "NotEnoughBalanceToPaySwapColdKey": { "code": "insufficient_balance", - "description": "The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap." + "description": "The coldkey's free TAO balance cannot cover the coldkey swap cost, which is recycled when the swap executes. Check the balance with `btcli wallet balance` against the swap cost and top up before scheduling the swap.", + "docs_url": "/docs/errors/chain/NotEnoughBalanceToPaySwapColdKey" }, "NotEnoughBalanceToPaySwapHotKey": { "code": "insufficient_balance", - "description": "The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying." + "description": "The coldkey's free TAO balance is below the hotkey swap cost (a per-subnet cost applies when swapping on a single netuid). Check `btcli wallet balance` against the key swap cost and fund the coldkey before retrying.", + "docs_url": "/docs/errors/chain/NotEnoughBalanceToPaySwapHotKey" }, "NotEnoughBalanceToStake": { "code": "insufficient_balance", - "description": "The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid)." + "description": "The coldkey's free balance is less than the TAO required, either the stake amount in add_stake or the burn cost of a registration. Check `btcli wallet balance` against the amount or the current registration burn (`Burn` storage for the netuid).", + "docs_url": "/docs/errors/chain/NotEnoughBalanceToStake" }, "NotEnoughStake": { "code": "insufficient_balance", - "description": "The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs." + "description": "The caller's hotkey holds less stake than the action requires; a generic insufficient-stake failure on staking-related calls. Check the hotkey's stake on the relevant subnet, e.g. `btcli stake list`, against the amount the extrinsic needs.", + "docs_url": "/docs/errors/chain/NotEnoughStake" }, "NotEnoughStakeToSetChildkeys": { "code": "insufficient_balance", - "description": "Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value." + "description": "Raised by `set_children` when the parent hotkey's total stake is below `StakeThreshold` and it is not the subnet owner hotkey. Compare the hotkey's total stake (`btcli stake list`) against the `StakeThreshold` storage value.", + "docs_url": "/docs/errors/chain/NotEnoughStakeToSetChildkeys" }, "NotEnoughStakeToSetWeights": { "code": "insufficient_balance", - "description": "Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`." + "description": "Setting or committing weights failed because the hotkey's stake weight on the subnet is below `StakeThreshold` (the weights-min-stake floor); the subnet owner hotkey is exempt. Check the hotkey's stake on that netuid against `StakeThreshold`.", + "docs_url": "/docs/errors/chain/NotEnoughStakeToSetWeights" }, "NotEnoughStakeToWithdraw": { "code": "insufficient_balance", - "description": "An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage)." + "description": "An unstake, stake move, swap, or transfer requested more alpha than the hotkey-coldkey pair holds on that subnet. Compare the requested amount against the pair's current stake on the netuid (`btcli stake list` or the `Alpha` storage).", + "docs_url": "/docs/errors/chain/NotEnoughStakeToWithdraw" }, "NotFound": { "code": "not_found", - "description": "The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state." + "description": "The referenced item does not exist in storage: no multisig operation for that call hash in `Multisigs`, no scheduled task at that slot or name in `Agenda`/`Lookup`, or no matching proxy registration in `Proxies`. Verify the identifier against current chain state.", + "docs_url": "/docs/errors/chain/NotFound" }, "NotNoted": { "code": "not_found", - "description": "The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored." + "description": "The preimage cannot be unnoted because no preimage was ever noted for this hash. Check `RequestStatusFor` (or legacy `StatusFor`) for the hash to confirm what, if anything, is stored.", + "docs_url": "/docs/errors/chain/NotNoted" }, "NotOwner": { "code": "not_authorized", - "description": "Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash." + "description": "Only the account that opened the multisig operation (its depositor) may cancel it or adjust its deposit. Compare the sender against the `depositor` field stored in the `Multisigs` entry for this call hash.", + "docs_url": "/docs/errors/chain/NotOwner" }, "NotPermittedOnRootSubnet": { "code": "invalid_argument", - "description": "An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0." + "description": "An admin-utils call that only applies to regular subnets (burn half-life, burn increase multiplier, owner-cut flags, or the subnet emission toggle) was targeted at the root network. Check that the `netuid` argument is not the root netuid 0.", + "docs_url": "/docs/errors/chain/NotPermittedOnRootSubnet" }, "NotProxy": { "code": "not_authorized", - "description": "The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call." + "description": "The sender is not registered as a proxy for the account it tried to act for. Check the `Proxies` entry of the `real` account and confirm the sender appears there with a proxy type and delay compatible with the call.", + "docs_url": "/docs/errors/chain/NotProxy" }, "NotReadyToDissolve": { "code": "too_early", - "description": "`dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record." + "description": "`dissolve` was called while outside contributions remain: the crowdloan's `raised` amount still exceeds the creator's own contribution. Call `refund` until only the creator's `Contributions` entry remains and equals `raised` in the `Crowdloans` record.", + "docs_url": "/docs/errors/chain/NotReadyToDissolve" }, "NotRequested": { "code": "not_found", - "description": "The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`." + "description": "The preimage request cannot be removed because there are no outstanding requests for this hash. Check the request status for the hash in `RequestStatusFor` before calling `unrequest_preimage`.", + "docs_url": "/docs/errors/chain/NotRequested" }, "NotRootSubnet": { "code": "invalid_argument", - "description": "A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0." + "description": "A call that only operates on the root network, such as setting root network weights, was given a non-root netuid. Check the netuid argument; root operations must target netuid 0.", + "docs_url": "/docs/errors/chain/NotRootSubnet" }, "NotSubnetOwner": { "code": "not_authorized", - "description": "The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`)." + "description": "The signing coldkey is not the recorded owner of the subnet it tried to administer (e.g. setting subnet identity or owner-only hyperparameters). Compare the caller against `SubnetOwner` for that netuid (`btcli subnets show`).", + "docs_url": "/docs/errors/chain/NotSubnetOwner" }, "NothingAuthorized": { "code": "not_found", - "description": "No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code." + "description": "No code upgrade has been authorized, so `apply_authorized_upgrade` has nothing to apply. Check the `AuthorizedUpgrade` storage item in System; an authorization must be recorded before applying the new code.", + "docs_url": "/docs/errors/chain/NothingAuthorized" }, "OrderAlreadyProcessed": { "code": "already_exists", - "description": "The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`." + "description": "The order id already has a terminal status: execution found it fulfilled, or `cancel_order` found any existing status for it. Check the `Orders` storage map under the blake2-256 hash of the SCALE-encoded `VersionedOrder`.", + "docs_url": "/docs/errors/chain/OrderAlreadyProcessed" }, "OrderCancelled": { "code": "expired", - "description": "The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order." + "description": "The order was previously cancelled via `cancel_order` and can never be executed. Check the `Orders` storage entry for the order id; a `Cancelled` status is terminal, so the signer must sign and submit a fresh order.", + "docs_url": "/docs/errors/chain/OrderCancelled" }, "OrderExpired": { "code": "expired", - "description": "The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value." + "description": "The current chain time is past the order's `expiry` field, which is a unix timestamp in milliseconds, so the order can no longer execute. Compare the `expiry` in the signed order payload with the chain's current `Timestamp` value.", + "docs_url": "/docs/errors/chain/OrderExpired" }, "OrderNetUidMismatch": { "code": "invalid_argument", - "description": "An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out." + "description": "An order inside an `execute_batched_orders` call has a `netuid` field different from the batch's `netuid` parameter, which hard-fails the entire batch. Check each order payload's `netuid` against the batch argument and split mismatched orders out.", + "docs_url": "/docs/errors/chain/OrderNetUidMismatch" }, "OutOfBounds": { "code": "invalid_argument", - "description": "A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug." + "description": "A pointer and length pair passed to a contract API host function references memory outside the contract's sandbox. Check the buffer pointers and lengths the contract passes to seal functions; this usually indicates a low-level contract bug.", + "docs_url": "/docs/errors/chain/OutOfBounds" }, "OutOfGas": { "code": "limit_exceeded", - "description": "The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight." + "description": "The contract exhausted the gas limit supplied for this execution before completing. Increase the `gas_limit` argument on `call` or `instantiate`; dry-run the call via RPC to estimate the required weight.", + "docs_url": "/docs/errors/chain/OutOfGas" }, "OutOfTransientStorage": { "code": "limit_exceeded", - "description": "A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit." + "description": "A write would exceed the per-execution byte limit for transient storage. Check how much data the contract places in transient storage during the call against the runtime's transient storage limit.", + "docs_url": "/docs/errors/chain/OutOfTransientStorage" }, "OutputBufferTooSmall": { "code": "invalid_argument", - "description": "The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug." + "description": "The output buffer the contract supplied to an API call is smaller than the data the runtime needs to write back. Check the output length pointer the contract passes and enlarge the buffer; usually a contract-side bug.", + "docs_url": "/docs/errors/chain/OutputBufferTooSmall" }, "Overflow": { "code": "internal", - "description": "A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values." + "description": "A checked arithmetic operation overflowed, e.g. incrementing `NextSubnetLeaseId` when registering a leased network, or adding to a crowdloan's `raised` amount or contributor count. Internal guard; inspect the amounts involved as this should not occur with realistic values.", + "docs_url": "/docs/errors/chain/Overflow" }, "POWRegistrationDisabled": { "code": "disabled", - "description": "`sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled." + "description": "`sudo_set_network_pow_registration_allowed` unconditionally fails because proof-of-work registration is deprecated and its toggle can no longer be changed. Nothing to check; the call is permanently disabled.", + "docs_url": "/docs/errors/chain/POWRegistrationDisabled" }, "PalletHotkeyNotRegistered": { "code": "not_registered", - "description": "Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs." + "description": "Root tried to enable the pallet via `set_pallet_status` before its hotkey was registered to the pallet's intermediary account. Check that the `PalletHotkey` constant is registered for the pallet account, which genesis or the `on_runtime_upgrade` migration performs.", + "docs_url": "/docs/errors/chain/PalletHotkeyNotRegistered" }, "PartialFillsNotEnabled": { "code": "disabled", - "description": "A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing." + "description": "A `partial_fill` amount was supplied for an order whose signed payload has `partial_fills_enabled` set to false. Check that field in the order payload; partial execution requires the signer to have opted in when signing.", + "docs_url": "/docs/errors/chain/PartialFillsNotEnabled" }, "PauseFailed": { "code": "invalid_argument", - "description": "A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause." + "description": "A GRANDPA pause was signalled while the authority set is not live, i.e. it is already paused or a pause is already pending. Check the Grandpa `State` storage before signalling a pause.", + "docs_url": "/docs/errors/chain/PauseFailed" }, "PaymentOverflow": { "code": "internal", - "description": "Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction." + "description": "Arithmetic overflowed while computing the total payment or refund for an EVM transaction, such as refunding remaining gas at the effective gas price. Check for extreme gas price or gas limit values in the transaction.", + "docs_url": "/docs/errors/chain/PaymentOverflow" }, "PreLogExists": { "code": "invalid_argument", - "description": "An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it." + "description": "An `ethereum.transact` extrinsic was submitted in a block that already carries a pre-log digest, meaning an Ethereum transaction is being injected by other means. Check the block's digest for a pre-runtime Ethereum log; transact is not allowed alongside it.", + "docs_url": "/docs/errors/chain/PreLogExists" }, "PriceConditionNotMet": { "code": "too_early", - "description": "The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field." + "description": "The subnet's current alpha price does not satisfy the order's trigger: buys and stop-losses require price at or below `limit_price`, take-profits at or above it. Compare `current_alpha_price` for the order's `netuid`, scaled by 1e9, with the `limit_price` field.", + "docs_url": "/docs/errors/chain/PriceConditionNotMet" }, "PriceLimitExceeded": { "code": "insufficient_liquidity", - "description": "The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting." + "description": "The `limit_price` given to a swap is not beyond the current pool price in the trade's direction, so the swap would immediately breach it. Compare the limit price argument against the subnet's current alpha price before submitting.", + "docs_url": "/docs/errors/chain/PriceLimitExceeded" }, "ProportionOverflow": { "code": "invalid_argument", - "description": "The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX." + "description": "The child proportions passed to `set_children` sum to more than u64::MAX. Reduce the per-child proportion values so their total fits in a u64; each proportion is a fraction of u64::MAX.", + "docs_url": "/docs/errors/chain/ProportionOverflow" }, "PulseVerificationError": { "code": "invalid_argument", - "description": "BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key)." + "description": "BLS signature verification of a submitted drand pulse against the stored beacon configuration failed. Check the pulse's signature and round against the `BeaconConfig` storage (drand quicknet public key).", + "docs_url": "/docs/errors/chain/PulseVerificationError" }, "RandomSubjectTooLong": { "code": "limit_exceeded", - "description": "The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section." + "description": "The subject buffer given to the deprecated `seal_random` API exceeds the schedule's `subject_len` limit. Shorten the randomness subject the contract passes or check the schedule's limits section.", + "docs_url": "/docs/errors/chain/RandomSubjectTooLong" }, "ReentranceDenied": { "code": "invalid_argument", - "description": "A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag." + "description": "A call tried to re-enter a contract already on the call stack without reentrancy being allowed, or contract code called back into the contracts pallet through the runtime. Check the callee address against the current call stack and the ALLOW_REENTRY call flag.", + "docs_url": "/docs/errors/chain/ReentranceDenied" }, "Reentrancy": { "code": "internal", - "description": "EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call." + "description": "EVM execution re-entered the pallet while another EVM execution was already in progress on the same thread, e.g. a precompile or runtime call dispatching back into the EVM. Inspect precompiles and runtime code that invoke the EVM from within an EVM call.", + "docs_url": "/docs/errors/chain/Reentrancy" }, "RegistrationNotPermittedOnRootSubnet": { "code": "invalid_argument", - "description": "A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership." + "description": "A neuron registration or child-hotkey operation (`register`, `burned_register`, `set_children`) was called with the root netuid, where these calls are invalid. Check the netuid argument; use a regular subnet, or `root_register` for root membership.", + "docs_url": "/docs/errors/chain/RegistrationNotPermittedOnRootSubnet" }, "RegistrationPriceLimitExceeded": { "code": "limit_exceeded", - "description": "`burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay." + "description": "`burned_register` with a price limit failed because the subnet's current registration burn cost exceeds the supplied `limit_price`. Check the current burn via `Burn` storage or `btcli subnets list` and raise the limit or wait for the cost to decay.", + "docs_url": "/docs/errors/chain/RegistrationPriceLimitExceeded" }, "RelayerMissMatch": { "code": "invalid_argument", - "description": "The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload." + "description": "The order's `relayer` allowlist is set but the account that submitted the execution transaction is not in it. Compare the extrinsic's signing account against the `relayer` list in the signed order payload.", + "docs_url": "/docs/errors/chain/RelayerMissMatch" }, "RelayerRequiredForPartialFill": { "code": "invalid_argument", - "description": "A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount." + "description": "A `partial_fill` was requested for an order whose `relayer` field is empty; partial fills are only permitted on orders that restrict who may execute them. Check the order payload and either set a relayer list or execute the full amount.", + "docs_url": "/docs/errors/chain/RelayerRequiredForPartialFill" }, "Requested": { "code": "invalid_argument", - "description": "The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed." + "description": "The preimage cannot be unnoted while there are still outstanding requests for it. Check the request count in the hash's request status; all requests must be cleared before the preimage can be removed.", + "docs_url": "/docs/errors/chain/Requested" }, "RequireSudo": { "code": "not_authorized", - "description": "The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item." + "description": "The call requires the sudo key but was signed by a different account. Compare the sender against the account stored in the Sudo pallet's `Key` storage item.", + "docs_url": "/docs/errors/chain/RequireSudo" }, "RescheduleNoChange": { "code": "invalid_argument", - "description": "The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block." + "description": "The reschedule was rejected because the new dispatch time equals the task's currently scheduled time. Check the task's existing slot in `Agenda` and pass a genuinely different `when` block.", + "docs_url": "/docs/errors/chain/RescheduleNoChange" }, "ReservesOutOfBalance": { "code": "insufficient_liquidity", - "description": "Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry." + "description": "Swap balancer initialization failed because the subnet's TAO and alpha reserves produce an invalid ratio, for example both reserves are zero when an initial price is supplied. Inspect the subnet's TAO and alpha reserves and the `SwapBalancer` entry.", + "docs_url": "/docs/errors/chain/ReservesOutOfBalance" }, "ReservesTooLow": { "code": "insufficient_liquidity", - "description": "The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size." + "description": "The output-side reserve is below the swap pallet's `MinimumReserve`, or a swap step produced zero output for a nonzero input. Check the subnet's TAO and alpha reserves against `MinimumReserve` and reduce the trade size.", + "docs_url": "/docs/errors/chain/ReservesTooLow" }, "ResumeFailed": { "code": "invalid_argument", - "description": "A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume." + "description": "A GRANDPA resume was signalled while the authority set is not paused, i.e. it is live or already pending a resume. Check the Grandpa `State` storage before signalling a resume.", + "docs_url": "/docs/errors/chain/ResumeFailed" }, "RevealPeriodTooLarge": { "code": "invalid_argument", - "description": "`set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid." + "description": "`set_reveal_period` was given a commit-reveal period above the compiled-in maximum number of epochs. Lower the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid.", + "docs_url": "/docs/errors/chain/RevealPeriodTooLarge" }, "RevealPeriodTooSmall": { "code": "invalid_argument", - "description": "`set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid." + "description": "`set_reveal_period` was given a commit-reveal period below the compiled-in minimum number of epochs. Raise the `reveal_period` argument; the current setting is readable from `RevealPeriodEpochs` for the netuid.", + "docs_url": "/docs/errors/chain/RevealPeriodTooSmall" }, "RevealTooEarly": { "code": "too_early", - "description": "A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch." + "description": "A weight reveal was submitted before the commit's reveal window: the current epoch must equal the commit epoch plus the reveal period. Check the commit in `WeightCommits` and the subnet's `RevealPeriodEpochs`, then wait for the reveal epoch.", + "docs_url": "/docs/errors/chain/RevealTooEarly" }, "RootNetUidNotAllowed": { "code": "invalid_argument", - "description": "The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet." + "description": "The order or batch targets the root subnet, netuid 0, which the limit orders pallet does not serve. Check the `netuid` field of the order payload or the `netuid` parameter of the batch call and target a non-root subnet.", + "docs_url": "/docs/errors/chain/RootNetUidNotAllowed" }, "RootNetworkDoesNotExist": { "code": "subnet_not_exists", - "description": "Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`." + "description": "Root registration or root stake claiming found no root network in chain state, which only happens on misconfigured or freshly bootstrapped chains. Verify netuid 0 exists in `NetworksAdded`.", + "docs_url": "/docs/errors/chain/RootNetworkDoesNotExist" }, "SameAutoStakeHotkeyAlreadySet": { "code": "already_exists", - "description": "The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted." + "description": "The coldkey tried to set its auto-stake destination on a subnet to the hotkey that is already configured. Read `AutoStakeDestination` for the coldkey and netuid before calling; only a different hotkey is accepted.", + "docs_url": "/docs/errors/chain/SameAutoStakeHotkeyAlreadySet" }, "SameNetuid": { "code": "invalid_argument", - "description": "A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ." + "description": "A stake swap or move where coldkey, hotkey, and subnet are all unchanged, so `origin_netuid` equals `destination_netuid` with nothing to transition. Check the call arguments; at least the subnet or one of the keys must differ.", + "docs_url": "/docs/errors/chain/SameNetuid" }, "SenderInSignatories": { "code": "invalid_argument", - "description": "The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting." + "description": "The multisig sender was included in the `other_signatories` list, but that list must contain only the remaining signatories. Remove the sender's own account from `other_signatories` before resubmitting.", + "docs_url": "/docs/errors/chain/SenderInSignatories" }, "ServingRateLimitExceeded": { "code": "rate_limited", - "description": "`serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait." + "description": "`serve_axon` or `serve_prometheus` was called again before enough blocks passed since the neuron's last serving update. Check the axon's last update block in `Axons` against the `ServingRateLimit` (serving_rate_limit hyperparameter) and wait.", + "docs_url": "/docs/errors/chain/ServingRateLimitExceeded" }, "SettingWeightsTooFast": { "code": "rate_limited", - "description": "The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks." + "description": "The neuron set weights again before `WeightsSetRateLimit` blocks elapsed since its last weight update on that subnet. Check the weights_rate_limit hyperparameter and the neuron's `LastUpdate` entry, then wait the remaining blocks.", + "docs_url": "/docs/errors/chain/SettingWeightsTooFast" }, "SignatoriesOutOfOrder": { "code": "invalid_argument", - "description": "The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting." + "description": "The `other_signatories` list is not sorted in strictly ascending account order, which the multisig pallet requires for a canonical account derivation. Sort the list and remove duplicates before resubmitting.", + "docs_url": "/docs/errors/chain/SignatoriesOutOfOrder" }, "SlippageTooHigh": { "code": "insufficient_liquidity", - "description": "A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution." + "description": "A stake, unstake, or move with a price limit would execute at a worse rate than the limit allows and `allow_partial` was false. Compare the `limit_price` argument with the subnet's current alpha price (`btcli subnets price`) or permit partial execution.", + "docs_url": "/docs/errors/chain/SlippageTooHigh" }, "SpaceLimitExceeded": { "code": "rate_limited", - "description": "The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage." + "description": "The commitment would push the account's byte quota for the current epoch over the cap; each `set_commitment` consumes at least 100 bytes. Check `UsedSpaceOf` for the netuid and account against `MaxSpace`, or wait for the next epoch to reset usage.", + "docs_url": "/docs/errors/chain/SpaceLimitExceeded" }, "SpecVersionNeedsToIncrease": { "code": "invalid_argument", - "description": "The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain." + "description": "The new runtime's `spec_version` is not greater than the current one, so the upgrade is rejected. Check the `RuntimeVersion` in the new wasm and bump `spec_version` above the version currently on chain.", + "docs_url": "/docs/errors/chain/SpecVersionNeedsToIncrease" }, "StakeTooLowForRoot": { "code": "insufficient_balance", - "description": "`root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`)." + "description": "`root_register` when the root network is full and the hotkey's stake on netuid 0 does not exceed the lowest-staked current root member. Compare your hotkey's root stake against existing root validators (`btcli root list`).", + "docs_url": "/docs/errors/chain/StakeTooLowForRoot" }, "StakeUnavailable": { "code": "insufficient_balance", - "description": "An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked." + "description": "An unstake would dip into stake that is still locked: the requested alpha exceeds the coldkey's unlocked balance on that subnet. Check the `Lock` entry for the coldkey and netuid; only total stake minus the decaying locked mass can be unstaked.", + "docs_url": "/docs/errors/chain/StakeUnavailable" }, "StakingRateLimitExceeded": { "code": "rate_limited", - "description": "Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block." + "description": "Staking operations (add_stake, remove_stake, and similar) were submitted faster than the per-block staking rate limit allows for the hotkey-coldkey pair. Space the transactions out and retry in a later block.", + "docs_url": "/docs/errors/chain/StakingRateLimitExceeded" }, "StartCallNotReady": { "code": "too_early", - "description": "`start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder." + "description": "`start_call` was made before `StartCallDelay` blocks elapsed since the subnet was registered. Compare the current block against `NetworkRegisteredAt` for the netuid plus `StartCallDelay`, and wait for the remainder.", + "docs_url": "/docs/errors/chain/StartCallNotReady" }, "StateChangeDenied": { "code": "not_authorized", - "description": "The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context." + "description": "The contract invoked a state-modifying host function, such as a storage write, transfer, or value-bearing call, while executing in read-only mode. Check whether the enclosing call was made with the read-only flag or from a static context.", + "docs_url": "/docs/errors/chain/StateChangeDenied" }, "StorageDepositLimitExhausted": { "code": "limit_exceeded", - "description": "The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`." + "description": "The execution created more storage than the caller's `storage_deposit_limit` allows to be charged. Raise the `storage_deposit_limit` argument or reduce storage usage; a dry-run reports the required `storage_deposit`.", + "docs_url": "/docs/errors/chain/StorageDepositLimitExhausted" }, "StorageDepositNotEnoughFunds": { "code": "insufficient_balance", - "description": "The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit." + "description": "The origin's free balance cannot cover the storage deposit limit specified or required for this call. Check the caller's withdrawable balance against the `storage_deposit_limit` argument and the dry-run's reported deposit.", + "docs_url": "/docs/errors/chain/StorageDepositNotEnoughFunds" }, "StorageOverflow": { "code": "internal", - "description": "Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit." + "description": "Template leftover in the drand pallet for a counter increment overflowing `u32::MAX`; no current code path raises it. If seen, inspect the drand pallet's stored counters for values near the u32 limit.", + "docs_url": "/docs/errors/chain/StorageOverflow" }, "SubNetRegistrationDisabled": { "code": "disabled", - "description": "Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid." + "description": "Neuron registration is switched off: either the subnet's `NetworkRegistrationAllowed` flag is false, or network creation has not opened yet (`NetworkRegistrationStartBlock` is in the future). Check the network_registration_allowed hyperparameter for the netuid.", + "docs_url": "/docs/errors/chain/SubNetRegistrationDisabled" }, "SubnetBuybackRateLimitExceeded": { "code": "rate_limited", - "description": "A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback." + "description": "A subnet buyback operation (staking TAO and immediately burning the acquired alpha, e.g. via `add_stake_burn`) was repeated within its rate-limit window. Wait for the window to pass before retrying the buyback.", + "docs_url": "/docs/errors/chain/SubnetBuybackRateLimitExceeded" }, "SubnetDoesNotExist": { "code": "subnet_not_exists", - "description": "The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters." + "description": "The admin-utils call targets a netuid with no registered subnet. Verify the `netuid` argument against `NetworksAdded` (the set of existing subnets) before setting hyperparameters.", + "docs_url": "/docs/errors/chain/SubnetDoesNotExist" }, "SubnetLimitReached": { "code": "limit_exceeded", - "description": "`register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable." + "description": "`register_network` failed because the subnet count is at the network limit and no existing subnet is eligible to be pruned. Check the number of registered subnets (`btcli subnets list`) against the subnet limit and retry once a subnet becomes prunable.", + "docs_url": "/docs/errors/chain/SubnetLimitReached" }, "SubnetNotExists": { "code": "subnet_not_exists", - "description": "The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved." + "description": "The netuid passed to the call does not correspond to a registered subnet. Verify the netuid argument against `NetworksAdded` or `btcli subnets list`; the subnet may also have been dissolved.", + "docs_url": "/docs/errors/chain/SubnetNotExists" }, "SubtokenDisabled": { "code": "subtoken_disabled", - "description": "The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved." + "description": "The subnet's alpha token is not yet enabled, so staking, swapping, and trading on it are blocked; `SubtokenEnabled` is false until the owner makes the `start_call` after registration. Check `SubtokenEnabled` for the netuid involved.", + "docs_url": "/docs/errors/chain/SubtokenDisabled" }, "SwapInputTooLarge": { "code": "insufficient_liquidity", - "description": "The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed." + "description": "The swap's net input after fees exceeds 1000 times the input-side reserve, the pallet's hard per-trade cap. Compare the input amount against the subnet's input-side reserve (TAO or alpha) and split the trade if needed.", + "docs_url": "/docs/errors/chain/SwapInputTooLarge" }, "SwapReturnedZero": { "code": "insufficient_liquidity", - "description": "The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit." + "description": "The netted pool swap in `execute_batched_orders` produced zero output for a non-zero input, meaning the pool lacks liquidity or the derived price limit clamped the swap entirely. Check the subnet pool's reserves and the batch's tightest slippage-derived price limit.", + "docs_url": "/docs/errors/chain/SwapReturnedZero" }, "SymbolAlreadyInUse": { "code": "already_exists", - "description": "The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken." + "description": "The token symbol requested for the subnet is already assigned to another subnet. Scan `TokenSymbol` across netuids and pick a symbol that is not taken.", + "docs_url": "/docs/errors/chain/SymbolAlreadyInUse" }, "SymbolDoesNotExist": { "code": "not_found", - "description": "The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry." + "description": "The requested token symbol is not in the chain's predefined symbol table, so it cannot be assigned to a subnet. Check the symbol argument against the chain's built-in `SYMBOLS` list and choose a valid entry.", + "docs_url": "/docs/errors/chain/SymbolDoesNotExist" }, "TargetBlockNumberInPast": { "code": "invalid_argument", - "description": "The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block." + "description": "The scheduler was given a dispatch block that is not in the future. Compare the `when` argument against the current block number and choose a strictly later block.", + "docs_url": "/docs/errors/chain/TargetBlockNumberInPast" }, "TempoOutOfBounds": { "code": "invalid_argument", - "description": "`set_tempo` was given a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range. Check the tempo argument against those chain constants and pick a value inside the bounds." + "description": "The subnet owner gave `sudo_set_tempo` a tempo outside the allowed MIN_TEMPO to MAX_TEMPO range (360-50,400 blocks). Check the tempo argument against those chain constants and pick a value inside the bounds; only root may set a tempo outside them.", + "docs_url": "/docs/errors/chain/TempoOutOfBounds" }, "TerminatedInConstructor": { "code": "internal", - "description": "The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls." + "description": "The contract called `seal_terminate` inside its constructor, self-destructing during instantiation, which is forbidden. Inspect the constructor logic; termination is only allowed in regular message calls.", + "docs_url": "/docs/errors/chain/TerminatedInConstructor" }, "TerminatedWhileReentrant": { "code": "invalid_argument", - "description": "`seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated." + "description": "`seal_terminate` was called on a contract that appears more than once on the call stack, so termination was refused. Check the call chain for reentrant calls into the contract being terminated.", + "docs_url": "/docs/errors/chain/TerminatedWhileReentrant" }, "TooBig": { "code": "limit_exceeded", - "description": "The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it." + "description": "The preimage exceeds the maximum size the pallet will store on-chain (4 MiB). Check the byte length of the preimage against the pallet's `MAX_SIZE` limit before noting it.", + "docs_url": "/docs/errors/chain/TooBig" }, "TooFew": { "code": "invalid_argument", - "description": "The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`." + "description": "The bulk preimage upgrade was requested with zero hashes, so there is nothing to do. Pass at least one hash to `ensure_updated`.", + "docs_url": "/docs/errors/chain/TooFew" }, "TooFewSignatories": { "code": "invalid_argument", - "description": "The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using." + "description": "The multisig signatory list is too short: `other_signatories` must contain at least one account besides the sender. Check the length of `other_signatories` against the threshold you are using.", + "docs_url": "/docs/errors/chain/TooFewSignatories" }, "TooMany": { "code": "limit_exceeded", - "description": "A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`." + "description": "A limit was exceeded: more preimage hashes than `MAX_HASH_UPGRADE_BULK_COUNT` were passed to `ensure_updated`, or the account has hit its proxy or announcement cap. Check the account's `Proxies` and `Announcements` entries against `MaxProxies` and `MaxPending`.", + "docs_url": "/docs/errors/chain/TooMany" }, "TooManyCalls": { "code": "limit_exceeded", - "description": "The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions." + "description": "The batch submitted to the utility pallet contains more calls than the batched-calls limit allows. Check the length of the `calls` vector and split the work across multiple smaller `batch`, `batch_all`, or `force_batch` submissions.", + "docs_url": "/docs/errors/chain/TooManyCalls" }, "TooManyChildren": { "code": "limit_exceeded", - "description": "`set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries." + "description": "`set_children` was called with more than 5 child hotkeys for a parent on the subnet. Trim the children list to at most 5 entries.", + "docs_url": "/docs/errors/chain/TooManyChildren" }, "TooManyFieldsInCommitmentInfo": { "code": "limit_exceeded", - "description": "The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit." + "description": "The `CommitmentInfo` passed to `set_commitment` contains more entries in `fields` than the pallet's `MaxFields` config allows. Count the fields in the `info` argument and trim to the `MaxFields` limit.", + "docs_url": "/docs/errors/chain/TooManyFieldsInCommitmentInfo" }, "TooManyFreezes": { "code": "limit_exceeded", - "description": "The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first." + "description": "The account already has the maximum number of balance freezes, so a new freeze cannot be added. Check the account's `Freezes` entry against the `MaxFreezes` constant; an existing freeze must be thawed first.", + "docs_url": "/docs/errors/chain/TooManyFreezes" }, "TooManyHolds": { "code": "limit_exceeded", - "description": "The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another." + "description": "The account already carries the maximum number of balance holds, one per hold reason variant. Check the account's `Holds` entry; an existing hold must be released before a new reason can place another.", + "docs_url": "/docs/errors/chain/TooManyHolds" }, "TooManyPendingExtrinsics": { "code": "limit_exceeded", - "description": "`store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire." + "description": "`store_encrypted` was rejected because the shield pallet's queue of encrypted extrinsics is already at capacity. Compare the `PendingExtrinsics` count against `MaxPendingExtrinsicsLimit` and wait for queued items to be processed or expire.", + "docs_url": "/docs/errors/chain/TooManyPendingExtrinsics" }, "TooManyRegistrationsThisBlock": { "code": "rate_limited", - "description": "Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block." + "description": "Registrations in the current block already reached the subnet's per-block cap (`MaxRegistrationsPerBlock`, the max_regs_per_block hyperparameter); root registration enforces the same cap on netuid 0. Retry in the next block.", + "docs_url": "/docs/errors/chain/TooManyRegistrationsThisBlock" }, "TooManyRegistrationsThisInterval": { "code": "rate_limited", - "description": "Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start." + "description": "Registrations in the current interval reached the cap of three times `TargetRegistrationsPerInterval` for the subnet. Compare `RegistrationsThisInterval` against that hyperparameter and wait for the next interval to start.", + "docs_url": "/docs/errors/chain/TooManyRegistrationsThisInterval" }, "TooManyReserves": { "code": "limit_exceeded", - "description": "The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another." + "description": "The account already has the maximum number of named reserves. Check the account's `Reserves` entry against the `MaxReserves` constant; a named reserve must be unreserved before adding another.", + "docs_url": "/docs/errors/chain/TooManyReserves" }, "TooManySignatories": { "code": "limit_exceeded", - "description": "The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant." + "description": "The multisig signatory list exceeds the maximum allowed. Compare the length of `other_signatories` plus the sender against the pallet's `MaxSignatories` constant.", + "docs_url": "/docs/errors/chain/TooManySignatories" }, "TooManyTopics": { "code": "limit_exceeded", - "description": "The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit." + "description": "The number of topics passed to `seal_deposit_event` exceeds the schedule's `event_topics` limit. Reduce the number of indexed topics in the contract's event definition or compare against the schedule limit.", + "docs_url": "/docs/errors/chain/TooManyTopics" }, "TooManyUIDsPerMechanism": { "code": "limit_exceeded", - "description": "Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit." + "description": "Setting max UIDs or mechanism count would make max_uids times mechanism_count exceed the chain default of 256 UIDs per subnet. Check `MaxAllowedUids` and the subnet's mechanism count so their product stays within the limit.", + "docs_url": "/docs/errors/chain/TooManyUIDsPerMechanism" }, "TooManyUnrevealedCommits": { "code": "limit_exceeded", - "description": "`commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again." + "description": "`commit_weights` (or a CRv3 commit) failed because the hotkey already has 10 unrevealed commits queued on the subnet. Inspect `WeightCommits` for the hotkey and reveal or let old commits expire before committing again.", + "docs_url": "/docs/errors/chain/TooManyUnrevealedCommits" }, "TooSoon": { "code": "rate_limited", - "description": "A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change." + "description": "A forced GRANDPA authority change was signalled too soon after the previous one. Check the Grandpa `NextForced` storage and wait until the current block passes it before signalling another forced change.", + "docs_url": "/docs/errors/chain/TooSoon" }, "TransactionMustComeFromEOA": { "code": "not_authorized", - "description": "Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead." + "description": "Rejected per EIP-3607: the sender address has contract code deployed, and transactions must originate from externally owned accounts. Check `eth_getCode` for the `source` address and sign with a plain EOA key instead.", + "docs_url": "/docs/errors/chain/TransactionMustComeFromEOA" }, "TransactorAccountShouldBeHotKey": { "code": "not_authorized", - "description": "The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin." + "description": "The extrinsic must be signed by the hotkey itself, but a different account (typically the coldkey) was the origin. Check which key signs the transaction; calls like axon serving expect the hotkey as origin.", + "docs_url": "/docs/errors/chain/TransactorAccountShouldBeHotKey" }, "TransferDisallowed": { "code": "disabled", - "description": "A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first." + "description": "A stake transfer or cross-subnet move was attempted while the origin or destination subnet has stake transfers switched off. Check the `TransferToggle` storage for both netuids involved; the subnet owner must enable transfers first.", + "docs_url": "/docs/errors/chain/TransferDisallowed" }, "TransferFailed": { "code": "insufficient_balance", - "description": "A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit." + "description": "A balance transfer performed during the contract call failed, most likely because the sender lacks enough free balance. Check the transferring account's free balance against the `value` being sent, accounting for the existential deposit.", + "docs_url": "/docs/errors/chain/TransferFailed" }, "TrimmingWouldExceedMaxImmunePercentage": { "code": "limit_exceeded", - "description": "Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target." + "description": "Trimming the subnet's UIDs cannot proceed because immune neurons would make up at least the maximum immune share (80%) of the reduced slot count. Check neurons still in `ImmunityPeriod` and retry after their immunity lapses or with a higher max UID target.", + "docs_url": "/docs/errors/chain/TrimmingWouldExceedMaxImmunePercentage" }, "TxChildkeyTakeRateLimitExceeded": { "code": "rate_limited", - "description": "`set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder." + "description": "`set_childkey_take` was called again for the hotkey on this subnet before its rate-limit window elapsed. Check the block of the last childkey-take change against `TxChildkeyTakeRateLimit` and wait out the remainder.", + "docs_url": "/docs/errors/chain/TxChildkeyTakeRateLimitExceeded" }, "TxRateLimitExceeded": { "code": "rate_limited", - "description": "An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass." + "description": "An owner or admin transaction (e.g. `set_children`, tempo or hyperparameter updates, setting the owner hotkey) was repeated within its rate-limit window for that key and subnet. Check when the same transaction type last succeeded and wait for the limit to pass.", + "docs_url": "/docs/errors/chain/TxRateLimitExceeded" }, "UidMapCouldNotBeCleared": { "code": "internal", - "description": "During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it." + "description": "During a UID reshuffle or trim, clearing the subnet's `Uids` map left residual entries (the storage clear returned a cursor). Internal state inconsistency rather than a caller error; inspect the `Uids` storage for the netuid and report it.", + "docs_url": "/docs/errors/chain/UidMapCouldNotBeCleared" }, "UidVecContainInvalidOne": { "code": "invalid_argument", - "description": "The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`)." + "description": "The weight submission includes a UID that is not registered on the subnet, i.e. at least one entry is not below `SubnetworkN`. Check the `uids` argument against the subnet's neuron count in the metagraph (`btcli subnets metagraph`).", + "docs_url": "/docs/errors/chain/UidVecContainInvalidOne" }, "UidsLengthExceedUidsInSubNet": { "code": "limit_exceeded", - "description": "The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector." + "description": "The weight submission contains more UID entries than there are neurons registered on the subnet. Compare the length of the `uids` argument against `SubnetworkN` for the netuid and trim the vector.", + "docs_url": "/docs/errors/chain/UidsLengthExceedUidsInSubNet" }, "UnableToRecoverPublicKey": { "code": "invalid_argument", - "description": "While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key." + "description": "While associating an EVM key, the secp256k1 public key recovered from the supplied signature could not be parsed. Check that the signature was produced by signing the expected EIP-191 message (hotkey plus block hash) with the EVM private key.", + "docs_url": "/docs/errors/chain/UnableToRecoverPublicKey" }, "Unannounced": { "code": "too_early", - "description": "The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`." + "description": "The proxied call was executed before its announcement matured, or no matching announcement exists at all. Check the proxy's `Announcements` entry for the call hash and the `delay` on the proxy registration; enough blocks must elapse between `announce` and `proxy_announced`.", + "docs_url": "/docs/errors/chain/Unannounced" }, "Unauthorized": { "code": "not_authorized", - "description": "In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`." + "description": "In System, the code passed to `apply_authorized_upgrade` does not hash to the value in `AuthorizedUpgrade`. In LimitOrders, the caller is not the order's signer, who alone may cancel it. Check the code hash against the authorization, or the sender against the order's `signer`.", + "docs_url": "/docs/errors/chain/Unauthorized" }, "Undefined": { "code": "internal", - "description": "Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs." + "description": "Catch-all EVM validation error for cases without a dedicated variant, such as a malformed EIP-7702 authorization list or an unknown validation failure. Inspect the raw transaction for unsupported fields and check the node logs.", + "docs_url": "/docs/errors/chain/Undefined" }, "Underflow": { "code": "internal", - "description": "A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`." + "description": "A checked subtraction underflowed in crowdloan accounting, e.g. `raised` exceeding `cap` when computing remaining room, or a contributor count decrement, indicating inconsistent state. Inspect the `Crowdloans` and `Contributions` entries for the `crowdloan_id`.", + "docs_url": "/docs/errors/chain/Underflow" }, "UnexpectedTimepoint": { "code": "invalid_argument", - "description": "A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry." + "description": "A timepoint was supplied but no multisig operation is underway for this call hash; the first approval must open the operation with no timepoint. Pass `maybe_timepoint: None` on the opening call, or verify the call hash matches an existing `Multisigs` entry.", + "docs_url": "/docs/errors/chain/UnexpectedTimepoint" }, "UnexpectedUnreserveLeftover": { "code": "internal", - "description": "While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`." + "description": "While lowering a commitment deposit, `Currency::unreserve` failed to return the full difference, leaving a leftover, which signals an internal inconsistency. Check the account's reserved balance against the deposit recorded in `CommitmentOf`.", + "docs_url": "/docs/errors/chain/UnexpectedUnreserveLeftover" }, "UnlockAmountTooHigh": { "code": "insufficient_balance", - "description": "An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount." + "description": "An unlock requested more alpha than remains locked for the coldkey on that subnet. Check the lock's remaining decaying locked mass in the `Lock` storage entry and request at most that amount.", + "docs_url": "/docs/errors/chain/UnlockAmountTooHigh" }, "Unproxyable": { "code": "not_authorized", - "description": "The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call." + "description": "The attempted call is not permitted by the registered proxy type's call filter. Check which `proxy_type` the sender holds in the real account's `Proxies` entry and whether that type's `InstanceFilter` allows this specific call.", + "docs_url": "/docs/errors/chain/Unproxyable" }, "Unreachable": { "code": "internal", - "description": "`announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring." + "description": "`announce_next_key` could not identify the current block author via the `FindAuthors` lookup, which should be impossible in a normally authored block. Check the block's author digest and the shield pallet's authorship wiring.", + "docs_url": "/docs/errors/chain/Unreachable" }, "UnverifiedPulse": { "code": "invalid_argument", - "description": "Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`." + "description": "Declared for drand pulses that fail validity checks, but current code raises `PulseVerificationError` for verification failures and silently skips unverified pulses. If seen on an older runtime, check the pulse signature against `BeaconConfig`.", + "docs_url": "/docs/errors/chain/UnverifiedPulse" }, "ValueNotInBounds": { "code": "invalid_argument", - "description": "An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds." + "description": "An admin-utils argument fell outside its allowed range: `min_burn` must be below `MinBurnUpperBound` and the subnet's max burn, `max_burn` above `MaxBurnLowerBound` and the min burn, and `max_epochs_per_block` at least 1. Check the argument against those bounds.", + "docs_url": "/docs/errors/chain/ValueNotInBounds" }, "ValueTooLarge": { "code": "limit_exceeded", - "description": "A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant." + "description": "A value written to contract storage or emitted as event data exceeds the `MaxValueSize` limit. Compare the size of the stored value or event payload against the runtime's maximum value size constant.", + "docs_url": "/docs/errors/chain/ValueTooLarge" }, "VestingBalance": { "code": "insufficient_balance", - "description": "The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs." + "description": "The account's balance is locked under a vesting schedule, leaving too little usable balance to send the requested value. Check the account's `Vesting` schedules and its lock in `Locks`, and compare the unvested (still locked) amount against what the transfer needs.", + "docs_url": "/docs/errors/chain/VestingBalance" }, "VotingPowerTrackingNotEnabled": { "code": "disabled", - "description": "Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic." + "description": "Disabling voting power tracking was requested on a subnet where tracking is not currently active. Check the `VotingPowerTrackingEnabled` storage flag for the netuid before calling the disable extrinsic.", + "docs_url": "/docs/errors/chain/VotingPowerTrackingNotEnabled" }, "WaitingForDissolvedSubnetCleanup": { "code": "too_early", - "description": "The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes." + "description": "The operation is blocked while a dissolved subnet's storage is still being torn down in the background. Check the `DissolveCleanupQueue` and retry after the on-idle cleanup for that netuid completes.", + "docs_url": "/docs/errors/chain/WaitingForDissolvedSubnetCleanup" }, "WeightExceedsAbsoluteMax": { "code": "limit_exceeded", - "description": "`set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant." + "description": "`set_on_initialize_weight` or `set_max_extrinsic_weight` was given a value above the shield pallet's hard cap of half the total block weight. Compare the `value` argument against the `MAX_ON_INITIALIZE_WEIGHT` constant.", + "docs_url": "/docs/errors/chain/WeightExceedsAbsoluteMax" }, "WeightVecLengthIsLow": { "code": "invalid_argument", - "description": "The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid." + "description": "The weight submission has fewer entries than the subnet's minimum (setting only a self-weight is the one exception). Compare the vector length against the `MinAllowedWeights` (min_allowed_weights hyperparameter) for the netuid.", + "docs_url": "/docs/errors/chain/WeightVecLengthIsLow" }, "WeightVecNotEqualSize": { "code": "invalid_argument", - "description": "The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID." + "description": "The `uids` and `values` vectors passed to a weight-setting call have different lengths, so they cannot be paired. Check the call arguments; both vectors must have exactly one value per UID.", + "docs_url": "/docs/errors/chain/WeightVecNotEqualSize" }, "WithdrawFailed": { "code": "insufficient_balance", - "description": "Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance." + "description": "Withdrawing the transaction fee from the sender's mapped account failed even though the balance check passed, e.g. due to locks, holds, or existential deposit constraints. Check the account's locks and its free versus withdrawable balance.", + "docs_url": "/docs/errors/chain/WithdrawFailed" }, "WrongTimepoint": { "code": "invalid_argument", - "description": "The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint." + "description": "The timepoint supplied does not match the one recorded when this multisig operation was opened. Read the correct `when` height and index from the `Multisigs` entry for the call hash and resubmit with that exact timepoint.", + "docs_url": "/docs/errors/chain/WrongTimepoint" }, "XCMDecodeFailed": { "code": "invalid_argument", - "description": "The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports." + "description": "The bytes the contract passed to `xcm_execute` or `xcm_send` could not be decoded as a versioned XCM message. Check the XCM encoding and version the contract produces against what the runtime supports.", + "docs_url": "/docs/errors/chain/XCMDecodeFailed" }, "ZeroBalanceAfterWithdrawn": { "code": "insufficient_balance", - "description": "Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn." + "description": "Withdrawing TAO from the coldkey (e.g. paying a registration burn or adding stake) would leave the account at zero, below what keeps it alive. Check the coldkey's free balance and leave at least the existential deposit after the amount withdrawn.", + "docs_url": "/docs/errors/chain/ZeroBalanceAfterWithdrawn" }, "ZeroShareInBatch": { "code": "invalid_argument", - "description": "An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch." + "description": "An order's pro-rata share of the batch output floored to zero, so the whole batch was rejected rather than consuming that order's input for no payout. Check the order's `amount` relative to the batch totals and retry it in a differently composed batch.", + "docs_url": "/docs/errors/chain/ZeroShareInBatch" } } } diff --git a/website/apps/bittensor-website/public/catalog/intents.json b/website/apps/bittensor-website/public/catalog/intents.json index d63ece39c6..2e4518a3f7 100644 --- a/website/apps/bittensor-website/public/catalog/intents.json +++ b/website/apps/bittensor-website/public/catalog/intents.json @@ -1582,7 +1582,7 @@ }, "name": { "type": "string", - "description": "Hyperparameter to set. One of: activity_cutoff, adjustment_alpha, alpha_high, alpha_low, alpha_sigmoid_steepness, bonds_moving_avg, bonds_penalty, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, max_burn, max_difficulty, min_allowed_weights, min_burn, min_childkey_take, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, owner_immune_neuron_limit, rho, serving_rate_limit, transfers_enabled, weights_version, yuma3_enabled." + "description": "Hyperparameter to set. One of: activity_cutoff_factor, adjustment_alpha, alpha_high, alpha_low, alpha_sigmoid_steepness, bonds_moving_avg, bonds_penalty, bonds_reset_enabled, burn_half_life, burn_increase_mult, commit_reveal_period, commit_reveal_weights_enabled, immunity_period, liquid_alpha_enabled, max_allowed_uids, max_burn, max_difficulty, min_allowed_weights, min_burn, min_childkey_take, network_pow_registration_allowed, owner_cut_auto_lock_enabled, owner_cut_enabled, owner_immune_neuron_limit, rho, serving_rate_limit, tempo, transfers_enabled, weights_version, yuma3_enabled." }, "value": { "type": [ diff --git a/website/apps/bittensor-website/public/catalog/reads.json b/website/apps/bittensor-website/public/catalog/reads.json index 8ef0b2220a..5b17b3b9a0 100644 --- a/website/apps/bittensor-website/public/catalog/reads.json +++ b/website/apps/bittensor-website/public/catalog/reads.json @@ -592,7 +592,7 @@ { "name": "metagraph", "summary": "The full metagraph for a subnet in one call (stakes, ranks, emissions, axons, ...).", - "description": "The full metagraph for a subnet in one call (stakes, ranks, emissions, axons, ...).", + "description": "The full metagraph for a subnet in one call (stakes, ranks, emissions, axons, ...).\n\n`name` and `symbol` are decoded to text (the wire carries them as\ncompact-u16 vectors of utf-8 bytes, unlike every other text field).", "params": { "netuid": "integer" }, @@ -954,8 +954,8 @@ }, { "name": "subnet_hyperparameters", - "summary": "All hyperparameters for a subnet (named fields; version-dependent set).", - "description": "All hyperparameters for a subnet (named fields; version-dependent set).", + "summary": "All hyperparameters for a subnet, as a flat name -> raw value mapping.", + "description": "All hyperparameters for a subnet, as a flat name -> raw value mapping.\n\nThe set of names is version-dependent; None if the subnet does not exist.\nUses the forward-compatible `get_subnet_hyperparams_v3` runtime API, so\nnewly added chain hyperparameters (e.g. `burn_half_life`) show up\nwithout a client update.", "params": { "netuid": "integer" }, diff --git a/website/apps/bittensor-website/scripts/generate.py b/website/apps/bittensor-website/scripts/generate.py index d7552e7415..94d5f7d193 100644 --- a/website/apps/bittensor-website/scripts/generate.py +++ b/website/apps/bittensor-website/scripts/generate.py @@ -1,6 +1,6 @@ """Generate the docs reference section from the SDK's own registries. -Everything under docs/tx, docs/query, docs/errors.mdx, and the hyperparameters +Everything under docs/tx, docs/query, docs/errors, and the hyperparameters index/meta (in the repo-root docs folder) plus public/catalog/ is emitted by this script — never hand-edited (the per-hyperparameter explainer pages in docs/hyperparameters/ are hand-written; --check verifies one exists per @@ -28,6 +28,7 @@ from pathlib import Path from bittensor import error_descriptions, error_map, hyperparams, result +from bittensor._generated.errors import ERRORS as CHAIN_ERROR_CATALOG from bittensor.intents import REGISTRY as INTENTS from bittensor.intents.hyperparameters import OWNER_HYPERPARAMETERS from bittensor.intents.registry import list_tools @@ -432,7 +433,7 @@ def query_meta() -> dict: return {"title": "Queries", "pages": pages} -# --- Errors page ----------------------------------------------------------- +# --- Error pages ----------------------------------------------------------- def sentence_case(text: str) -> str: @@ -449,7 +450,66 @@ def sentence_case(text: str) -> str: return "\n\n".join(paragraphs) -def errors_page() -> str: +def chain_errors_for(code) -> list[str]: + """Chain error names classifying to a code, sorted.""" + return sorted(n for n, c in error_map.NAME_TO_CODE.items() if c is code) + + +# Chain error name -> the pallets that declare it (a name can exist in several). +CHAIN_ERROR_PALLETS: dict[str, list[str]] = {} +for _info in CHAIN_ERROR_CATALOG.values(): + _pallets = CHAIN_ERROR_PALLETS.setdefault(_info.name, []) + if _info.pallet not in _pallets: + _pallets.append(_info.pallet) + + +def chain_error_remediation(name: str) -> str: + """The remediation the CLI would print for this exact chain error (includes + the per-name overrides, e.g. SlippageTooHigh's tolerance flags).""" + return result.ChainError("", name=name).remediation + + +def error_page(code) -> str: + """One explainer page per semantic error code (the hyperparameters layout: + an index table linking to a page per entry). The page carries the long-form + explanation (`btcli explain `), the remediation hint, and the chain + errors that classify to this code.""" + remediation = sentence_case(result.REMEDIATION[code]) + explanation = sentence_case(result.EXPLANATIONS[code]) + header = frontmatter(code.value, remediation) + parts = [header, mdx_escape(explanation) + "\n"] + + parts.append("## Remediation\n") + parts.append(mdx_escape(remediation) + "\n") + + names = chain_errors_for(code) + parts.append("## Chain errors\n") + if names: + parts.append( + f"The exact chain error names (from the extrinsic receipt) that " + f"classify to `{code.value}`; the description says what triggered " + "the failure and where to check. Each name has its own page:\n" + ) + parts.append("| Chain error | Description |") + parts.append("| --- | --- |") + for name in names: + description = error_descriptions.DESCRIPTIONS[name] + parts.append(f"| [`{name}`](/docs/errors/chain/{name}) | {cell(description)} |") + parts.append("") + else: + parts.append( + "No chain error classifies to this code — it is raised client-side " + "by the SDK before or after the call reaches the chain.\n" + ) + parts.append( + "The same explanation is available in the terminal: " + f"`btcli explain {code.value}` (or `btcli explain ` " + "for one exact chain error).\n" + ) + return "\n".join(parts) + + +def errors_index() -> str: header = frontmatter( "Errors", "Every failure carries a machine-readable code and a remediation hint.", @@ -459,29 +519,97 @@ def errors_page() -> str: "A failed `execute` returns an `ExtrinsicResult` whose `error` has a " "semantic `code` (branch on it) and a `remediation` hint (what to try " "next). Every chain error name is deliberately classified — a CI gate " - "keeps the mapping complete in both directions. The machine-readable " - "version is at [`/catalog/errors.json`](/catalog/errors.json).\n", - "## Error codes\n", + "keeps the mapping complete in both directions. Each code has its own " + "explainer page listing the chain errors that map to it, and every " + "exact chain error name has its own page under " + "[chain errors](/docs/errors/chain). The machine-readable version is " + "at [`/catalog/errors.json`](/catalog/errors.json).\n", + "| Code | Chain errors | Remediation |", + "| --- | --- | --- |", ] for code in error_map.ErrorCode: remediation = sentence_case(result.REMEDIATION[code]) - parts.append(f"### `{code.value}`\n") - parts.append(mdx_escape(remediation) + "\n") + count = len(chain_errors_for(code)) + parts.append( + f"| [`{code.value}`](/docs/errors/{kebab(code.value)}) | " + f"{count if count else '—'} | {cell(remediation)} |" + ) + parts.append("") + return "\n".join(parts) + - parts.append("## Chain error classification\n") +def errors_meta() -> dict: + return { + "title": "Errors", + "pages": [ + "index", + *(kebab(code.value) for code in error_map.ErrorCode), + "chain", + ], + } + + +def chain_error_page(name: str, code) -> str: + """One page per exact chain error name, at /docs/errors/chain/ (the + URL keeps the on-chain CamelCase name so CLI links never need mangling).""" + description = sentence_case(error_descriptions.DESCRIPTIONS[name]) + remediation = sentence_case(chain_error_remediation(name)) + pallets = CHAIN_ERROR_PALLETS.get(name, []) + header = frontmatter(name, remediation) + parts = [header, mdx_escape(description) + "\n"] + + pallet_list = ", ".join(f"`{p}`" for p in pallets) + origin = ( + f"Declared by the {pallet_list} pallet{'s' if len(pallets) > 1 else ''}; it" + if pallets + else "It" + ) parts.append( - "The exact chain error name (from the extrinsic receipt) maps to a code; " - "the description says what triggered it and where to check:\n" + f"{origin} classifies to the semantic code " + f"[`{code.value}`](/docs/errors/{kebab(code.value)}).\n" + ) + + parts.append("## Remediation\n") + parts.append(mdx_escape(remediation) + "\n") + + parts.append( + "The same explanation is available in the terminal: " + f"`btcli explain {name}`.\n" + ) + return "\n".join(parts) + + +def chain_errors_index() -> str: + header = frontmatter( + "Chain errors", + "Every exact chain error name, classified to a semantic code.", ) - parts.append("| Chain error | Code | Description |") - parts.append("| --- | --- | --- |") + parts = [ + header, + "The exact chain error name (from the extrinsic receipt) maps to a " + "semantic [code](/docs/errors); the description says what triggered " + "the failure and where to check. Each name has its own page:\n", + "| Chain error | Code | Description |", + "| --- | --- | --- |", + ] for name, code in sorted(error_map.NAME_TO_CODE.items()): description = error_descriptions.DESCRIPTIONS[name] - parts.append(f"| `{name}` | `{code.value}` | {cell(description)} |") + parts.append( + f"| [`{name}`](/docs/errors/chain/{name}) | " + f"[`{code.value}`](/docs/errors/{kebab(code.value)}) | " + f"{cell(description)} |" + ) parts.append("") return "\n".join(parts) +def chain_errors_meta() -> dict: + return { + "title": "Chain errors", + "pages": ["index", *sorted(error_map.NAME_TO_CODE)], + } + + # --- Hyperparameters page --------------------------------------------------- # Unit kind -> the label the docs table shows for it. @@ -563,9 +691,19 @@ def write_catalogs(catalog_root: Path) -> None: if not namespace_shadowed(spec): r["python"] = f"client.{namespace_attr(spec)}.{spec.name}(...)" errors = { - "codes": {code.value: result.REMEDIATION[code] for code in error_map.ErrorCode}, + "codes": { + code.value: { + "remediation": result.REMEDIATION[code], + "docs_url": f"/docs/errors/{kebab(code.value)}", + } + for code in error_map.ErrorCode + }, "chain_errors": { - n: {"code": c.value, "description": error_descriptions.DESCRIPTIONS[n]} + n: { + "code": c.value, + "description": error_descriptions.DESCRIPTIONS[n], + "docs_url": f"/docs/errors/chain/{n}", + } for n, c in sorted(error_map.NAME_TO_CODE.items()) }, } @@ -584,8 +722,10 @@ def generate(content_root: Path) -> None: with tempfile.TemporaryDirectory(dir=content_root) as tmp: tx_dir = Path(tmp) / "tx" query_dir = Path(tmp) / "query" + errors_dir = Path(tmp) / "errors" tx_dir.mkdir() query_dir.mkdir() + errors_dir.mkdir() for op, cls in sorted(INTENTS.items()): (tx_dir / f"{kebab(op)}.mdx").write_text(intent_page(op, cls)) @@ -597,13 +737,29 @@ def generate(content_root: Path) -> None: (query_dir / "index.mdx").write_text(read_index()) (query_dir / "meta.json").write_text(json.dumps(query_meta(), indent=2) + "\n") - errors = errors_page() - - for src, dest in ((tx_dir, content_root / "tx"), (query_dir, content_root / "query")): + for code in error_map.ErrorCode: + (errors_dir / f"{kebab(code.value)}.mdx").write_text(error_page(code)) + (errors_dir / "index.mdx").write_text(errors_index()) + (errors_dir / "meta.json").write_text(json.dumps(errors_meta(), indent=2) + "\n") + + chain_dir = errors_dir / "chain" + chain_dir.mkdir() + for name, code in sorted(error_map.NAME_TO_CODE.items()): + (chain_dir / f"{name}.mdx").write_text(chain_error_page(name, code)) + (chain_dir / "index.mdx").write_text(chain_errors_index()) + (chain_dir / "meta.json").write_text(json.dumps(chain_errors_meta(), indent=2) + "\n") + + for src, dest in ( + (tx_dir, content_root / "tx"), + (query_dir, content_root / "query"), + (errors_dir, content_root / "errors"), + ): if dest.exists(): shutil.rmtree(dest) src.rename(dest) - (content_root / "errors.mdx").write_text(errors) + # The errors section used to be a single generated errors.mdx page; + # drop the leftover so it does not shadow the errors/ folder. + (content_root / "errors.mdx").unlink(missing_ok=True) # Only the index and meta are generated: the per-parameter explainer # pages in this folder are hand-written and left untouched. hyperparams_dir = content_root / "hyperparameters" @@ -635,13 +791,16 @@ def check() -> int: if not committed.exists() or not filecmp.cmp(fresh, committed, shallow=False): stale.append(str(committed)) # Files that were generated once but no longer are (e.g. a removed intent). - for sub in ("tx", "query"): + for sub in ("tx", "query", "errors"): committed_dir = CONTENT / sub if not committed_dir.exists(): continue for committed in sorted(committed_dir.rglob("*")): if committed.is_file() and not (tmp_content / committed.relative_to(CONTENT)).exists(): stale.append(str(committed)) + # The pre-folder single errors page must not linger beside errors/. + if (CONTENT / "errors.mdx").exists(): + stale.append(str(CONTENT / "errors.mdx")) # Every hyperparameter must have its hand-written explainer page. for name in hyperparams.HYPERPARAMS: page = CONTENT / "hyperparameters" / f"{kebab(name)}.mdx" @@ -665,9 +824,11 @@ def main() -> int: generate(CONTENT) write_catalogs(CATALOG) n_tx, n_q = len(INTENTS), len(READS) + n_err = len(list(error_map.ErrorCode)) + n_chain = len(error_map.NAME_TO_CODE) print( - f"Generated {n_tx} tx pages, {n_q} query pages, errors.mdx, " - "the hyperparameters index, and 3 catalogs." + f"Generated {n_tx} tx pages, {n_q} query pages, {n_err} error pages, " + f"{n_chain} chain error pages, the hyperparameters index, and 3 catalogs." ) return 0 diff --git a/website/apps/bittensor-website/src/app/(pages-without-footer)/releases/v431-upgrade/page.tsx b/website/apps/bittensor-website/src/app/(pages-without-footer)/releases/v431-upgrade/page.tsx index da928da631..41205a9c6e 100644 --- a/website/apps/bittensor-website/src/app/(pages-without-footer)/releases/v431-upgrade/page.tsx +++ b/website/apps/bittensor-website/src/app/(pages-without-footer)/releases/v431-upgrade/page.tsx @@ -553,8 +553,9 @@ btcli tx transfer --dest 5F...dest --amount-tao 1 --signer extension`} every existing proxy configuration.
  • - Node operators — nodes not yet running the spec 431 binary must - upgrade to continue syncing. + Node operators — no binary upgrade is required to continue + syncing. Nodes execute the upgraded on-chain Wasm runtime automatically; install + the latest node image when it is published to receive node-software updates.
  • Indexers and SDK authors — chain metadata now carries typed diff --git a/website/apps/bittensor-website/src/app/(pages-without-footer)/wallet/WalletPage.tsx b/website/apps/bittensor-website/src/app/(pages-without-footer)/wallet/WalletPage.tsx index 63bbc76a7e..d677adf715 100644 --- a/website/apps/bittensor-website/src/app/(pages-without-footer)/wallet/WalletPage.tsx +++ b/website/apps/bittensor-website/src/app/(pages-without-footer)/wallet/WalletPage.tsx @@ -182,8 +182,9 @@ function WalletCard({card}: {card: WalletCardConfig}) { ) : ( @@ -195,6 +196,13 @@ function WalletCard({card}: {card: WalletCardConfig}) { } const walletsSectionCards: WalletCardConfig[] = [ + { + title: 'Bittensor CLI', + primaryHref: '/docs/quickstart#1-install', + primaryAriaLabel: 'Bittensor CLI — open install docs', + description: 'Command-line interface for managing wallets, staking, and on-chain interactions', + platforms: [{kind: 'cli'}], + }, { title: 'Crucible Wallet', primaryHref: 'https://cruciblelabs.com/', @@ -253,13 +261,6 @@ const walletsSectionCards: WalletCardConfig[] = [ ), platforms: [{kind: 'chrome'}, {kind: 'external'}], }, - { - title: 'Bittensor CLI', - primaryHref: 'https://github.com/RaoFoundation/btcli', - primaryAriaLabel: 'Bittensor CLI — open GitHub repository', - description: 'Command-line interface for managing wallets, staking, and on-chain interactions', - platforms: [{kind: 'cli'}], - }, ]; const coldStorageSectionCards: WalletCardConfig[] = [ diff --git a/website/apps/bittensor-website/src/app/docs/docs.tw.css b/website/apps/bittensor-website/src/app/docs/docs.tw.css index 386a1bdb15..1a643d368b 100644 --- a/website/apps/bittensor-website/src/app/docs/docs.tw.css +++ b/website/apps/bittensor-website/src/app/docs/docs.tw.css @@ -286,6 +286,36 @@ border-bottom: none; } +/* --------------------------------------------------------------------------- + Math (KaTeX) — sized to sit inside the prose rather than on top of it. + Two classes (.bt-docs .katex) so this beats the marketing pages' global + `.katex { font-size: 2em }` without touching them. KaTeX's own math-italic + faces are kept: forcing mono breaks fraction/superscript metrics. +--------------------------------------------------------------------------- */ + +.bt-docs .katex { + /* KaTeX defaults to 1.21em; match the prose x-height instead. */ + font-size: 1em; + color: var(--bt-fg); +} + +/* Display math: restrained and left-aligned like the site's other blocks + (code, blockquotes), with an indent echoing the blockquote inset. */ +.bt-docs .katex-display { + margin-block: 1.5rem; + text-align: start; + padding-inline-start: 1.25em; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: thin; + scrollbar-color: var(--bt-line) transparent; +} + +.bt-docs .katex-display > .katex { + text-align: start; + font-size: 1.0625em; +} + /* --------------------------------------------------------------------------- Code blocks — shiki output (bt-light theme). --------------------------------------------------------------------------- */ diff --git a/website/apps/bittensor-website/src/components/docs/chart-theme.ts b/website/apps/bittensor-website/src/components/docs/chart-theme.ts new file mode 100644 index 0000000000..2f1d8e60f7 --- /dev/null +++ b/website/apps/bittensor-website/src/components/docs/chart-theme.ts @@ -0,0 +1,45 @@ +/** + * Shared chart theme for the docs explainer figures. + * + * Design rules (the "research-paper figure" language): + * - Monochrome ink on white. INK for primary series/text, INK_FAINT for + * secondary series, axis ticks, and axis titles. + * - Red (ACCENT) is reserved for thresholds, warnings, and highlight points + * only — never for a regular data series. Tint warning regions with + * ACCENT_REGION; wash accented stat values with ACCENT_WASH. + * - No Chart.js legends. Label series directly in-plot with uppercase + * FiraCode annotations (GRAPH_FONT) drawn via a Chart.js plugin. + * - Keep axes quiet: grid GRID, border AXIS_BORDER, ticks via baseTicks() + * with maxTicksLimit 5–6, axis titles via axisTitle(). + */ + +export const INK = 'rgb(41, 41, 41)'; +export const INK_FAINT = 'rgba(41, 41, 41, 0.45)'; +export const GRID = 'rgba(41, 41, 41, 0.05)'; +export const AXIS_BORDER = 'rgba(41, 41, 41, 0.25)'; +export const ACCENT = '#d15168'; +export const ACCENT_REGION = 'rgba(209, 81, 104, 0.05)'; +export const ACCENT_WASH = 'rgba(209, 81, 104, 0.08)'; + +/** Canvas ctx.font string for in-plot annotations drawn by plugins. */ +export const GRAPH_FONT = '10px FiraCode, monospace'; + +/** Base tick styling for any scale; spread first, then override. */ +export function baseTicks(overrides?: Record) { + return { + maxTicksLimit: 6, + font: { family: 'FiraCode, monospace', size: 10 }, + color: INK_FAINT, + ...overrides, + }; +} + +/** Muted 10px axis title. */ +export function axisTitle(text: string) { + return { + display: true, + text, + font: { size: 10 }, + color: INK_FAINT, + }; +} diff --git a/website/apps/bittensor-website/src/components/docs/conviction-lock-chart.tsx b/website/apps/bittensor-website/src/components/docs/conviction-lock-chart.tsx index f434809e61..c67ae758cb 100644 --- a/website/apps/bittensor-website/src/components/docs/conviction-lock-chart.tsx +++ b/website/apps/bittensor-website/src/components/docs/conviction-lock-chart.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useMemo, useState } from 'react'; +import { useMemo, useRef, useState } from 'react'; import { Chart as ChartJS, CategoryScale, @@ -9,10 +9,20 @@ import { LineElement, Tooltip, Legend, + type Plugin, } from 'chart.js'; import { Line } from 'react-chartjs-2'; import { ExplainerPanel, ExplainerSlider, ExplainerStat } from './explainer-panel'; import { MATURITY_RATE_BLOCKS, formatBlocks, formatPct, perpetualConviction } from '@/lib/emission-math'; +import { + AXIS_BORDER, + GRAPH_FONT, + GRID, + INK, + INK_FAINT, + axisTitle, + baseTicks, +} from './chart-theme'; ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend); @@ -29,13 +39,54 @@ export function ConvictionLockChart() { }); }, [lockedMass, startConviction, horizon]); + // The plugin is registered once at chart creation, so it reads live values + // through a ref instead of closing over state that would go stale. + const drawState = useRef({ lockedMass, startConviction, horizon }); + drawState.current = { lockedMass, startConviction, horizon }; + + // Direct in-plot labels instead of a legend: uppercase FiraCode annotations + // beside the conviction curve and the locked-mass reference line. + const annotationPlugin = useMemo>( + () => ({ + id: 'convictionLockAnnotations', + afterDatasetsDraw(chart) { + const { lockedMass, startConviction, horizon } = drawState.current; + const { ctx, chartArea, scales } = chart; + const xScale = scales.x; + const yScale = scales.y; + if (!xScale || !yScale) return; + + ctx.save(); + ctx.font = GRAPH_FONT; + ctx.textAlign = 'left'; + + // Locked-mass line label, tucked above the dashed line at the left. + const yMass = yScale.getPixelForValue(lockedMass); + ctx.fillStyle = INK_FAINT; + ctx.fillText('LOCKED MASS (M)', chartArea.left + 6, yMass - 6); + + // Conviction curve label, below the curve where it has risen away + // from the mass line's label zone. + const xLabel = horizon * 0.45; + const yCurve = yScale.getPixelForValue( + perpetualConviction(lockedMass, startConviction, xLabel), + ); + ctx.fillStyle = INK; + ctx.fillText('CONVICTION', xScale.getPixelForValue(xLabel) + 4, yCurve + 16); + + ctx.restore(); + }, + }), + [], + ); + const data = useMemo( () => ({ datasets: [ { label: 'Conviction', data: points.map((p) => ({x: p.x, y: p.y})), - borderColor: 'rgb(41, 41, 41)', + borderColor: INK, borderWidth: 1.5, pointRadius: 0, tension: 0.2, @@ -43,7 +94,7 @@ export function ConvictionLockChart() { { label: 'Locked mass', data: points.map((p) => ({x: p.x, y: lockedMass})), - borderColor: 'rgba(110, 110, 110, 0.6)', + borderColor: 'rgba(41, 41, 41, 0.5)', borderDash: [4, 4], borderWidth: 1, pointRadius: 0, @@ -61,16 +112,18 @@ export function ConvictionLockChart() { scales: { x: { type: 'linear' as const, - title: {display: true, text: 'Blocks since lock', font: {size: 11}}, - ticks: { + grid: {color: GRID}, + border: {color: AXIS_BORDER}, + ticks: baseTicks({ callback: (v: number | string) => formatBlocks(Number(v)), - maxTicksLimit: 6, - font: {size: 10}, - }, + }), + title: axisTitle('blocks since lock'), }, y: { - title: {display: true, text: 'α', font: {size: 11}}, - grid: {color: 'rgba(41, 41, 41, 0.06)'}, + grid: {color: GRID}, + border: {color: AXIS_BORDER}, + ticks: baseTicks({maxTicksLimit: 5}), + title: axisTitle('conviction (α)'), }, }, }), @@ -86,16 +139,16 @@ export function ConvictionLockChart() { caption="c₁ = m − (m − c₀)·e^(−Δt/τ). Locked mass stays fixed; conviction approaches mass asymptotically (~63% at 1τ)." >
    - +
    -
    +
    -
    +
    >( + () => ({ + id: 'modeComparisonAnnotations', + afterDatasetsDraw(chart) { + const { lockedMass, horizon } = drawState.current; + const { ctx, scales } = chart; + const xScale = scales.x; + const yScale = scales.y; + if (!xScale || !yScale) return; + + ctx.save(); + ctx.font = GRAPH_FONT; + ctx.textAlign = 'left'; + + // Perpetual conviction rises toward mass; label above the curve. + const xMain = horizon * 0.55; + const perpetualY = rollForwardLock(lockedMass, 0, xMain, {perpetual: true}).conviction; + ctx.fillStyle = INK; + ctx.fillText('PERPETUAL', xScale.getPixelForValue(xMain) + 4, yScale.getPixelForValue(perpetualY) - 8); + + // Decaying conviction peaks then falls; label below the curve. + const decayingY = rollForwardLock(lockedMass, 0, xMain, {perpetual: false}).conviction; + ctx.fillStyle = INK_FAINT; + ctx.fillText('DECAYING', xScale.getPixelForValue(xMain) + 4, yScale.getPixelForValue(decayingY) + 16); + + // Freed locked mass of the decaying lock, labelled at the left where + // its steep descent is clear of the two conviction curves. + const xMass = horizon * 0.12; + const massY = rollForwardLock(lockedMass, 0, xMass, {perpetual: false}).lockedMass; + ctx.fillText('DECAYING MASS', xScale.getPixelForValue(xMass) + 6, yScale.getPixelForValue(massY) - 8); + + ctx.restore(); + }, + }), + [], + ); + const data = useMemo( () => ({ - labels: chart.labels.map((b) => String(Math.round(b))), datasets: [ { label: 'Perpetual — conviction', - data: chart.perpetual.map((p) => p.conviction), - borderColor: 'rgb(41, 41, 41)', + data: chart.labels.map((dt, i) => ({x: dt, y: chart.perpetual[i].conviction})), + borderColor: INK, borderWidth: 1.5, pointRadius: 0, tension: 0.25, }, { label: 'Decaying — conviction', - data: chart.decaying.map((p) => p.conviction), + data: chart.labels.map((dt, i) => ({x: dt, y: chart.decaying[i].conviction})), borderColor: 'rgba(41, 41, 41, 0.5)', borderWidth: 1.5, borderDash: [5, 3], @@ -57,8 +110,8 @@ export function ConvictionModeComparison() { }, { label: 'Decaying — locked mass', - data: chart.decaying.map((p) => p.lockedMass), - borderColor: 'rgba(110, 110, 110, 0.45)', + data: chart.labels.map((dt, i) => ({x: dt, y: chart.decaying[i].lockedMass})), + borderColor: INK_FAINT, borderWidth: 1, pointRadius: 0, tension: 0.25, @@ -73,16 +126,34 @@ export function ConvictionModeComparison() { responsive: true, maintainAspectRatio: false, plugins: { - legend: { - position: 'bottom' as const, - labels: {boxWidth: 10, font: {size: 10}}, + legend: {display: false}, + tooltip: { + callbacks: { + title: (items: {parsed: {x: number}}[]) => + `+${formatBlocks(items[0]?.parsed.x ?? 0)}`, + label: (ctx: {dataset: {label?: string}; parsed: {y: number}}) => + `${ctx.dataset.label}: ${formatAlpha(ctx.parsed.y)}`, + }, }, }, scales: { - x: {ticks: {maxTicksLimit: 6, font: {size: 10}}}, + x: { + type: 'linear' as const, + grid: {color: GRID}, + border: {color: AXIS_BORDER}, + ticks: baseTicks({ + callback: (v: number | string) => formatBlocks(Number(v)), + }), + title: axisTitle('blocks since lock'), + }, y: { - grid: {color: 'rgba(41, 41, 41, 0.06)'}, - ticks: {callback: (v: number | string) => formatAlpha(Number(v)), font: {size: 10}}, + grid: {color: GRID}, + border: {color: AXIS_BORDER}, + ticks: baseTicks({ + maxTicksLimit: 5, + callback: (v: number | string) => formatAlpha(Number(v)), + }), + title: axisTitle('conviction (α)'), }, }, }), @@ -101,10 +172,10 @@ export function ConvictionModeComparison() { caption="Same 500k α lock on a subnet hotkey. Perpetual: mass stays, conviction approaches mass. Decaying: mass frees on UnlockRate; conviction peaks then falls." >
    - +
    -
    +
    -
    +
    = threshold; + if (above && start === null) { + if (i === 0) { + start = labels[0]; + } else { + const t = (threshold - total[i - 1]) / (total[i] - total[i - 1]); + start = labels[i - 1] + t * (labels[i] - labels[i - 1]); + } + } else if (!above && start !== null) { + const t = (threshold - total[i - 1]) / (total[i] - total[i - 1]); + segments.push({from: start, to: labels[i - 1] + t * (labels[i] - labels[i - 1])}); + start = null; + } + } + if (start !== null) segments.push({from: start, to: labels[labels.length - 1]}); + return segments; +} + export function ConvictionSubnetScenario() { const [elapsed, setElapsed] = useState(400_000); const [bobLock, setBobLock] = useState(EXAMPLE_SUBNET.validator.lockedMass); @@ -74,8 +113,12 @@ export function ConvictionSubnetScenario() { const bob = seriesForLocker(bobLock, true, false, horizon, steps); const carol = seriesForLocker(carolLock, carolPerpetual, false, horizon, steps); const total = labels.map((_, i) => alice[i] + bob[i] + carol[i]); - return {labels, alice, bob, carol, total}; - }, [bobLock, carolLock, carolPerpetual, horizon]); + const segments = aboveThresholdSegments(labels, total, threshold); + // The red dot marks where total conviction first crosses the gate + // (the subnet is already past one year of age in this scenario). + const crossing = segments.length > 0 ? segments[0].from : null; + return {labels, alice, bob, carol, total, segments, crossing}; + }, [bobLock, carolLock, carolPerpetual, horizon, threshold]); const now = useMemo(() => { const alice = rollForwardLock(EXAMPLE_SUBNET.owner.lockedMass, 0, elapsed, { @@ -98,21 +141,115 @@ export function ConvictionSubnetScenario() { const ownershipReady = EXAMPLE_SUBNET.ageBlocks >= ONE_YEAR_BLOCKS && now.total >= threshold; + // The plugin is registered once at chart creation, so it reads live values + // through a ref instead of closing over state that would go stale. + const drawState = useRef({ + segments: chart.segments, + threshold, + horizon, + bobLock, + carolLock, + carolPerpetual, + }); + drawState.current = { + segments: chart.segments, + threshold, + horizon, + bobLock, + carolLock, + carolPerpetual, + }; + + // Region tint where the ownership gate holds, plus direct in-plot labels — + // the treatment of the v431 release conviction graph. + const annotationPlugin = useMemo>( + () => ({ + id: 'subnetScenarioAnnotations', + beforeDatasetsDraw(chart) { + const { segments } = drawState.current; + const { ctx, chartArea, scales } = chart; + const xScale = scales.x; + if (!xScale) return; + + ctx.save(); + ctx.font = GRAPH_FONT; + + for (const segment of segments) { + const left = xScale.getPixelForValue(segment.from); + const right = xScale.getPixelForValue(segment.to); + ctx.fillStyle = ACCENT_REGION; + ctx.fillRect(left, chartArea.top, right - left, chartArea.height); + if (right - left > 90) { + ctx.fillStyle = ACCENT; + ctx.textAlign = 'center'; + // Keep the two-line label inside the plot when the region is + // clipped by the right edge. + const cx = Math.min((left + right) / 2, chartArea.right - 44); + ctx.fillText('OWNERSHIP', cx, chartArea.top + 14); + ctx.fillText('CONTESTABLE', cx, chartArea.top + 28); + } + } + + ctx.restore(); + }, + afterDatasetsDraw(chart) { + const { threshold, horizon, bobLock, carolLock, carolPerpetual } = drawState.current; + const { ctx, chartArea, scales } = chart; + const xScale = scales.x; + const yScale = scales.y; + if (!xScale || !yScale) return; + + ctx.save(); + ctx.font = GRAPH_FONT; + ctx.textAlign = 'left'; + + // Threshold label on the dashed gate line. + ctx.fillStyle = ACCENT; + ctx.fillText('10% THRESHOLD', chartArea.left + 6, yScale.getPixelForValue(threshold) - 6); + + // Direct series labels instead of a legend. + const totalAt = (dt: number) => + rollForwardLock(EXAMPLE_SUBNET.owner.lockedMass, 0, dt, {perpetual: true, ownerLock: true}).conviction + + rollForwardLock(bobLock, 0, dt, {perpetual: true}).conviction + + rollForwardLock(carolLock, 0, dt, {perpetual: carolPerpetual}).conviction; + + // Below the curve: the total rises left-to-right, so the gap under + // the label's anchor point only grows along the text. + const xMain = horizon * 0.35; + ctx.fillStyle = INK; + ctx.fillText( + 'TOTAL CONVICTION', + xScale.getPixelForValue(xMain) + 4, + yScale.getPixelForValue(totalAt(xMain)) + 16, + ); + + const xSide = horizon * 0.68; + const bobY = rollForwardLock(bobLock, 0, xSide, {perpetual: true}).conviction; + const carolY = rollForwardLock(carolLock, 0, xSide, {perpetual: carolPerpetual}).conviction; + ctx.fillStyle = INK_FAINT; + ctx.fillText('BOB', xScale.getPixelForValue(xSide) + 4, yScale.getPixelForValue(bobY) - 6); + ctx.fillText('CAROL', xScale.getPixelForValue(xSide) + 4, yScale.getPixelForValue(carolY) - 6); + + ctx.restore(); + }, + }), + [], + ); + const data = useMemo( () => ({ - labels: chart.labels.map((b) => String(Math.round(b))), datasets: [ { label: 'Total conviction', - data: chart.total, - borderColor: 'rgb(41, 41, 41)', + data: chart.labels.map((dt, i) => ({x: dt, y: chart.total[i]})), + borderColor: INK, borderWidth: 2, pointRadius: 0, tension: 0.3, }, { label: 'Bob (validator)', - data: chart.bob, + data: chart.labels.map((dt, i) => ({x: dt, y: chart.bob[i]})), borderColor: 'rgba(41, 41, 41, 0.55)', borderWidth: 1, pointRadius: 0, @@ -120,8 +257,8 @@ export function ConvictionSubnetScenario() { }, { label: 'Carol (staker)', - data: chart.carol, - borderColor: 'rgba(110, 110, 110, 0.7)', + data: chart.labels.map((dt, i) => ({x: dt, y: chart.carol[i]})), + borderColor: INK_FAINT, borderWidth: 1, borderDash: [4, 3], pointRadius: 0, @@ -129,15 +266,28 @@ export function ConvictionSubnetScenario() { }, { label: '10% threshold', - data: chart.labels.map(() => threshold), - borderColor: 'rgba(110, 110, 110, 0.35)', + data: [ + {x: 0, y: threshold}, + {x: horizon, y: threshold}, + ], + borderColor: ACCENT, borderWidth: 1, borderDash: [6, 4], pointRadius: 0, }, + { + label: 'Gate crossed', + // Red dot exactly where total conviction crosses the threshold. + data: chart.crossing === null ? [] : [{x: chart.crossing, y: threshold}], + borderColor: ACCENT, + backgroundColor: ACCENT, + showLine: false, + pointRadius: 4, + pointStyle: 'circle' as const, + }, ], }), - [chart, threshold], + [chart, threshold, horizon], ); const options = useMemo( @@ -146,14 +296,11 @@ export function ConvictionSubnetScenario() { maintainAspectRatio: false, interaction: {mode: 'index' as const, intersect: false}, plugins: { - legend: { - display: true, - position: 'bottom' as const, - labels: {boxWidth: 10, font: {size: 10, family: 'FiraCode, monospace'}}, - }, + legend: {display: false}, tooltip: { callbacks: { - title: (items: {label: string}[]) => `Block +${items[0]?.label ?? ''}`, + title: (items: {parsed: {x: number}}[]) => + `Block +${Math.round(items[0]?.parsed.x ?? 0).toLocaleString('en-US')}`, label: (ctx: {dataset: {label?: string}; parsed: {y: number}}) => `${ctx.dataset.label}: ${formatAlpha(ctx.parsed.y)}`, }, @@ -161,20 +308,32 @@ export function ConvictionSubnetScenario() { }, scales: { x: { - title: {display: true, text: 'Blocks since locks started', font: {size: 11}}, - ticks: {maxTicksLimit: 6, font: {size: 10}}, + type: 'linear' as const, + min: 0, + max: horizon, + grid: {color: GRID}, + border: {color: AXIS_BORDER}, + ticks: baseTicks({ + callback: (v: number | string) => formatBlocks(Number(v)), + }), + title: axisTitle('blocks since locks started'), }, y: { - title: {display: true, text: 'Conviction (α)', font: {size: 11}}, - grid: {color: 'rgba(41, 41, 41, 0.06)'}, - ticks: { + // Headroom above the tallest curve so the in-plot region label + // drawn at the top of the chart stays clear of the series. + min: 0, + grace: '15%' as const, + grid: {color: GRID}, + border: {color: AXIS_BORDER}, + ticks: baseTicks({ + maxTicksLimit: 5, callback: (v: number | string) => formatAlpha(Number(v)), - font: {size: 10}, - }, + }), + title: axisTitle('conviction (α)'), }, }, }), - [], + [horizon], ); return ( @@ -182,25 +341,22 @@ export function ConvictionSubnetScenario() { title={`Example: Subnet ${EXAMPLE_SUBNET.netuid} (${EXAMPLE_SUBNET.name})`} caption="Fictional numbers for illustration. Three coldkeys lock toward different hotkeys; total conviction must reach 10% of SubnetAlphaOut before ownership can transfer." > -
    - {[ - {label: 'SubnetAlphaOut', value: formatAlpha(EXAMPLE_SUBNET.alphaOut)}, - {label: '10% threshold', value: formatAlpha(threshold)}, - {label: 'Subnet age', value: formatBlocks(EXAMPLE_SUBNET.ageBlocks)}, - {label: 'Ownership gate', value: ownershipReady ? 'Open' : 'Closed'}, - ].map((item) => ( -
    -

    {item.label}

    -

    {item.value}

    -
    - ))} +
    + + + +
    - +
    -
    +
    -
    - + setCarolPerpetual(id === 'perpetual')} /> - - -
    ); diff --git a/website/apps/bittensor-website/src/components/docs/emission-flow-diagram.tsx b/website/apps/bittensor-website/src/components/docs/emission-flow-diagram.tsx index 0d55ba99f7..2209c38182 100644 --- a/website/apps/bittensor-website/src/components/docs/emission-flow-diagram.tsx +++ b/website/apps/bittensor-website/src/components/docs/emission-flow-diagram.tsx @@ -5,18 +5,24 @@ import { ExplainerPanel, ExplainerStat } from './explainer-panel'; import { useEmissionSnapshot } from '@/hooks/use-emission-snapshot'; import { alphaEmissionPerBlock, alphaIssuance } from '@/lib/emission-snapshot'; import { alphaOutSplit, formatPct, formatTao, rootProportion } from '@/lib/emission-math'; +import { ACCENT, INK } from './chart-theme'; -function FlowBar({label, pct, detail}: {label: string; pct: number; detail?: string}) { +function FlowBar({label, pct, detail, accent = false}: {label: string; pct: number; detail?: string; accent?: boolean}) { return (
    -
    +
    {label} - {formatPct(pct)} + + {formatPct(pct)} +
    -
    -
    +
    +
    - {detail &&

    {detail}

    } + {detail &&

    {detail}

    }
    ); } @@ -46,20 +52,18 @@ export function EmissionFlowDiagram() { title={`Per-tempo alpha split — SN${featured.netuid} ${featured.name}`} caption={`Finney snapshot via TMC: ${alphaOut.toFixed(4)} α_out/block. Root gate ${rootGateOpen ? 'open' : 'closed'} (Σ EMA = ${snapshot.emaPriceSum.toFixed(2)}).`} > -
    -
    -

    Per block (coinbase)

    +
    +
    +

    01 · Per block (coinbase)

    • {formatTao(snapshot.blockEmissionTao)}/block minted → price-EMA shares
    • -
    • SN{featured.netuid} receives {formatTao(featured.taoPerBlock, 4)} τ
    • +
    • SN{featured.netuid} receives {formatTao(featured.taoPerBlock, 4)}
    • Accrues {alphaOut.toFixed(4)} α_out for next epoch
    -
    - -
    -

    At epoch (Yuma)

    +
    +

    02 · At epoch (Yuma)

    • Distribute miner half via incentive ranks
    • Pay validator dividends + delegate take
    • @@ -70,7 +74,7 @@ export function EmissionFlowDiagram() {
    -
    +
    @@ -81,11 +85,12 @@ export function EmissionFlowDiagram() { label="Recycled (gate closed)" pct={segments.recycled} detail={`Σ subnet EMA prices = ${snapshot.emaPriceSum.toFixed(2)} ≤ 1.0`} + accent /> )}
    -
    +
    diff --git a/website/apps/bittensor-website/src/components/docs/emission-network-snapshot.tsx b/website/apps/bittensor-website/src/components/docs/emission-network-snapshot.tsx index c4b4179ef7..8bbb862d96 100644 --- a/website/apps/bittensor-website/src/components/docs/emission-network-snapshot.tsx +++ b/website/apps/bittensor-website/src/components/docs/emission-network-snapshot.tsx @@ -13,7 +13,7 @@ export function EmissionNetworkSnapshot() { title="Finney mainnet snapshot" caption={`Price-EMA emission (live ${snapshot.emissionMode}). Σ EMA prices from TaoMarketCap — fetched ${formatSnapshotAge(snapshot.fetchedAt)}.`} > -
    +
    1.0, TMC)' : 'Root gate closed (Σ EMA ≤ 1.0, TMC)' } + accent={!loading && !snapshot.rootDividendGateOpen} />
    -

    +

    TAO splits across subnets by SubnetMovingPrice{' '} (EMA of spot alpha price, capped at 1.0), minus last-tempo{' '} MinerBurned penalties. Top recipient right diff --git a/website/apps/bittensor-website/src/components/docs/evm-address-domains.tsx b/website/apps/bittensor-website/src/components/docs/evm-address-domains.tsx index e69010eadf..518852dbf0 100644 --- a/website/apps/bittensor-website/src/components/docs/evm-address-domains.tsx +++ b/website/apps/bittensor-website/src/components/docs/evm-address-domains.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from 'react'; import { ExplainerPanel, ExplainerStat } from './explainer-panel'; -function DomainBox({ +function Domain({ title, example, signs, @@ -15,8 +15,8 @@ function DomainBox({ children: ReactNode; }) { return ( -

    -

    {title}

    +
    +

    {title}

    {example}

    {signs}

    {children}
    @@ -28,7 +28,29 @@ function Arrow({ label }: { label?: string }) { return (
    - {label && {label}} + {label && ( + + {label} + + )} +
    + ); +} + +function Mapping({ + title, + commands, + children, +}: { + title: string; + commands: string; + children: ReactNode; +}) { + return ( +
    +

    {title}

    +

    {children}

    +

    {commands}

    ); } @@ -40,42 +62,36 @@ export function EvmAddressDomains() { caption="Conversions are deterministic but never carry private keys — a btcli wallet cannot sign EVM txs, and MetaMask cannot sign extrinsics." >
    - +

    Coldkeys, hotkeys, neurons

    Used by btcli tx …

    -
    + - +

    MetaMask, Hardhat, contracts

    Used by eth_sendRawTransaction

    -
    +
    -
    -
    -

    Hashed mirror (fund an EVM account)

    -

    - Every h160 has an ss58 mirror:{' '} - ss58(blake2("evm:" ++ h160)). Transfer TAO to - the mirror and it appears as that EVM account's balance. -

    -

    - btcli evm mirror · btcli evm fund -

    -
    -
    -

    Truncated mapping (claim a MetaMask deposit)

    -

    - Every ss58 account controls one h160: the first 20 bytes of its public - key. Send TAO from MetaMask to that address, then claim it on the native side. -

    -

    - btcli evm deposit-address · btcli evm claim-deposit -

    -
    +
    + + Every h160 has an ss58 mirror:{' '} + ss58(blake2("evm:" ++ h160)). Transfer TAO to + the mirror and it appears as that EVM account's balance. + + + Every ss58 account controls one h160: the first 20 bytes of its public + key. Send TAO from MetaMask to that address, then claim it on the native side. +
    -
    +
    diff --git a/website/apps/bittensor-website/src/components/docs/evm-money-flows.tsx b/website/apps/bittensor-website/src/components/docs/evm-money-flows.tsx index 21305a8fe3..1575a32ece 100644 --- a/website/apps/bittensor-website/src/components/docs/evm-money-flows.tsx +++ b/website/apps/bittensor-website/src/components/docs/evm-money-flows.tsx @@ -20,14 +20,14 @@ function FlowCard({ note?: string; }) { return ( -
    -
    -

    {title}

    +
    +
    +

    {title}

    {command}
    -
    - signs: {signer} - gas: {gas} +
    + signs · {signer} + gas · {gas}
      {steps.map((step, index) => ( @@ -51,7 +51,7 @@ export function EvmMoneyFlows() { title="Four ways TAO crosses the ss58 ↔ EVM seam" caption="Pick the path that matches who holds the keys. The two “withdraw” names are easy to confuse — read the signer and gas columns." > -
      +
      -
      -

      {title}

      - {caption &&

      {caption}

      } -
      -
      {children}
      +
      +
      +
      +
      + {title} +
      + {tag && ( + + {tag} + + )} +
      + {caption && ( +

      {caption}

      + )} +
      +
      {children}
      +
      ); } @@ -29,16 +52,71 @@ export function ExplainerStat({ label, value, hint, + accent = false, }: { label: string; value: string; hint?: string; + accent?: boolean; +}) { + return ( +
      +

      {label}

      +

      + + {value} + +

      + {hint &&

      {hint}

      } +
      + ); +} + +export function ExplainerToggle({ + label, + options, + value, + onChange, +}: { + label: string; + options: readonly { id: Id; label: string; accent?: boolean }[]; + value: Id; + onChange: (id: Id) => void; }) { return ( -
      -

      {label}

      -

      {value}

      - {hint &&

      {hint}

      } +
      + + {label} + +
      + {options.map((option) => { + const active = option.id === value; + return ( + + ); + })} +
      ); } @@ -59,22 +137,40 @@ export function ExplainerSlider({ step: number; display: string; onChange: (value: number) => void; + /** Accepted for backwards compatibility; the red styling is now the default. */ + accent?: boolean; }) { + const id = useId(); + const pct = ((value - min) / (max - min)) * 100; return ( -
    From 9ded802157d23ef279e1c27d7e318d663abf154f Mon Sep 17 00:00:00 2001 From: unarbos Date: Tue, 14 Jul 2026 11:31:23 -0600 Subject: [PATCH 26/43] restore devnet and testnet docker image publishing Co-authored-by: Cursor --- .github/workflows/docker.yml | 22 +++++++++++---------- docs/internals/release-process.mdx | 31 +++++++++++++----------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index be842703ed..2132bc0829 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,13 +1,16 @@ name: Publish Docker Image -# Node images publish on runtime releases and on demand. Releases cut by -# watch-mainnet-release.yml use the default GITHUB_TOKEN, which never emits -# `release: published`; the watcher therefore dispatches this workflow -# directly with the release tag. Release-version tags (vN) move :latest. +# Node images publish when a network mirror moves, on runtime releases, and on +# demand. Releases cut by watch-mainnet-release.yml use the default +# GITHUB_TOKEN, which never emits `release: published`; the watcher therefore +# dispatches this workflow directly with the release tag. Release-version tags +# (vN) move :latest; network mirror tags do not. on: release: types: [published] + push: + branches: [devnet, testnet] workflow_dispatch: inputs: tag: @@ -31,7 +34,9 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.inputs.tag || github.ref_name }} + # Push/release events carry the immutable promoted commit. Manual + # dispatches may override it with a branch or tag. + ref: ${{ github.event.inputs.tag || github.sha }} - name: Resolve immutable source revision id: ref @@ -116,18 +121,15 @@ jobs: runs-on: [self-hosted, fireactions-turbo-8] timeout-minutes: 30 steps: - - name: Determine tag, ref, and image name + - name: Determine tag and image name env: INPUT_TAG: ${{ github.event.inputs.tag || github.ref_name }} run: | - ref="$INPUT_TAG" - # `ref` is what we check out (a real branch/tag, may contain '/'). # Docker tags cannot contain '/', so derive the tag by replacing any # disallowed characters — otherwise a ref like `feat/x` fails tag # validation at push time. - tag="${ref//[^a-zA-Z0-9._-]/-}" + tag="${INPUT_TAG//[^a-zA-Z0-9._-]/-}" echo "tag=$tag" >> $GITHUB_ENV - echo "ref=$ref" >> $GITHUB_ENV # Move :latest for release events and for dispatched release-version # tags (the watcher dispatches with tag=vN because its GITHUB_TOKEN # release cannot fire the `release` trigger). diff --git a/docs/internals/release-process.mdx b/docs/internals/release-process.mdx index a6648ba1a5..4c886ba6f1 100644 --- a/docs/internals/release-process.mdx +++ b/docs/internals/release-process.mdx @@ -52,8 +52,11 @@ Human approval lives in GitHub **environment settings**, not workflow code: | mainnet | `mainnet` | environment reviewers **plus** the multisig ceremony below | Deploys to devnet and testnet are direct `setCode` transactions via the CI -deploy key; each is followed by an on-chain `spec_version` verification and a -smoke suite. +deploy key. After the on-chain `spec_version` is verified, the train moves the +corresponding network mirror branch. That branch push builds the exact deployed +commit and updates `ghcr.io/raofoundation/subtensor:devnet` or `:testnet`; it +does not move `:latest`. The smoke suite then validates the live network while +the independent image build runs. ### The mainnet multisig ceremony @@ -74,28 +77,20 @@ running your runtime with a public endpoint yet, it cuts the release train's artifacts: 1. **GitHub release** `v` -2. **Python SDK + bittensor-core wheels** to PyPI (trusted publishing, with +2. **Production Docker images** tagged `v` and `latest` +3. **Python SDK + bittensor-core wheels** to PyPI (trusted publishing, with PEP 740 provenance attestations) -3. **Publishable Rust crates** to crates.io (auto-discovered; workspace crates +4. **Publishable Rust crates** to crates.io (auto-discovered; workspace crates are `publish = false` while they depend on the patched polkadot-sdk fork) -4. **Production website/docs** to Vercel +5. **Production website/docs** to Vercel This ordering means the release always reflects what is *actually running on mainnet*, not what was merged. -### Known gap: Docker images don't publish on release - -`docker.yml` and `docker-localnet.yml` trigger on `release: published` and are -what tag `ghcr.io` images (including `:latest`) for a mainnet release. However, -the watcher creates the release with the default `GITHUB_TOKEN`, and **GitHub -does not trigger workflows from events created by the default token** (a -recursion guard). So the production node image is currently *not* published -when a release is cut. Until fixed (use a PAT/app token for `gh release -create`, or have the watcher call `gh workflow run docker.yml -f -branch-or-tag=v`), publish manually via `docker.yml`'s -`workflow_dispatch` with the release tag. Note the release also carries no -attached artifacts — the srtool wasm/digest live only as 90-day workflow -artifacts on the train run. +The watcher explicitly dispatches `docker.yml` and `docker-localnet.yml` +because releases created with the default `GITHUB_TOKEN` do not emit another +workflow event. The production build publishes both the immutable release tag +and `:latest`; the localnet build does the same in its separate package. ## Hotfixes From c6b7442b8992ded2ecc0c709508c11c65a0a816e Mon Sep 17 00:00:00 2001 From: unarbos Date: Tue, 14 Jul 2026 11:31:23 -0600 Subject: [PATCH 27/43] beautify the extension signing bridge ui Co-authored-by: Cursor --- sdk/python/bittensor/cli/context.py | 25 +- sdk/python/bittensor/extension/client.py | 4 + sdk/python/bittensor/extension/signer.py | 4 + .../bittensor/extension/static/bridge.html | 340 +++++++++++++++--- .../tests/unit/test_extension_bridge.py | 17 + 5 files changed, 341 insertions(+), 49 deletions(-) diff --git a/sdk/python/bittensor/cli/context.py b/sdk/python/bittensor/cli/context.py index ee0985c108..c8bef916e0 100644 --- a/sdk/python/bittensor/cli/context.py +++ b/sdk/python/bittensor/cli/context.py @@ -459,22 +459,31 @@ async def _execute(client): ) use_shield = False signer = await self.resolve_signing_wallet(intent.signer) + result = None try: if use_shield: - return await client.submit_shielded( + result = await client.submit_shielded( intent, signer, wait_for_finalization=False, ) - result = await client.execute( - intent, - signer, - wait_for_finalization=False, - **options, - ) - await self._attach_multisig_followup(client, intent, result) + else: + result = await client.execute( + intent, + signer, + wait_for_finalization=False, + **options, + ) + await self._attach_multisig_followup(client, intent, result) return result finally: + if self.uses_extension_signer() and hasattr( + signer, "report_transaction_result" + ): + with contextlib.suppress(Exception): + await signer.report_transaction_result( + bool(result is not None and result.success) + ) if hasattr(signer, "close"): await signer.close() diff --git a/sdk/python/bittensor/extension/client.py b/sdk/python/bittensor/extension/client.py index 2bed2d1eef..fc6d9f2c53 100644 --- a/sdk/python/bittensor/extension/client.py +++ b/sdk/python/bittensor/extension/client.py @@ -122,3 +122,7 @@ async def sign_bytes(self, address: str, data_hex: str) -> dict[str, Any]: if not isinstance(result, dict): raise BridgeError("bridge returned an invalid bytes signature") return result + + async def report_transaction_result(self, success: bool) -> None: + """Tell the bridge page that the submitted transaction has finished.""" + await self.request("transaction.result", {"success": success}) diff --git a/sdk/python/bittensor/extension/signer.py b/sdk/python/bittensor/extension/signer.py index 223a212d28..395d5c2584 100644 --- a/sdk/python/bittensor/extension/signer.py +++ b/sdk/python/bittensor/extension/signer.py @@ -93,6 +93,10 @@ def account_name(self) -> str: async def close(self) -> None: await self._bridge.close() + async def report_transaction_result(self, success: bool) -> None: + """Update the bridge page after the chain submission completes.""" + await self._bridge.report_transaction_result(success) + async def sign_extrinsic_payload(self, payload: dict[str, Any]) -> dict[str, Any]: body = dict(payload) body["address"] = self.ss58_address diff --git a/sdk/python/bittensor/extension/static/bridge.html b/sdk/python/bittensor/extension/static/bridge.html index 8315399091..4c34043cb2 100644 --- a/sdk/python/bittensor/extension/static/bridge.html +++ b/sdk/python/bittensor/extension/static/bridge.html @@ -14,69 +14,327 @@ Bittensor Extension Bridge - -

    Bittensor Extension Bridge

    -

    Starting…

    -

    - Keep this tab open while using btcli --signer extension. - Authorize Talisman, Polkadot.js, or another compatible wallet when prompted. -

    -
      + +
      + +
      +

      Keep this page open

      +

      Switch back to btcli.

      +
      +