Skip to content

NominationPools


Calls


bond_extra

Bond extra more funds from origin into the pool to which they already belong.

Additional funds can come from either the free balance of the account, of from the accumulated rewards, see [BondExtra].

Bonding extra funds implies an automatic payout of all pending rewards as well.

Attributes

Name Type
extra BondExtra<BalanceOf<T>>

Python

call = substrate.compose_call(
    'NominationPools', 'bond_extra', {
    'extra': {
        'FreeBalance': 'u128',
        'Rewards': None,
    },
}
)

chill

Chill on behalf of the pool.

The dispatch origin of this call must be signed by the pool nominator or the pool root role, same as [Pallet::nominate].

This directly forward the call to the staking pallet, on behalf of the pool bonded account.

Attributes

Name Type
pool_id PoolId

Python

call = substrate.compose_call(
    'NominationPools', 'chill', {'pool_id': 'u32'}
)

claim_payout

A bonded member can use this to claim their payout based on the rewards that the pool has accumulated since their last claimed payout (OR since joining if this is there first time claiming rewards). The payout will be transferred to the member&#x27;s account.

The member will earn rewards pro rata based on the members stake vs the sum of the members in the pools stake. Rewards do not "expire".

Attributes

No attributes

Python

call = substrate.compose_call(
    'NominationPools', 'claim_payout', {}
)

create

Create a new delegation pool.

# Arguments

  • amount - The amount of funds to delegate to the pool. This also acts of a sort of deposit since the pools creator cannot fully unbond funds until the pool is being destroyed.
  • index - A disambiguation index for creating the account. Likely only useful when creating multiple pools in the same extrinsic.
  • root - The account to set as [PoolRoles::root].
  • nominator - The account to set as the [PoolRoles::nominator].
  • state_toggler - The account to set as the [PoolRoles::state_toggler].

# Note

In addition to amount, the caller will transfer the existential deposit; so the caller needs at have at least amount + existential_deposit transferrable.

Attributes

Name Type
amount BalanceOf<T>
root T::AccountId
nominator T::AccountId
state_toggler T::AccountId

Python

call = substrate.compose_call(
    'NominationPools', 'create', {
    'amount': 'u128',
    'nominator': 'AccountId',
    'root': 'AccountId',
    'state_toggler': 'AccountId',
}
)

join

Stake funds with a pool. The amount to bond is transferred from the member to the pools account and immediately increases the pools bond.

# Note

  • An account can only be a member of a single pool.
  • An account cannot join the same pool multiple times.
  • This call will not dust the member account, so the member must have at least existential deposit + amount in their account.
  • Only a pool with [PoolState::Open] can be joined

Attributes

Name Type
amount BalanceOf<T>
pool_id PoolId

Python

call = substrate.compose_call(
    'NominationPools', 'join', {'amount': 'u128', 'pool_id': 'u32'}
)

nominate

Nominate on behalf of the pool.

The dispatch origin of this call must be signed by the pool nominator or the pool root role.

This directly forward the call to the staking pallet, on behalf of the pool bonded account.

Attributes

Name Type
pool_id PoolId
validators Vec<T::AccountId>

Python

call = substrate.compose_call(
    'NominationPools', 'nominate', {
    'pool_id': 'u32',
    'validators': ['AccountId'],
}
)

pool_withdraw_unbonded

Call withdraw_unbonded for the pools account. This call can be made by any account.

This is useful if their are too many unlocking chunks to call unbond, and some can be cleared by withdrawing. In the case there are too many unlocking chunks, the user would probably see an error like NoMoreChunks emitted from the staking system when they attempt to unbond.

Attributes

Name Type
pool_id PoolId
num_slashing_spans u32

Python

call = substrate.compose_call(
    'NominationPools', 'pool_withdraw_unbonded', {
    'num_slashing_spans': 'u32',
    'pool_id': 'u32',
}
)

set_configs

Update configurations for the nomination pools. The origin for this call must be Root.

# Arguments

  • min_join_bond - Set [MinJoinBond].
  • min_create_bond - Set [MinCreateBond].
  • max_pools - Set [MaxPools].
  • max_members - Set [MaxPoolMembers].
  • max_members_per_pool - Set [MaxPoolMembersPerPool].

Attributes

Name Type
min_join_bond ConfigOp<BalanceOf<T>>
min_create_bond ConfigOp<BalanceOf<T>>
max_pools ConfigOp<u32>
max_members ConfigOp<u32>
max_members_per_pool ConfigOp<u32>

Python

call = substrate.compose_call(
    'NominationPools', 'set_configs', {
    'max_members': {
        'Noop': None,
        'Remove': None,
        'Set': 'u32',
    },
    'max_members_per_pool': {
        'Noop': None,
        'Remove': None,
        'Set': 'u32',
    },
    'max_pools': {
        'Noop': None,
        'Remove': None,
        'Set': 'u32',
    },
    'min_create_bond': {
        'Noop': None,
        'Remove': None,
        'Set': 'u128',
    },
    'min_join_bond': {
        'Noop': None,
        'Remove': None,
        'Set': 'u128',
    },
}
)

set_metadata

Set a new metadata for the pool.

The dispatch origin of this call must be signed by the state toggler, or the root role of the pool.

Attributes

Name Type
pool_id PoolId
metadata Vec<u8>

Python

call = substrate.compose_call(
    'NominationPools', 'set_metadata', {
    'metadata': 'Bytes',
    'pool_id': 'u32',
}
)

set_state

Set a new state for the pool.

If a pool is already in the Destroying state, then under no condition can its state change again.

The dispatch origin of this call must be either:

  1. signed by the state toggler, or the root role of the pool,
  2. if the pool conditions to be open are NOT met (as described by ok_to_be_open), and then the state of the pool can be permissionlessly changed to Destroying.

Attributes

Name Type
pool_id PoolId
state PoolState

Python

call = substrate.compose_call(
    'NominationPools', 'set_state', {
    'pool_id': 'u32',
    'state': (
        'Open',
        'Blocked',
        'Destroying',
    ),
}
)

unbond

Unbond up to unbonding_points of the member_account&#x27;s funds from the pool. It implicitly collects the rewards one last time, since not doing so would mean some rewards would be forfeited.

Under certain conditions, this call can be dispatched permissionlessly (i.e. by any account).

# Conditions for a permissionless dispatch.

  • The pool is blocked and the caller is either the root or state-toggler. This is refereed to as a kick.
  • The pool is destroying and the member is not the depositor.
  • The pool is destroying, the member is the depositor and no other members are in the pool.

## Conditions for permissioned dispatch (i.e. the caller is also the member_account):

  • The caller is not the depositor.
  • The caller is the depositor, the pool is destroying and no other members are in the pool.

# Note

If there are too many unlocking chunks to unbond with the pool account, [Call::pool_withdraw_unbonded] can be called to try and minimize unlocking chunks. If there are too many unlocking chunks, the result of this call will likely be the NoMoreChunks error from the staking system.

Attributes

Name Type
member_account T::AccountId
unbonding_points BalanceOf<T>

Python

call = substrate.compose_call(
    'NominationPools', 'unbond', {
    'member_account': 'AccountId',
    'unbonding_points': 'u128',
}
)

update_roles

Update the roles of the pool.

The root is the only entity that can change any of the roles, including itself, excluding the depositor, who can never change.

It emits an event, notifying UIs of the role change. This event is quite relevant to most pool members and they should be informed of changes to pool roles.

Attributes

Name Type
pool_id PoolId
new_root ConfigOp<T::AccountId>
new_nominator ConfigOp<T::AccountId>
new_state_toggler ConfigOp<T::AccountId>

Python

call = substrate.compose_call(
    'NominationPools', 'update_roles', {
    'new_nominator': {
        'Noop': None,
        'Remove': None,
        'Set': 'AccountId',
    },
    'new_root': {
        'Noop': None,
        'Remove': None,
        'Set': 'AccountId',
    },
    'new_state_toggler': {
        'Noop': None,
        'Remove': None,
        'Set': 'AccountId',
    },
    'pool_id': 'u32',
}
)

withdraw_unbonded

Withdraw unbonded funds from member_account. If no bonded funds can be unbonded, an error is returned.

Under certain conditions, this call can be dispatched permissionlessly (i.e. by any account).

# Conditions for a permissionless dispatch

  • The pool is in destroy mode and the target is not the depositor.
  • The target is the depositor and they are the only member in the sub pools.
  • The pool is blocked and the caller is either the root or state-toggler.

# Conditions for permissioned dispatch

  • The caller is the target and they are not the depositor.

# Note

If the target is the depositor, the pool will be destroyed.

Attributes

Name Type
member_account T::AccountId
num_slashing_spans u32

Python

call = substrate.compose_call(
    'NominationPools', 'withdraw_unbonded', {
    'member_account': 'AccountId',
    'num_slashing_spans': 'u32',
}
)

Events


Bonded

A member has became bonded in a pool.

Attributes

Name Type Composition
member T::AccountId AccountId
pool_id PoolId u32
bonded BalanceOf<T> u128
joined bool bool

Created

A pool has been created.

Attributes

Name Type Composition
depositor T::AccountId AccountId
pool_id PoolId u32

Destroyed

A pool has been destroyed.

Attributes

Name Type Composition
pool_id PoolId u32

MemberRemoved

A member has been removed from a pool.

The removal can be voluntary (withdrawn all unbonded funds) or involuntary (kicked).

Attributes

Name Type Composition
pool_id PoolId u32
member T::AccountId AccountId

PaidOut

A payout has been made to a member.

Attributes

Name Type Composition
member T::AccountId AccountId
pool_id PoolId u32
payout BalanceOf<T> u128

PoolSlashed

The active balance of pool pool_id has been slashed to balance.

Attributes

Name Type Composition
pool_id PoolId u32
balance BalanceOf<T> u128

RolesUpdated

The roles of a pool have been updated to the given new roles. Note that the depositor can never change.

Attributes

Name Type Composition
root Option<T::AccountId> (None, 'AccountId')
state_toggler Option<T::AccountId> (None, 'AccountId')
nominator Option<T::AccountId> (None, 'AccountId')

StateChanged

The state of a pool has changed

Attributes

Name Type Composition
pool_id PoolId u32
new_state PoolState ('Open', 'Blocked', 'Destroying')

Unbonded

A member has unbonded from their pool.

  • balance is the corresponding balance of the number of points that has been requested to be unbonded (the argument of the unbond transaction) from the bonded pool.
  • points is the number of points that are issued as a result of balance being dissolved into the corresponding unbonding pool.
  • era is the era in which the balance will be unbonded. In the absence of slashing, these values will match. In the presence of slashing, the number of points that are issued in the unbonding pool will be less than the amount requested to be unbonded.

Attributes

Name Type Composition
member T::AccountId AccountId
pool_id PoolId u32
balance BalanceOf<T> u128
points BalanceOf<T> u128
era EraIndex u32

UnbondingPoolSlashed

The unbond pool at era of pool pool_id has been slashed to balance.

Attributes

Name Type Composition
pool_id PoolId u32
era EraIndex u32
balance BalanceOf<T> u128

Withdrawn

A member has withdrawn from their pool.

The given number of points have been dissolved in return of balance.

Similar to Unbonded event, in the absence of slashing, the ratio of point to balance will be 1.

Attributes

Name Type Composition
member T::AccountId AccountId
pool_id PoolId u32
balance BalanceOf<T> u128
points BalanceOf<T> u128

Storage functions


BondedPools

Storage for bonded pools.

Python

result = substrate.query(
    'NominationPools', 'BondedPools', ['u32']
)

Return value

{
    'member_counter': 'u32',
    'points': 'u128',
    'roles': {
        'depositor': 'AccountId',
        'nominator': (None, 'AccountId'),
        'root': (None, 'AccountId'),
        'state_toggler': (None, 'AccountId'),
    },
    'state': ('Open', 'Blocked', 'Destroying'),
}

CounterForBondedPools

Counter for the related counted storage map

Python

result = substrate.query(
    'NominationPools', 'CounterForBondedPools', []
)

Return value

'u32'

CounterForMetadata

Counter for the related counted storage map

Python

result = substrate.query(
    'NominationPools', 'CounterForMetadata', []
)

Return value

'u32'

CounterForPoolMembers

Counter for the related counted storage map

Python

result = substrate.query(
    'NominationPools', 'CounterForPoolMembers', []
)

Return value

'u32'

CounterForReversePoolIdLookup

Counter for the related counted storage map

Python

result = substrate.query(
    'NominationPools', 'CounterForReversePoolIdLookup', []
)

Return value

'u32'

CounterForRewardPools

Counter for the related counted storage map

Python

result = substrate.query(
    'NominationPools', 'CounterForRewardPools', []
)

Return value

'u32'

CounterForSubPoolsStorage

Counter for the related counted storage map

Python

result = substrate.query(
    'NominationPools', 'CounterForSubPoolsStorage', []
)

Return value

'u32'

LastPoolId

Ever increasing number of all pools created so far.

Python

result = substrate.query(
    'NominationPools', 'LastPoolId', []
)

Return value

'u32'

MaxPoolMembers

Maximum number of members that can exist in the system. If None, then the count members are not bound on a system wide basis.

Python

result = substrate.query(
    'NominationPools', 'MaxPoolMembers', []
)

Return value

'u32'

MaxPoolMembersPerPool

Maximum number of members that may belong to pool. If None, then the count of members is not bound on a per pool basis.

Python

result = substrate.query(
    'NominationPools', 'MaxPoolMembersPerPool', []
)

Return value

'u32'

MaxPools

Maximum number of nomination pools that can exist. If None, then an unbounded number of pools can exist.

Python

result = substrate.query(
    'NominationPools', 'MaxPools', []
)

Return value

'u32'

Metadata

Metadata for the pool.

Python

result = substrate.query(
    'NominationPools', 'Metadata', ['u32']
)

Return value

'Bytes'

MinCreateBond

Minimum bond required to create a pool.

This is the amount that the depositor must put as their initial stake in the pool, as an indication of "skin in the game".

This is the value that will always exist in the staking ledger of the pool bonded account while all other accounts leave.

Python

result = substrate.query(
    'NominationPools', 'MinCreateBond', []
)

Return value

'u128'

MinJoinBond

Minimum amount to bond to join a pool.

Python

result = substrate.query(
    'NominationPools', 'MinJoinBond', []
)

Return value

'u128'

PoolMembers

Active members.

Python

result = substrate.query(
    'NominationPools', 'PoolMembers', ['AccountId']
)

Return value

{
    'last_recorded_reward_counter': 'u128',
    'points': 'u128',
    'pool_id': 'u32',
    'unbonding_eras': 'scale_info::607',
}

ReversePoolIdLookup

A reverse lookup from the pool's account id to its id.

This is only used for slashing. In all other instances, the pool id is used, and the accounts are deterministically derived from it.

Python

result = substrate.query(
    'NominationPools', 'ReversePoolIdLookup', ['AccountId']
)

Return value

'u32'

RewardPools

Reward pools. This is where there rewards for each pool accumulate. When a members payout is claimed, the balance comes out fo the reward pool. Keyed by the bonded pools account.

Python

result = substrate.query(
    'NominationPools', 'RewardPools', ['u32']
)

Return value

{
    'last_recorded_reward_counter': 'u128',
    'last_recorded_total_payouts': 'u128',
    'total_rewards_claimed': 'u128',
}

SubPoolsStorage

Groups of unbonding pools. Each group of unbonding pools belongs to a bonded pool, hence the name sub-pools. Keyed by the bonded pools account.

Python

result = substrate.query(
    'NominationPools', 'SubPoolsStorage', ['u32']
)

Return value

{'no_era': {'balance': 'u128', 'points': 'u128'}, 'with_era': 'scale_info::615'}

Constants


MaxPointsToBalance

The maximum pool points-to-balance ratio that an open pool can have.

This is important in the event slashing takes place and the pool's points-to-balance ratio becomes disproportional.

Moreover, this relates to the RewardCounter type as well, as the arithmetic operations are a function of number of points, and by setting this value to e.g. 10, you ensure that the total number of points in the system are at most 10 times the total_issuance of the chain, in the absolute worse case.

For a value of 10, the threshold would be a pool points-to-balance ratio of 10:1. Such a scenario would also be the equivalent of the pool being 90% slashed.

Value

10

Python

constant = substrate.get_constant('NominationPools', 'MaxPointsToBalance')

PalletId

The nomination pool's pallet id.

Value

'0x70792f6e6f706c73'

Python

constant = substrate.get_constant('NominationPools', 'PalletId')

Errors


AccountBelongsToOtherPool

An account is already delegating in another pool. An account may only belong to one pool at a time.


CanNotChangeState

The pools state cannot be changed.


CannotWithdrawAny

None of the funds can be withdrawn yet because the bonding duration has not passed.


Defensive

Some error occurred that should never happen. This should be reported to the maintainers.


DoesNotHavePermission

The caller does not have adequate permissions.


FullyUnbonding

The member is fully unbonded (and thus cannot access the bonded and reward pool anymore to, for example, collect rewards).


MaxPoolMembers

Too many members in the pool or system.


MaxPools

The system is maxed out on pools.


MaxUnbondingLimit

The member cannot unbond further chunks due to reaching the limit.


MetadataExceedsMaxLen

Metadata exceeds [Config::MaxMetadataLen]


MinimumBondNotMet

The amount does not meet the minimum bond to either join or create a pool.

The depositor can never unbond to a value less than Pallet::depositor_min_bond. The caller does not have nominating permissions for the pool. Members can never unbond to a value below MinJoinBond.


NotDestroying

A pool must be in [PoolState::Destroying] in order for the depositor to unbond or for other members to be permissionlessly unbonded.


NotKickerOrDestroying

Either a) the caller cannot make a valid kick or b) the pool is not destroying.


NotNominator

The caller does not have nominating permissions for the pool.


NotOpen

The pool is not open to join


OverflowRisk

The transaction could not be executed due to overflow risk for the pool.


PartialUnbondNotAllowedPermissionlessly

Partial unbonding now allowed permissionlessly.


PoolMemberNotFound

An account is not a member.


PoolNotFound

A (bonded) pool id does not exist.


RewardPoolNotFound

A reward pool does not exist. In all cases this is a system logic error.


SubPoolsNotFound

A sub pool does not exist.