Transactions

set-crowdloan-max-contribution

Set or clear the per-contributor max for a non-finalized crowdloan (creator only).

View as Markdown

Caps how much any single contributor can put in, useful to keep a raise broadly distributed. Omitting the amount clears the limit. Only the creator may change it, and only while the loan has not been finalized.

SignerOriginPalletWraps
coldkeysigned account (pallet role may apply)CrowdloanCrowdloan.set_max_contribution

Parameters

ParameterTypeRequiredDescription
crowdloan_idintegeryesIdentifier of the crowdloan, assigned when it was created.
new_max_contribution_taonumber | "all"noLargest total any single contributor may put in. Omit to clear the limit.

Address parameters (--hotkey, --coldkey, --dest, ...) accept a raw ss58 address, an address-book or proxy-book name, or a local wallet/hotkey name.

CLI

Preview with --dry-run (shows fee, effects, and policy result without submitting), then submit:

btcli tx set-crowdloan-max-contribution \
  --crowdloan-id <int> --dry-run
btcli tx set-crowdloan-max-contribution \
  --crowdloan-id <int> -w my_coldkey

Python

import bittensor as bt
from bittensor.wallet import Wallet

wallet = Wallet(name="my_coldkey", hotkey="my_hotkey")
intent = bt.SetCrowdloanMaxContribution(crowdloan_id=0)

sub = bt.Subtensor()
plan = sub.plan(intent, wallet)   # fee, effects, policy — no submission
result = sub.execute(intent, wallet)
if not result.success:
    print(result.error.code, result.error.remediation)

(bt.Subtensor is also the async client — async with bt.Subtensor() as client: — see The client.) Or build the intent by op name, as an agent would:

result = sub.execute_tool("set_crowdloan_max_contribution", {...}, wallet)

On-chain implementation

Crowdloan.set_max_contributionpallets/crowdloan/src/lib.rs#L935:

#[pallet::call_index(9)]
#[pallet::weight(T::WeightInfo::set_max_contribution())]
pub fn set_max_contribution(
    origin: OriginFor<T>,
    #[pallet::compact] crowdloan_id: CrowdloanId,
    new_max_contribution: Option<BalanceOf<T>>,
) -> DispatchResult {
    let who = ensure_signed(origin)?;

    let crowdloan = Self::ensure_crowdloan_exists(crowdloan_id)?;
    ensure!(!crowdloan.finalized, Error::<T>::AlreadyFinalized);

    // Only the creator can update the max contribution.
    ensure!(who == crowdloan.creator, Error::<T>::InvalidOrigin);

    if let Some(max_contribution) = new_max_contribution {
        let creator_contribution =
            Contributions::<T>::get(crowdloan_id, &crowdloan.creator)
                .unwrap_or_else(Zero::zero);
        ensure!(
            max_contribution >= crowdloan.min_contribution
                && max_contribution >= creator_contribution,
            Error::<T>::MaximumContributionTooLow
        );
        MaxContributions::<T>::insert(crowdloan_id, max_contribution);
    } else {
        MaxContributions::<T>::remove(crowdloan_id);
    }

    Self::deposit_event(Event::<T>::MaxContributionUpdated {
        crowdloan_id,
        new_max_contribution,
    });
    Ok(())
}

Every file is browsable under /code exactly as built into the runtime, or as plain text under /code/raw/<path> (index: /code/index.json).