Skip to content

The Parachain Staking Pallet

Introduction

Moonbeam uses a Delegated Proof of Stake (DPoS) system that determines which collators are eligible to produce blocks based on their total stake in the network. For general information on staking, such as general terminology, staking variables, and more, please refer to the Staking on Moonbeam page.

The DPoS system is powered by the parachain staking pallet, allowing token holders (delegators) to express exactly which collator candidates they would like to support and with what quantity of stake. The design of the parachain staking pallet is such that it enforces shared risk/reward on chain between delegators and candidates.

Some of the functionality of the parachain staking pallet is also available through a staking precompile. The precompile is a Solidity interface that enables you to perform staking actions through the Ethereum API. Please refer to the Staking Precompile guide for more information.

This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the parachain staking pallet.

Exit Delays

Some of the staking pallet extrinsics include exit delays that you must wait before the request can be executed. The exit delays to note are as follows:

Variable Value
Decrease candidate bond 28 rounds (168 hours)
Decrease delegator bond 28 rounds (168 hours)
Revoke delegation 28 rounds (168 hours)
Leave candidates 28 rounds (168 hours)
Leave delegators 28 rounds (168 hours)
Variable Value
Decrease candidate bond 24 rounds (48 hours)
Decrease delegator bond 24 rounds (48 hours)
Revoke delegation 24 rounds (48 hours)
Leave candidates 24 rounds (48 hours)
Leave delegators 24 rounds (48 hours)
Variable Value
Decrease candidate bond 2 rounds (4 hours)
Decrease delegator bond 2 rounds (4 hours)
Revoke delegation 2 rounds (4 hours)
Leave candidates 2 rounds (4 hours)
Leave delegators 2 rounds (4 hours)

Parachain Staking Pallet Interface

Extrinsics

The parachain staking pallet provides the following extrinsics (functions):

cancelCandidateBondLess() - cancels a pending scheduled request to decrease a candidate's self bond amount

None

 import { ApiPromise, WsProvider } from '@polkadot/api';
 import { Keyring } from '@polkadot/keyring';

 const main = async () => {
   // Initialize the API
   const api = await ApiPromise.create({
     provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
   });

   // Initialize the keyring with ethereum type
   const keyring = new Keyring({ type: 'ethereum' });

   try {
     // Setup account from private key
     const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
     const account = keyring.addFromUri(PRIVATE_KEY);

     console.log('Account address:', account.address);

     // Create the cancel transaction
     const tx = api.tx.parachainStaking.cancelCandidateBondLess();

     // Sign and send the transaction
     await tx.signAndSend(account, ({ status, events }) => {
       if (status.isInBlock) {
         console.log(`Transaction included in block hash: ${status.asInBlock}`);

         // Process events
         events.forEach(({ event }) => {
           const { section, method, data } = event;
           console.log(`\t${section}.${method}:`, data.toString());

           // Handle any failures
           if (section === 'system' && method === 'ExtrinsicFailed') {
             const [dispatchError] = data;
             let errorInfo;

             if (dispatchError.isModule) {
               const decoded = api.registry.findMetaError(
                 dispatchError.asModule
               );
               errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
             } else {
               errorInfo = dispatchError.toString();
             }
             console.error('Failure reason:', errorInfo);
           }

           // Log successful cancellation
           if (
             section === 'parachainStaking' &&
             method === 'CancelledCandidateBondLess'
           ) {
             const [candidate, amount, executeRound] = data;
             console.log('\nSuccessfully cancelled bond decrease request!');
             console.log('Candidate:', candidate.toString());
             console.log('Amount that was to be decreased:', amount.toString());
             console.log(
               'Round it was to be executed:',
               executeRound.toString()
             );
           }
         });

         process.exit(0);
       }
     });
   } catch (error) {
     console.error('Error in cancelling candidate bond less:', error);
     process.exit(1);
   }
 };

 // Execute the script
 main().catch((error) => {
   console.error('Script error:', error);
   process.exit(1);
 });
cancelDelegationRequest(candidate) - cancels any pending delegation requests provided the address of a candidate
  • candidate - The address of the relevant collator
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup delegator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const delegator = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address for which to cancel the delegation request
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    console.log('Delegator address:', delegator.address);
    console.log('Candidate address:', candidateAddress);

    // Create the cancel delegation request transaction
    const tx =
      api.tx.parachainStaking.cancelDelegationRequest(candidateAddress);

    // Sign and send the transaction
    await tx.signAndSend(delegator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(`Transaction included in block hash: ${status.asInBlock}`);

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful cancellation
          if (
            section === 'parachainStaking' &&
            method === 'CancelledDelegationRequest'
          ) {
            const [delegatorAddress, scheduledRequest, candidateAddress] = data;
            console.log('\nSuccessfully cancelled delegation request!');
            console.log('Delegator:', delegatorAddress.toString());
            console.log('Candidate:', candidateAddress.toString());

            const request = scheduledRequest.toJSON();
            console.log('Request details:');
            console.log('- Execution round:', request.whenExecutable);
            if (request.action.decrease) {
              console.log('- Action: Decrease by', request.action.decrease);
            } else if (request.action.revoke) {
              console.log('- Action: Revoke amount', request.action.revoke);
            }
          }
        });

        process.exit(0);
      }
    });
  } catch (error) {
    console.error('Error in cancelling delegation request:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
cancelLeaveCandidates(candidateCount) - cancels a candidate's pending scheduled request to leave the candidate pool given the current number of candidates in the pool
  • candidateCount - The current number of collator candidates in the pool
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup candidate account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const candidate = keyring.addFromUri(PRIVATE_KEY);

    // First, get the current candidate count from the chain
    const candidates = await api.query.parachainStaking.candidatePool();
    const candidateCount = candidates.length;

    console.log('Candidate address:', candidate.address);
    console.log('Current candidate count:', candidateCount);

    // Create the cancel leave candidates transaction
    const tx = api.tx.parachainStaking.cancelLeaveCandidates(candidateCount);

    // Sign and send the transaction
    await tx.signAndSend(candidate, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(`Transaction included in block hash: ${status.asInBlock}`);

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful cancellation
          if (
            section === 'parachainStaking' &&
            method === 'CancelledLeaveCandidates'
          ) {
            const [candidateAddress, candidateCount] = data;
            console.log('\nSuccessfully cancelled leave candidates request!');
            console.log('Candidate:', candidateAddress.toString());
            console.log(
              'Candidate count at cancellation:',
              candidateCount.toString()
            );
          }
        });

        process.exit(0);
      }
    });
  } catch (error) {
    console.error('Error in cancelling leave candidates request:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
candidateBondMore(more) - request to increase a candidate's self bond by a specified amount
  • more - The amount of WEI by which to increase the candidate's self bond
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup candidate account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const candidate = keyring.addFromUri(PRIVATE_KEY);

    // Amount to increase bond by (e.g., 1 DEV = 1_000_000_000_000_000_000)
    const moreBond = '1000000000000000000';

    console.log('Candidate address:', candidate.address);
    console.log('Increasing bond by:', moreBond, 'Wei (1 DEV)');

    // Query current bond before increasing
    const candidateInfo = await api.query.parachainStaking.candidateInfo(
      candidate.address
    );
    if (candidateInfo.isSome) {
      console.log('Current bond:', candidateInfo.unwrap().bond.toString());
    }

    // Create the increase bond transaction
    const tx = api.tx.parachainStaking.candidateBondMore(moreBond);

    // Sign and send the transaction
    await tx.signAndSend(candidate, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(`Transaction included in block hash: ${status.asInBlock}`);

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful bond increase
          if (
            section === 'parachainStaking' &&
            method === 'CandidateBondedMore'
          ) {
            const [candidateAddress, amount, newTotal] = data;
            console.log('\nSuccessfully increased candidate bond!');
            console.log('Candidate:', candidateAddress.toString());
            console.log('Amount increased:', amount.toString());
            console.log('New total bond:', newTotal.toString());
          }
        });

        // Query updated bond after transaction
        api.query.parachainStaking
          .candidateInfo(candidate.address)
          .then((newInfo) => {
            if (newInfo.isSome) {
              console.log('\nUpdated bond:', newInfo.unwrap().bond.toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in increasing candidate bond:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
delegate(candidate, amount, candidateDelegationCount, delegationCount) - deprecated as of runtime 2400 - request to add a delegation to a specific candidate for a given amount. Use the delegateWithAutoCompound extrinsic instead
  • candidate - The address of the collator candidate to delegate to (H160 format address, e.g., '0x123...')
  • amount - The amount to delegate in Wei (e.g., 1 DEV = 1_000_000_000_000_000_000 Wei)
  • candidateDelegationCount - The current number of delegations to the candidate
  • delegationCount - The current number of delegations from the delegator

Deprecated as of runtime 2400 Use the delegateWithAutoCompound extrinsic instead

delegateWithAutoCompound(candidate, amount, autoCompound, candidateDelegationCount, candidateAutoCompoundingDelegationCount, delegationCount) - delegates a collator candidate and sets the percentage of rewards to auto-compound given an integer (no decimals) for the amount between 0-100. If the caller is not a delegator, this function adds them to the set of delegators. If the caller is already a delegator, then it adjusts their delegation amount
  • candidate - The collator's address you want to delegate to
  • amount - The amount to delegate (in Wei, e.g. 1000000000000000000 for 1 DEV)
  • autoCompound - The percentage of rewards to automatically compound (0-100)
  • candidateDelegationCount - The current number of delegations to the collator
  • candidateAutoCompoundingDelegationCount - The current number of auto-compounding delegations for the collator
  • delegationCount - The total number of delegations you have across all collators
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup delegator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const delegator = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address to delegate to
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Amount to delegate (e.g., 1 DEV = 1_000_000_000_000_000_000)
    const amount = '1000000000000000000';

    // Auto-compound percentage (0-100)
    const autoCompound = 50; // 50% of rewards will be auto-compounded

    // Get current delegation counts
    const candidateInfo =
      await api.query.parachainStaking.candidateInfo(candidateAddress);
    const delegatorState = await api.query.parachainStaking.delegatorState(
      delegator.address
    );
    const autoCompoundDelegations =
      await api.query.parachainStaking.autoCompoundingDelegations(
        candidateAddress
      );

    // Get delegation counts
    let candidateDelegationCount = 0;
    let candidateAutoCompoundingDelegationCount = 0;
    let delegationCount = 0;

    if (candidateInfo.isSome) {
      candidateDelegationCount = candidateInfo.unwrap().delegationCount;
    }

    candidateAutoCompoundingDelegationCount = autoCompoundDelegations.length;

    if (delegatorState.isSome) {
      delegationCount = delegatorState.unwrap().delegations.length;
    }

    console.log('Delegation Details:');
    console.log('Delegator address:', delegator.address);
    console.log('Candidate address:', candidateAddress);
    console.log('Delegation amount:', amount, 'Wei (1 DEV)');
    console.log('Auto-compound percentage:', autoCompound, '%');
    console.log('\nCurrent Stats:');
    console.log(
      'Candidate delegation count:',
      candidateDelegationCount.toString()
    );
    console.log(
      'Candidate auto-compounding delegation count:',
      candidateAutoCompoundingDelegationCount.toString()
    );
    console.log('Delegator total delegations:', delegationCount.toString());

    // Create the delegate with auto-compound transaction
    const tx = api.tx.parachainStaking.delegateWithAutoCompound(
      candidateAddress,
      amount,
      autoCompound,
      candidateDelegationCount,
      candidateAutoCompoundingDelegationCount,
      delegationCount
    );

    // Sign and send the transaction
    await tx.signAndSend(delegator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful delegation
          if (section === 'parachainStaking' && method === 'Delegation') {
            const [delegator, amount, candidate, autoCompound] = data;
            console.log('\nSuccessfully delegated with auto-compound!');
            console.log('Delegator:', delegator.toString());
            console.log('Candidate:', candidate.toString());
            console.log('Amount:', amount.toString());
            console.log(
              'Auto-compound percentage:',
              autoCompound.toString(),
              '%'
            );
          }
        });

        process.exit(0);
      }
    });
  } catch (error) {
    console.error('Error in delegation with auto-compound:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
delegatorBondMore(candidate, more) - request to increase a delegator's amount delegated for a specific candidate
  • candidate - the address of the respective collator
  • more - The amount you want to increase your delegation by (in Wei, e.g. 1000000000000000000 for 1 DEV)
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup delegator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const delegator = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address for which to increase delegation
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Amount to increase delegation by (e.g., 1 DEV = 1_000_000_000_000_000_000)
    const moreBond = '1000000000000000000';

    // Query current delegation before increasing
    const delegatorState = await api.query.parachainStaking.delegatorState(
      delegator.address
    );

    console.log('Current Delegation Info:');
    console.log('Delegator address:', delegator.address);
    console.log('Candidate address:', candidateAddress);

    if (delegatorState.isSome) {
      const state = delegatorState.unwrap();
      const currentDelegation = state.delegations.find(
        (d) =>
          d.owner.toString().toLowerCase() === candidateAddress.toLowerCase()
      );
      if (currentDelegation) {
        console.log(
          'Current delegation amount:',
          currentDelegation.amount.toString()
        );
      }
    }

    console.log('Amount to increase by:', moreBond, 'Wei (1 DEV)');

    // Create the increase delegation transaction
    const tx = api.tx.parachainStaking.delegatorBondMore(
      candidateAddress,
      moreBond
    );

    // Sign and send the transaction
    await tx.signAndSend(delegator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful bond increase
          if (
            section === 'parachainStaking' &&
            method === 'DelegationIncreased'
          ) {
            const [delegator, candidate, amount, inTopDelegations] = data;
            console.log('\nSuccessfully increased delegation!');
            console.log('Delegator:', delegator.toString());
            console.log('Candidate:', candidate.toString());
            console.log('Amount increased by:', amount.toString());
            console.log('In top delegations:', inTopDelegations.toString());
          }
        });

        // Query updated delegation after transaction
        api.query.parachainStaking
          .delegatorState(delegator.address)
          .then((newState) => {
            if (newState.isSome) {
              const state = newState.unwrap();
              const updatedDelegation = state.delegations.find(
                (d) =>
                  d.owner.toString().toLowerCase() ===
                  candidateAddress.toLowerCase()
              );
              if (updatedDelegation) {
                console.log(
                  '\nNew delegation amount:',
                  updatedDelegation.amount.toString()
                );
              }
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in increasing delegation:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
executeCandidateBondLess(candidate) - executes any scheduled due requests to decrease a candidate's self bond amount
  • candidate - the address of the respective collator
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup account from private key (this can be any account, doesn't need to be the candidate)
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const executor = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address whose bond decrease should be executed
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Query current candidate info before execution
    const candidateInfo =
      await api.query.parachainStaking.candidateInfo(candidateAddress);

    console.log('Execution Details:');
    console.log('Executor address:', executor.address);
    console.log('Candidate address:', candidateAddress);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCandidate current bond:', info.bond.toString());
      console.log('Candidate status:', info.status.toString());
    }

    // Create the execute bond decrease transaction
    const tx =
      api.tx.parachainStaking.executeCandidateBondLess(candidateAddress);

    // Sign and send the transaction
    await tx.signAndSend(executor, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful execution
          if (
            section === 'parachainStaking' &&
            method === 'CandidateBondedLess'
          ) {
            const [candidate, amount, newBond] = data;
            console.log('\nSuccessfully executed candidate bond decrease!');
            console.log('Candidate:', candidate.toString());
            console.log('Amount decreased:', amount.toString());
            console.log('New bond amount:', newBond.toString());
          }
        });

        // Query updated candidate info after execution
        api.query.parachainStaking
          .candidateInfo(candidateAddress)
          .then((newInfo) => {
            if (newInfo.isSome) {
              const info = newInfo.unwrap();
              console.log('\nUpdated candidate bond:', info.bond.toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in executing candidate bond decrease:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
executeDelegationRequest(delegator, candidate) - executes any scheduled due delegation requests for a specific delegator provided the address of the candidate
  • delegator - The address of the delegator who made the delegation request
  • candidate - The collator's address associated with the delegation request
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup executor account from private key (this can be any account)
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const executor = keyring.addFromUri(PRIVATE_KEY);

    // The delegator's address whose request will be executed
    const delegatorAddress = 'INSERT_DELEGATOR_ADDRESS';

    // The candidate's address for the delegation request
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Query current delegation info before execution
    const delegatorState =
      await api.query.parachainStaking.delegatorState(delegatorAddress);

    console.log('Execution Details:');
    console.log('Executor address:', executor.address);
    console.log('Delegator address:', delegatorAddress);
    console.log('Candidate address:', candidateAddress);

    if (delegatorState.isSome) {
      const state = delegatorState.unwrap();
      const currentDelegation = state.delegations.find(
        (d) =>
          d.owner.toString().toLowerCase() === candidateAddress.toLowerCase()
      );
      if (currentDelegation) {
        console.log(
          '\nCurrent delegation amount:',
          currentDelegation.amount.toString()
        );
      }
    }

    // Create the execute delegation request transaction
    const tx = api.tx.parachainStaking.executeDelegationRequest(
      delegatorAddress,
      candidateAddress
    );

    // Sign and send the transaction
    await tx.signAndSend(executor, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful delegation decrease/revoke
          if (
            section === 'parachainStaking' &&
            method === 'DelegationDecreased'
          ) {
            const [delegator, candidate, amount, inTopDelegations] = data;
            console.log('\nSuccessfully executed delegation decrease!');
            console.log('Delegator:', delegator.toString());
            console.log('Candidate:', candidate.toString());
            console.log('Amount decreased:', amount.toString());
            console.log('In top delegations:', inTopDelegations.toString());
          }

          if (
            section === 'parachainStaking' &&
            method === 'DelegationRevoked'
          ) {
            const [delegator, candidate, amount] = data;
            console.log('\nSuccessfully executed delegation revocation!');
            console.log('Delegator:', delegator.toString());
            console.log('Candidate:', candidate.toString());
            console.log('Amount revoked:', amount.toString());
          }
        });

        // Query updated delegation info after execution
        api.query.parachainStaking
          .delegatorState(delegatorAddress)
          .then((newState) => {
            if (newState.isSome) {
              const state = newState.unwrap();
              const updatedDelegation = state.delegations.find(
                (d) =>
                  d.owner.toString().toLowerCase() ===
                  candidateAddress.toLowerCase()
              );
              if (updatedDelegation) {
                console.log(
                  '\nNew delegation amount:',
                  updatedDelegation.amount.toString()
                );
              } else {
                console.log('\nDelegation has been fully revoked');
              }
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in executing delegation request:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
executeLeaveCandidates(candidate, candidateDelegationCount) - executes any scheduled due requests to leave the set of collator candidates
  • candidate - The address of the collator who requested to leave the candidate pool
  • candidateDelegationCount - The current number of delegations for the leaving candidate
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup executor account from private key (this can be any account)
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const executor = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address who is scheduled to leave
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Get candidate information and delegation count
    const candidateInfo =
      await api.query.parachainStaking.candidateInfo(candidateAddress);
    let candidateDelegationCount = 0;

    console.log('Execution Details:');
    console.log('Executor address:', executor.address);
    console.log('Candidate address:', candidateAddress);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      candidateDelegationCount = info.delegationCount;
      console.log('\nCandidate Information:');
      console.log('Current bond:', info.bond.toString());
      console.log('Delegation count:', candidateDelegationCount.toString());
      console.log('Status:', info.status.toString());
    } else {
      console.log('\nWarning: Candidate info not found');
    }

    // Create the execute leave candidates transaction
    const tx = api.tx.parachainStaking.executeLeaveCandidates(
      candidateAddress,
      candidateDelegationCount
    );

    // Sign and send the transaction
    await tx.signAndSend(executor, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful execution of leave request
          if (section === 'parachainStaking' && method === 'CandidateLeft') {
            const [candidate, amount, remainingCount] = data;
            console.log('\nSuccessfully executed leave candidates request!');
            console.log('Candidate:', candidate.toString());
            console.log('Amount unlocked:', amount.toString());
            console.log('Remaining candidates:', remainingCount.toString());
          }
        });

        // Query final candidate state
        api.query.parachainStaking
          .candidateInfo(candidateAddress)
          .then((finalState) => {
            if (finalState.isNone) {
              console.log(
                '\nCandidate has been successfully removed from the candidate pool'
              );
            } else {
              console.log('\nWarning: Candidate still exists in the pool');
              console.log('Current state:', finalState.unwrap().toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in executing leave candidates request:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
goOffline() - allows a collator candidate to temporarily leave the pool of candidates without unbonding

None

import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup collator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const collator = keyring.addFromUri(PRIVATE_KEY);

    // Query current collator info before going offline
    const candidateInfo = await api.query.parachainStaking.candidateInfo(
      collator.address
    );

    console.log('Collator Details:');
    console.log('Collator address:', collator.address);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCurrent Status:');
      console.log('Bond:', info.bond.toString());
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Status:', info.status.toString());
    } else {
      console.log('\nWarning: Not found in candidate pool');
      process.exit(1);
    }

    // Create the go offline transaction
    const tx = api.tx.parachainStaking.goOffline();

    // Sign and send the transaction
    await tx.signAndSend(collator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful offline status change
          if (
            section === 'parachainStaking' &&
            method === 'CandidateWentOffline'
          ) {
            const [collatorAccount] = data;
            console.log('\nSuccessfully went offline!');
            console.log('Collator:', collatorAccount.toString());
          }
        });

        // Query final collator state
        api.query.parachainStaking
          .candidateInfo(collator.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const info = finalState.unwrap();
              console.log('\nUpdated Status:');
              console.log('Bond:', info.bond.toString());
              console.log('Delegation Count:', info.delegationCount.toString());
              console.log('Status:', info.status.toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in going offline:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
goOnline() - allows a collator candidate to rejoin the pool of candidates after previously calling goOffline()

None

import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup collator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const collator = keyring.addFromUri(PRIVATE_KEY);

    // Query current collator info before going online
    const candidateInfo = await api.query.parachainStaking.candidateInfo(
      collator.address
    );

    console.log('Collator Details:');
    console.log('Collator address:', collator.address);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCurrent Status:');
      console.log('Bond:', info.bond.toString());
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Status:', info.status.toString());
    } else {
      console.log('\nWarning: Not found in candidate pool');
      process.exit(1);
    }

    // Create the go online transaction
    const tx = api.tx.parachainStaking.goOnline();

    // Sign and send the transaction
    await tx.signAndSend(collator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful online status change
          if (
            section === 'parachainStaking' &&
            method === 'CandidateBackOnline'
          ) {
            const [collatorAccount] = data;
            console.log('\nSuccessfully went back online!');
            console.log('Collator:', collatorAccount.toString());
          }
        });

        // Query final collator state
        api.query.parachainStaking
          .candidateInfo(collator.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const info = finalState.unwrap();
              console.log('\nUpdated Status:');
              console.log('Bond:', info.bond.toString());
              console.log('Delegation Count:', info.delegationCount.toString());
              console.log('Status:', info.status.toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in going online:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
joinCandidates(bond, candidateCount) - request to join the set of collator candidates with a specified bond amount and provided the current candidate count
  • bond - The amount to stake as collator bond (in Wei, e.g. 500000000000000000000 for 500 DEV)
  • candidateCount - The total number of candidates currently in the candidate pool
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const account = keyring.addFromUri(PRIVATE_KEY);

    // Set bond amount to 500 DEV (multiply by 10^18 for proper decimals)
    const bondAmount = '500000000000000000000';

    // Get current candidate count
    const candidates = await api.query.parachainStaking.candidatePool();
    const candidateCount = candidates.length;

    // Check account balance
    const balance = await api.query.system.account(account.address);

    console.log('Join Candidates Details:');
    console.log('Account address:', account.address);
    console.log('Current free balance:', balance.data.free.toString());
    console.log('Bond amount:', bondAmount, '(501 DEV)');
    console.log('Current candidate count:', candidateCount);

    // Create the join candidates transaction
    const tx = api.tx.parachainStaking.joinCandidates(
      bondAmount,
      candidateCount
    );

    // Sign and send the transaction
    await tx.signAndSend(account, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful joining
          if (
            section === 'parachainStaking' &&
            method === 'JoinedCollatorCandidates'
          ) {
            const [account, amountLocked, newTotalAmountLocked] = data;
            console.log('\nSuccessfully joined collator candidates!');
            console.log('Account:', account.toString());
            console.log('Amount locked:', amountLocked.toString());
            console.log(
              'New total amount locked:',
              newTotalAmountLocked.toString()
            );
          }
        });

        // Query final candidate state
        api.query.parachainStaking
          .candidateInfo(account.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const info = finalState.unwrap();
              console.log('\nNew Candidate Status:');
              console.log('Bond:', info.bond.toString());
              console.log('Delegation Count:', info.delegationCount.toString());
              console.log('Status:', info.status.toString());
            }

            // Get updated candidate count
            api.query.parachainStaking.candidatePool().then((newCandidates) => {
              console.log('New candidate count:', newCandidates.length);
              process.exit(0);
            });
          });
      }
    });
  } catch (error) {
    console.error('Error in joining candidates:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
notifyInactiveCollator(collator) - marks a collator as inactive if they have not been producing blocks for the maximum number of offline rounds, as returned by the maxOfflineRounds pallet constant
  • collator - the address of the collator to be notified
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup notifier account from private key (this can be any account)
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const notifier = keyring.addFromUri(PRIVATE_KEY);

    // The potentially inactive collator's address
    const inactiveCollator = 'INSERT_COLLATOR_ADDRESS';

    // Get max offline rounds from constants
    const maxOfflineRounds = await api.consts.parachainStaking.maxOfflineRounds;

    // Get current round info
    const round = await api.query.parachainStaking.round();

    // Get collator info
    const collatorInfo =
      await api.query.parachainStaking.candidateInfo(inactiveCollator);

    console.log('Notify Inactive Collator Details:');
    console.log('Notifier address:', notifier.address);
    console.log('Inactive collator address:', inactiveCollator);
    console.log('Maximum allowed offline rounds:', maxOfflineRounds.toString());
    console.log('Current round:', round.current.toString());

    if (collatorInfo.isSome) {
      const info = collatorInfo.unwrap();
      console.log('\nCollator Current Status:');
      console.log('Bond:', info.bond.toString());
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Status:', info.status.toString());
    }

    // Create the notify inactive collator transaction
    const tx = api.tx.parachainStaking.notifyInactiveCollator(inactiveCollator);

    // Sign and send the transaction
    await tx.signAndSend(notifier, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful notification
          if (
            section === 'parachainStaking' &&
            method === 'CollatorWentOffline'
          ) {
            const [collatorAccount] = data;
            console.log('\nSuccessfully notified inactive collator!');
            console.log('Collator:', collatorAccount.toString());
          }
        });

        // Query final collator state
        api.query.parachainStaking
          .candidateInfo(inactiveCollator)
          .then((finalState) => {
            if (finalState.isSome) {
              const info = finalState.unwrap();
              console.log('\nUpdated Collator Status:');
              console.log('Bond:', info.bond.toString());
              console.log('Delegation Count:', info.delegationCount.toString());
              console.log('Status:', info.status.toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in notifying inactive collator:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
scheduleCandidateBondLess(less) - schedules a request to decrease a candidate's self bond by a specified amount. There is an exit delay that must be waited before you can execute the request via the executeCandidateBondLess extrinsic
  • less - The amount you want to decrease your delegation by (in Wei, e.g. 1000000000000000000 for 1 DEV)
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup candidate account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const candidate = keyring.addFromUri(PRIVATE_KEY);

    // Amount to decrease bond by (e.g., 1 DEV = 1_000_000_000_000_000_000)
    const decreaseAmount = '1000000000000000000'; // 1 DEV

    // Get current candidate info
    const candidateInfo = await api.query.parachainStaking.candidateInfo(
      candidate.address
    );

    console.log('Schedule Bond Decrease Details:');
    console.log('Candidate address:', candidate.address);
    console.log('Bond decrease amount:', decreaseAmount, 'Wei (1 DEV)');

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCurrent Candidate Status:');
      console.log('Current bond:', info.bond.toString());
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Status:', info.status.toString());
    } else {
      console.log('\nWarning: Account is not a candidate');
      process.exit(1);
    }

    // Create the schedule bond decrease transaction
    const tx =
      api.tx.parachainStaking.scheduleCandidateBondLess(decreaseAmount);

    // Get current round
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    // Sign and send the transaction
    await tx.signAndSend(candidate, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful scheduling
          if (
            section === 'parachainStaking' &&
            method === 'CandidateBondLessRequested'
          ) {
            const [candidate, amountToDecrease, executeRound] = data;
            console.log('\nSuccessfully scheduled bond decrease!');
            console.log('Candidate:', candidate.toString());
            console.log('Amount to decrease:', amountToDecrease.toString());
            console.log('Execute round:', executeRound.toString());
            console.log(
              `\nNote: You must wait until round ${executeRound.toString()} to execute the decrease request`
            );
          }
        });

        // Query final candidate state
        api.query.parachainStaking
          .candidateInfo(candidate.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const info = finalState.unwrap();
              console.log('\nUpdated Candidate Status:');
              console.log('Bond:', info.bond.toString());
              console.log('Delegation Count:', info.delegationCount.toString());
              console.log('Status:', info.status.toString());
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in scheduling bond decrease:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
scheduleDelegatorBondLess(candidate, less) - schedules a request for a delegator to bond less with respect to a specific candidate. There is an exit delay that must be waited before you can execute the request via the executeDelegationRequest extrinsic
  • candidate - The collator's address for which you want to decrease your delegation
  • less - The amount you want to decrease your delegation by (in Wei, e.g. 1000000000000000000 for 1 DEV)
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup delegator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const delegator = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address to decrease delegation for
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Amount to decrease delegation by (e.g., 1 DEV = 1_000_000_000_000_000_000)
    const decreaseAmount = '1000000000000000000'; // 1 DEV

    // Get current delegation info
    const delegatorState = await api.query.parachainStaking.delegatorState(
      delegator.address
    );

    console.log('Schedule Delegation Decrease Details:');
    console.log('Delegator address:', delegator.address);
    console.log('Candidate address:', candidateAddress);
    console.log('Amount to decrease:', decreaseAmount, 'Wei (1 DEV)');

    if (delegatorState.isSome) {
      const state = delegatorState.unwrap();
      const currentDelegation = state.delegations.find(
        (d) =>
          d.owner.toString().toLowerCase() === candidateAddress.toLowerCase()
      );
      if (currentDelegation) {
        console.log(
          '\nCurrent Delegation Amount:',
          currentDelegation.amount.toString()
        );
      } else {
        console.log(
          '\nWarning: No existing delegation found for this candidate'
        );
        process.exit(1);
      }
    } else {
      console.log('\nWarning: Account is not a delegator');
      process.exit(1);
    }

    // Get current round
    const round = await api.query.parachainStaking.round();
    console.log('Current round:', round.current.toString());

    // Create the schedule decrease transaction
    const tx = api.tx.parachainStaking.scheduleDelegatorBondLess(
      candidateAddress,
      decreaseAmount
    );

    // Sign and send the transaction
    await tx.signAndSend(delegator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful scheduling
          if (
            section === 'parachainStaking' &&
            method === 'DelegationDecreaseScheduled'
          ) {
            const [delegator, candidate, amountToDecrease, executeRound] = data;
            console.log('\nSuccessfully scheduled delegation decrease!');
            console.log('Delegator:', delegator.toString());
            console.log('Candidate:', candidate.toString());
            console.log('Amount to decrease:', amountToDecrease.toString());
            console.log('Execute round:', executeRound.toString());
            console.log(
              `\nNote: You must wait until round ${executeRound.toString()} to execute the decrease request`
            );
          }
        });

        // Query final delegation state
        api.query.parachainStaking
          .delegatorState(delegator.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const state = finalState.unwrap();
              const updatedDelegation = state.delegations.find(
                (d) =>
                  d.owner.toString().toLowerCase() ===
                  candidateAddress.toLowerCase()
              );
              if (updatedDelegation) {
                console.log('\nCurrent Delegation Status:');
                console.log('Amount:', updatedDelegation.amount.toString());
                console.log(
                  'Note: Amount will decrease after execution in the scheduled round'
                );
              }
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in scheduling delegation decrease:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
scheduleLeaveCandidates(candidateCount) - schedules a request for a candidate to remove themselves from the candidate pool. There is an exit delay that must be waited before you can execute the request via the executeLeaveCandidates extrinsic
  • candidateCount - The total number of candidates currently in the candidate pool
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup collator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const collator = keyring.addFromUri(PRIVATE_KEY);

    // Get current candidate pool information
    const candidates = await api.query.parachainStaking.candidatePool();
    const candidateCount = candidates.length;

    // Get current candidate info
    const candidateInfo = await api.query.parachainStaking.candidateInfo(
      collator.address
    );

    console.log('Schedule Leave Details:');
    console.log('Collator address:', collator.address);
    console.log('Current candidate count:', candidateCount);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCurrent Candidate Status:');
      console.log('Bond:', info.bond.toString());
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Status:', info.status.toString());
    } else {
      console.log('\nWarning: Account is not a candidate');
      process.exit(1);
    }

    // Create the schedule leave transaction
    const tx = api.tx.parachainStaking.scheduleLeaveCandidates(candidateCount);

    // Get the current round
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    // Sign and send the transaction
    await tx.signAndSend(collator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful scheduling
          if (
            section === 'parachainStaking' &&
            method === 'CandidateScheduledExit'
          ) {
            const [round, candidate, scheduledExit] = data;
            console.log('\nSuccessfully scheduled leave candidates!');
            console.log('Candidate:', candidate.toString());
            console.log('Current round:', round.toString());
            console.log('Scheduled exit round:', scheduledExit.toString());
            console.log(
              `\nNote: You must wait until round ${scheduledExit.toString()} to execute the leave request`
            );
          }
        });

        // Query final candidate state
        api.query.parachainStaking
          .candidateInfo(collator.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const info = finalState.unwrap();
              console.log('\nUpdated Candidate Status:');
              console.log('Bond:', info.bond.toString());
              console.log('Delegation Count:', info.delegationCount.toString());
              console.log(
                'Status:',
                info.status.toString(),
                '(Leaving status shows the exit round)'
              );
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in scheduling leave candidates:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
scheduleRevokeDelegation(collator) - schedules a request to revoke a delegation given the address of a candidate. There is an exit delay that must be waited before you can execute the request via the executeDelegationRequest extrinsic
  • collator - The collator's address from which you want to revoke your delegation
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup delegator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const delegator = keyring.addFromUri(PRIVATE_KEY);

    // The collator's address to revoke delegation from
    const collatorAddress = 'INSERT_COLLATOR_ADDRESS';

    // Get current delegation info
    const delegatorState = await api.query.parachainStaking.delegatorState(
      delegator.address
    );

    console.log('Schedule Revoke Delegation Details:');
    console.log('Delegator address:', delegator.address);
    console.log('Collator address:', collatorAddress);

    if (delegatorState.isSome) {
      const state = delegatorState.unwrap();
      const currentDelegation = state.delegations.find(
        (d) =>
          d.owner.toString().toLowerCase() === collatorAddress.toLowerCase()
      );
      if (currentDelegation) {
        console.log(
          '\nCurrent Delegation Amount:',
          currentDelegation.amount.toString()
        );
      } else {
        console.log(
          '\nWarning: No existing delegation found for this collator'
        );
        process.exit(1);
      }
    } else {
      console.log('\nWarning: Account is not a delegator');
      process.exit(1);
    }

    // Get current round
    const round = await api.query.parachainStaking.round();
    console.log('Current round:', round.current.toString());

    // Create the schedule revoke transaction
    const tx =
      api.tx.parachainStaking.scheduleRevokeDelegation(collatorAddress);

    // Sign and send the transaction
    await tx.signAndSend(delegator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful scheduling
          if (
            section === 'parachainStaking' &&
            method === 'DelegationRevocationScheduled'
          ) {
            const [round, delegator, candidate, executeRound] = data;
            console.log('\nSuccessfully scheduled delegation revocation!');
            console.log('Round:', round.toString());
            console.log('Delegator:', delegator.toString());
            console.log('Collator:', candidate.toString());
            console.log('Execute round:', executeRound.toString());
            console.log(
              `\nNote: You must wait until round ${executeRound.toString()} to execute the revocation request`
            );
          }
        });

        // Query final delegation state
        api.query.parachainStaking
          .delegatorState(delegator.address)
          .then((finalState) => {
            if (finalState.isSome) {
              const state = finalState.unwrap();
              const updatedDelegation = state.delegations.find(
                (d) =>
                  d.owner.toString().toLowerCase() ===
                  collatorAddress.toLowerCase()
              );
              if (updatedDelegation) {
                console.log('\nCurrent Delegation Status:');
                console.log('Amount:', updatedDelegation.amount.toString());
                console.log(
                  'Note: Delegation will be fully revoked after execution in the scheduled round'
                );
              }
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in scheduling delegation revocation:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
setAutoCompound(candidate, value, candidateAutoCompoundingDelegationCountHint, delegationCountHint) - sets the percentage of rewards to be auto-compounded for an existing delegation given an integer (no decimals) for the value between 0-100
  • candidate - The collator's address you're delegating to
  • value - Auto-compound percentage (0-100)
  • candidateAutoCompoundingDelegationCountHint - Number of auto-compounding delegations for this collator
  • delegationCountHint - Total number of delegations you have across all collators
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  // Initialize the keyring with ethereum type
  const keyring = new Keyring({ type: 'ethereum' });

  try {
    // Setup delegator account from private key
    const PRIVATE_KEY = 'INSERT_PRIVATE_KEY';
    const delegator = keyring.addFromUri(PRIVATE_KEY);

    // The candidate's address for the delegation
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    // Auto-compound percentage (0-100)
    const autoCompoundValue = 50; // 50% of rewards will be auto-compounded

    // Get auto-compounding delegations count
    const autoCompoundDelegations =
      await api.query.parachainStaking.autoCompoundingDelegations(
        candidateAddress
      );
    const candidateAutoCompoundingDelegationCount =
      autoCompoundDelegations.length;

    // Get delegator state for delegation count
    const delegatorState = await api.query.parachainStaking.delegatorState(
      delegator.address
    );
    let delegationCount = 0;

    console.log('Set Auto-Compound Details:');
    console.log('Delegator address:', delegator.address);
    console.log('Candidate address:', candidateAddress);
    console.log('Auto-compound percentage:', autoCompoundValue, '%');

    if (delegatorState.isSome) {
      const state = delegatorState.unwrap();
      delegationCount = state.delegations.length;
      const currentDelegation = state.delegations.find(
        (d) =>
          d.owner.toString().toLowerCase() === candidateAddress.toLowerCase()
      );
      if (currentDelegation) {
        console.log(
          '\nCurrent Delegation Amount:',
          currentDelegation.amount.toString()
        );
      } else {
        console.log(
          '\nWarning: No existing delegation found for this candidate'
        );
        process.exit(1);
      }
    } else {
      console.log('\nWarning: Account is not a delegator');
      process.exit(1);
    }

    console.log('\nDelegation Counts:');
    console.log(
      'Auto-compounding delegations:',
      candidateAutoCompoundingDelegationCount
    );
    console.log('Total delegations:', delegationCount);

    // Create the set auto-compound transaction
    const tx = api.tx.parachainStaking.setAutoCompound(
      candidateAddress,
      autoCompoundValue,
      candidateAutoCompoundingDelegationCount,
      delegationCount
    );

    // Sign and send the transaction
    await tx.signAndSend(delegator, ({ status, events }) => {
      if (status.isInBlock) {
        console.log(
          `\nTransaction included in block hash: ${status.asInBlock}`
        );

        // Process events
        events.forEach(({ event }) => {
          const { section, method, data } = event;
          console.log(`\t${section}.${method}:`, data.toString());

          // Handle any failures
          if (section === 'system' && method === 'ExtrinsicFailed') {
            const [dispatchError] = data;
            let errorInfo;

            if (dispatchError.isModule) {
              const decoded = api.registry.findMetaError(
                dispatchError.asModule
              );
              errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`;
            } else {
              errorInfo = dispatchError.toString();
            }
            console.error('Failure reason:', errorInfo);
          }

          // Log successful auto-compound setting
          if (section === 'parachainStaking' && method === 'AutoCompoundSet') {
            const [candidate, delegator, value] = data;
            console.log('\nSuccessfully set auto-compound percentage!');
            console.log('Candidate:', candidate.toString());
            console.log('Delegator:', delegator.toString());
            console.log('Auto-compound value:', value.toString(), '%');
          }
        });

        // Query updated auto-compound settings
        api.query.parachainStaking
          .autoCompoundingDelegations(candidateAddress)
          .then((newAutoCompound) => {
            const delegatorSetting = newAutoCompound.find(
              (d) =>
                d.delegator.toString().toLowerCase() ===
                delegator.address.toLowerCase()
            );
            if (delegatorSetting) {
              console.log('\nUpdated Auto-Compound Setting:');
              console.log('Value:', delegatorSetting.value.toString(), '%');
            }
            process.exit(0);
          });
      }
    });
  } catch (error) {
    console.error('Error in setting auto-compound:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});

Storage Methods

The parachain staking pallet includes the following read-only storage methods to obtain chain state data:

atStake(u32, AccountId20) - provides a snapshot of a collator's delegation stake and the percentage of rewards set to auto-compound given a round number and, optionally, the collator's address
  • u32 - round number
  • AccountId20 - collator address to query. If omitted, information about all collators will be returned

Information about a collator's delegations including delegator addresses, amounts, and auto-compound percentages

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get current round information
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    // Example collator address
    const collatorAddress = 'INSERT_COLLATOR_ADDRESS';

    console.log('Query Parameters:');
    console.log('Current round:', currentRound);
    console.log('Collator address:', collatorAddress);

    // Query current round
    console.log('\nQuerying current round stake...');
    const currentStake = await api.query.parachainStaking.atStake(
      currentRound,
      collatorAddress
    );

    if (currentStake) {
      console.log('\nCurrent Round Stake Details:');
      const stakeInfo = currentStake.toHuman();
      console.log(JSON.stringify(stakeInfo, null, 2));

      // Get raw values for calculations if needed
      const rawStake = currentStake.toJSON();
      console.log('\nRaw Stake Values:');
      console.log('Total stake:', rawStake.total);
      console.log('Own stake:', rawStake.bond);
    }

    // Query previous round
    const previousRound = currentRound - 1;
    console.log('\nQuerying previous round stake...');
    const previousStake = await api.query.parachainStaking.atStake(
      previousRound,
      collatorAddress
    );

    if (previousStake) {
      console.log('\nPrevious Round Stake Details:');
      const previousStakeInfo = previousStake.toHuman();
      console.log(JSON.stringify(previousStakeInfo, null, 2));
    }

    // Get scheduled delegation requests
    const delegationRequests =
      await api.query.parachainStaking.delegationScheduledRequests(
        collatorAddress
      );

    console.log('\nScheduled Delegation Changes:');
    if (delegationRequests.length > 0) {
      console.log(JSON.stringify(delegationRequests.toHuman(), null, 2));
    } else {
      console.log('No scheduled delegation changes');
    }

    // Get auto-compound settings
    const autoCompound =
      await api.query.parachainStaking.autoCompoundingDelegations(
        collatorAddress
      );

    console.log('\nAuto-Compound Settings:');
    if (autoCompound.length > 0) {
      console.log(JSON.stringify(autoCompound.toHuman(), null, 2));
    } else {
      console.log('No auto-compound settings found');
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying at stake:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
autoCompoundingDelegations(AccountId20) - returns a list of delegators for a given candidate that have set up auto-compounding along with the percentage of rewards set to be auto-compounded
  • AccountId20 - the collator address to query. If omitted, information about all collators will be returned

The list of delegators who have auto-compounding enabled and the respective percentage of rewards they have set to be auto-compounded

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Example candidate address
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    console.log('Query Parameters:');
    console.log('Candidate address:', candidateAddress);

    // Query auto-compounding delegations
    const autoCompoundDelegations =
      await api.query.parachainStaking.autoCompoundingDelegations(
        candidateAddress
      );

    // Get candidate info
    const candidateInfo =
      await api.query.parachainStaking.candidateInfo(candidateAddress);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCandidate Information:');
      console.log('Total delegations:', info.delegationCount.toString());
      console.log('Bond amount:', info.bond.toString());
    }

    console.log('\nAuto-Compounding Delegations:');
    if (autoCompoundDelegations.length > 0) {
      console.log(
        'Total auto-compounding delegators:',
        autoCompoundDelegations.length
      );

      // Display each auto-compounding delegation
      autoCompoundDelegations.forEach((delegation, index) => {
        const { delegator, value } = delegation;
        console.log(`\nDelegator #${index + 1}:`);
        console.log('Address:', delegator.toString());
        console.log('Auto-compound percentage:', value.toString(), '%');
      });

      // Get more detailed information for each delegator
      console.log('\nDetailed Delegation Information:');
      for (const delegation of autoCompoundDelegations) {
        const delegatorState = await api.query.parachainStaking.delegatorState(
          delegation.delegator
        );
        if (delegatorState.isSome) {
          const state = delegatorState.unwrap();
          const specificDelegation = state.delegations.find(
            (d) =>
              d.owner.toString().toLowerCase() ===
              candidateAddress.toLowerCase()
          );

          if (specificDelegation) {
            console.log(`\nDelegator ${delegation.delegator.toString()}:`);
            console.log(
              'Delegation amount:',
              specificDelegation.amount.toString()
            );
            console.log(
              'Auto-compound value:',
              delegation.value.toString(),
              '%'
            );
          }
        }
      }

      // Calculate some statistics
      const averageCompounding =
        autoCompoundDelegations.reduce(
          (acc, curr) => acc + curr.value.toNumber(),
          0
        ) / autoCompoundDelegations.length;
      console.log('\nStatistics:');
      console.log(
        'Average auto-compound percentage:',
        averageCompounding.toFixed(2),
        '%'
      );

      const maxCompounding = Math.max(
        ...autoCompoundDelegations.map((d) => d.value.toNumber())
      );
      const minCompounding = Math.min(
        ...autoCompoundDelegations.map((d) => d.value.toNumber())
      );
      console.log('Highest auto-compound setting:', maxCompounding, '%');
      console.log('Lowest auto-compound setting:', minCompounding, '%');
    } else {
      console.log('No auto-compounding delegations found for this candidate');
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying auto-compounding delegations:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
awardedPts(u32, AccountId20) - returns the awarded points for each collator per round given a round number and, optionally, the collator's address
  • u32 - the round number
  • AccountId20 - the collator to query. If omitted, information about all collators will be returned

The number of awarded points for a given round and collator.

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get current round information
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    // Example collator address - you can set this to null to query all collators
    const collatorAddress = 'INSERT_COLLATOR_ADDRESS';

    // Query several recent rounds
    const roundsToQuery = 5;
    const rounds = Array.from(
      { length: roundsToQuery },
      (_, i) => currentRound - i
    );

    console.log('Query Parameters:');
    console.log('Current round:', currentRound);
    console.log('Collator address:', collatorAddress || 'All collators');
    console.log(`Querying last ${roundsToQuery} rounds:`, rounds);

    // Store points data for analysis
    const pointsData = {};

    // Query points for each round
    for (const roundNumber of rounds) {
      let roundPoints;

      if (collatorAddress) {
        // Query specific collator
        roundPoints = await api.query.parachainStaking.awardedPts(
          roundNumber,
          collatorAddress
        );
        console.log(
          `\nRound ${roundNumber} Points for ${collatorAddress}:`,
          roundPoints.toString()
        );

        pointsData[roundNumber] = {
          [collatorAddress]: roundPoints.toNumber(),
        };
      } else {
        // Query all collators for this round
        roundPoints =
          await api.query.parachainStaking.awardedPts.entries(roundNumber);
        console.log(`\nRound ${roundNumber} Points:`);

        pointsData[roundNumber] = {};

        for (const [key, points] of roundPoints) {
          const collator = key.args[1].toString();
          const pointsValue = points.toNumber();
          console.log(`Collator ${collator}: ${pointsValue} points`);

          pointsData[roundNumber][collator] = pointsValue;
        }
      }
    }

    // Calculate statistics
    console.log('\nStatistics:');

    if (collatorAddress) {
      // Statistics for specific collator
      const collatorPoints = rounds.map(
        (r) => pointsData[r][collatorAddress] || 0
      );
      const totalPoints = collatorPoints.reduce((a, b) => a + b, 0);
      const averagePoints = totalPoints / rounds.length;
      const maxPoints = Math.max(...collatorPoints);
      const minPoints = Math.min(...collatorPoints);

      console.log(`\nCollator ${collatorAddress}:`);
      console.log('Total points:', totalPoints);
      console.log('Average points per round:', averagePoints.toFixed(2));
      console.log('Highest points:', maxPoints);
      console.log('Lowest points:', minPoints);
    } else {
      // Statistics for all collators
      const collators = new Set(
        rounds.flatMap((r) => Object.keys(pointsData[r]))
      );

      for (const collator of collators) {
        const collatorPoints = rounds.map((r) => pointsData[r][collator] || 0);
        const totalPoints = collatorPoints.reduce((a, b) => a + b, 0);
        const averagePoints = totalPoints / rounds.length;
        const maxPoints = Math.max(...collatorPoints);
        const minPoints = Math.min(...collatorPoints);

        console.log(`\nCollator ${collator}:`);
        console.log('Total points:', totalPoints);
        console.log('Average points per round:', averagePoints.toFixed(2));
        console.log('Highest points:', maxPoints);
        console.log('Lowest points:', minPoints);
        console.log('Points history:', collatorPoints.join(', '));
      }
    }

    // Get current selected candidates for context
    const selectedCandidates =
      await api.query.parachainStaking.selectedCandidates();
    console.log('\nCurrently Selected Candidates:', selectedCandidates.length);
    console.log(selectedCandidates.map((c) => c.toString()).join('\n'));

    process.exit(0);
  } catch (error) {
    console.error('Error querying awarded points:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
bottomDelegations(AccountId20) - returns at the most the bottom 50 delegations for all candidates or for a given candidate's address
  • AccountId20 - the collator to query. If omitted, information about all collators will be returned

The bottom 50 delegations for a given collator address

 import { ApiPromise, WsProvider } from '@polkadot/api';

 const main = async () => {
   // Initialize the API
   const api = await ApiPromise.create({
     provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
   });

   try {
     // Example candidate address
     const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

     // Get candidate info first
     const candidateInfo =
       await api.query.parachainStaking.candidateInfo(candidateAddress);

     console.log('Query Parameters:');
     console.log('Candidate address:', candidateAddress);

     if (candidateInfo.isSome) {
       const info = candidateInfo.unwrap();
       console.log('\nCandidate Information:');
       console.log('Total delegations:', info.delegationCount.toString());
       console.log('Bond amount:', info.bond.toString(), 'Wei');
     }

     // Query bottom delegations
     const bottomDelegations =
       await api.query.parachainStaking.bottomDelegations(candidateAddress);

     if (bottomDelegations.isSome) {
       const delegations = bottomDelegations.unwrap();
       console.log('\nBottom Delegations:');
       console.log(
         'Total bottom delegations found:',
         delegations.delegations.length
       );

       // Sort delegations by amount in descending order
       const sortedDelegations = [...delegations.delegations].sort(
         (a, b) => BigInt(b.amount) - BigInt(a.amount)
       );

       // Display each delegation
       sortedDelegations.forEach((delegation, index) => {
         console.log(`\nDelegation #${index + 1}:`);
         console.log('Delegator:', delegation.owner.toString());
         console.log('Amount:', delegation.amount.toString(), 'Wei');
         // Convert Wei to DEV (1 DEV = 10^18 Wei)
         const devAmount = BigInt(delegation.amount) / BigInt(10 ** 18);
         console.log('Amount in DEV:', devAmount.toString(), 'DEV');
       });

       // Calculate some statistics
       if (sortedDelegations.length > 0) {
         const total = sortedDelegations.reduce(
           (acc, curr) => acc + BigInt(curr.amount),
           BigInt(0)
         );
         const average = total / BigInt(sortedDelegations.length);
         const highest = sortedDelegations[0].amount;
         const lowest = sortedDelegations[sortedDelegations.length - 1].amount;

         console.log('\nStatistics:');
         console.log('Total delegated in bottom:', total.toString(), 'Wei');
         console.log('Average delegation:', average.toString(), 'Wei');
         console.log('Highest bottom delegation:', highest.toString(), 'Wei');
         console.log('Lowest bottom delegation:', lowest.toString(), 'Wei');

         // Show in DEV for readability
         console.log('\nStatistics (in DEV):');
         console.log(
           'Total delegated:',
           (BigInt(total) / BigInt(10 ** 18)).toString(),
           'DEV'
         );
         console.log(
           'Average delegation:',
           (BigInt(average) / BigInt(10 ** 18)).toString(),
           'DEV'
         );
         console.log(
           'Highest bottom delegation:',
           (BigInt(highest) / BigInt(10 ** 18)).toString(),
           'DEV'
         );
         console.log(
           'Lowest bottom delegation:',
           (BigInt(lowest) / BigInt(10 ** 18)).toString(),
           'DEV'
         );
       }

       // Get top delegations for comparison
       const topDelegations =
         await api.query.parachainStaking.topDelegations(candidateAddress);
       if (topDelegations.isSome) {
         const top = topDelegations.unwrap();
         console.log('\nComparison with Top Delegations:');
         console.log('Number of top delegations:', top.delegations.length);
         console.log('Number of bottom delegations:', sortedDelegations.length);

         if (top.delegations.length > 0) {
           const lowestTop = top.delegations[top.delegations.length - 1].amount;
           console.log('Lowest top delegation:', lowestTop.toString(), 'Wei');
           console.log(
             'Lowest top delegation in DEV:',
             (BigInt(lowestTop) / BigInt(10 ** 18)).toString(),
             'DEV'
           );
         }
       }
     } else {
       console.log('\nNo bottom delegations found for this candidate');
     }

     process.exit(0);
   } catch (error) {
     console.error('Error querying bottom delegations:', error);
     process.exit(1);
   }
 };

 // Execute the script
 main().catch((error) => {
   console.error('Script error:', error);
   process.exit(1);
 });
candidateInfo(AccountId20) - returns candidate information such as the candidate's bond, delegation count, and more for all candidates or for a given candidate's address
  • AccountId20 - The collator address to query. If omitted, information about all collators will be returned

Information about the relevant collator including collator bond, total backing stake, delegation count, lowest included delegation amount, collator status, and capacity information

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Example candidate address
    const candidateAddress = 'INSERT_COLLATOR_ADDRESS';

    console.log('Query Parameters:');
    console.log('Candidate address:', candidateAddress);

    // Query candidate info
    const candidateInfo =
      await api.query.parachainStaking.candidateInfo(candidateAddress);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();

      console.log('\nCandidate Information:');
      console.log('Bond:', info.bond.toString(), 'Wei');
      console.log(
        'Bond in DEV:',
        (BigInt(info.bond) / BigInt(10 ** 18)).toString(),
        'DEV'
      );
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Status:', info.status.toString());
      console.log(
        'Lowest Top Delegation Amount:',
        info.lowestTopDelegationAmount.toString(),
        'Wei'
      );
      console.log(
        'Lowest Top Delegation in DEV:',
        (BigInt(info.lowestTopDelegationAmount) / BigInt(10 ** 18)).toString(),
        'DEV'
      );
      console.log(
        'Highest Bottom Delegation Amount:',
        info.highestBottomDelegationAmount.toString(),
        'Wei'
      );
      console.log(
        'Highest Bottom Delegation in DEV:',
        (
          BigInt(info.highestBottomDelegationAmount) / BigInt(10 ** 18)
        ).toString(),
        'DEV'
      );
      console.log(
        'Lowest Bottom Delegation Amount:',
        info.lowestBottomDelegationAmount.toString(),
        'Wei'
      );
      console.log(
        'Lowest Bottom Delegation in DEV:',
        (
          BigInt(info.lowestBottomDelegationAmount) / BigInt(10 ** 18)
        ).toString(),
        'DEV'
      );
      console.log('Top Capacity:', info.topCapacity.toString());
      console.log('Bottom Capacity:', info.bottomCapacity.toString());

      // Get additional context
      const round = await api.query.parachainStaking.round();
      console.log('\nCurrent Round:', round.current.toString());

      // Check if in selected candidates
      const selectedCandidates =
        await api.query.parachainStaking.selectedCandidates();
      const isSelected = selectedCandidates.some(
        (c) => c.toString() === candidateAddress
      );
      console.log('Is Selected Candidate:', isSelected);

      // Get top delegations
      const topDelegations =
        await api.query.parachainStaking.topDelegations(candidateAddress);
      if (topDelegations.isSome) {
        const top = topDelegations.unwrap();
        console.log('\nTop Delegations Count:', top.delegations.length);
        console.log('Total Top Delegated:', top.total.toString(), 'Wei');
        console.log(
          'Total Top Delegated in DEV:',
          (BigInt(top.total) / BigInt(10 ** 18)).toString(),
          'DEV'
        );
      }

      // Get bottom delegations
      const bottomDelegations =
        await api.query.parachainStaking.bottomDelegations(candidateAddress);
      if (bottomDelegations.isSome) {
        const bottom = bottomDelegations.unwrap();
        console.log('\nBottom Delegations Count:', bottom.delegations.length);
        console.log('Total Bottom Delegated:', bottom.total.toString(), 'Wei');
        console.log(
          'Total Bottom Delegated in DEV:',
          (BigInt(bottom.total) / BigInt(10 ** 18)).toString(),
          'DEV'
        );
      }

      // Get auto-compounding delegations
      const autoCompounding =
        await api.query.parachainStaking.autoCompoundingDelegations(
          candidateAddress
        );
      console.log(
        '\nAuto-compounding Delegations Count:',
        autoCompounding.length
      );

      // Calculate some total statistics
      const totalStake =
        BigInt(info.bond) +
        (topDelegations.isSome
          ? BigInt(topDelegations.unwrap().total)
          : BigInt(0)) +
        (bottomDelegations.isSome
          ? BigInt(bottomDelegations.unwrap().total)
          : BigInt(0));

      console.log('\nTotal Statistics:');
      console.log('Total Stake:', totalStake.toString(), 'Wei');
      console.log(
        'Total Stake in DEV:',
        (totalStake / BigInt(10 ** 18)).toString(),
        'DEV'
      );

      // Check recent points (last 3 rounds)
      console.log('\nRecent Points:');
      const currentRound = round.current.toNumber();
      for (let i = 0; i < 3; i++) {
        const roundNumber = currentRound - i;
        const points = await api.query.parachainStaking.awardedPts(
          roundNumber,
          candidateAddress
        );
        console.log(`Round ${roundNumber}: ${points.toString()} points`);
      }
    } else {
      console.log('\nNo candidate information found for this address');
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying candidate info:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
candidatePool() - returns a list of each of the candidates in the pool and their total backing stake

None

A list of each of the candidates in the pool and their total backing stake

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get current round information
    const round = await api.query.parachainStaking.round();
    console.log('Current Round:', round.current.toString());

    // Query candidate pool
    const candidatePool = await api.query.parachainStaking.candidatePool();

    console.log('\nCandidate Pool Information:');
    console.log('Total Candidates:', candidatePool.length);

    // Sort candidates by amount, handling BigInt comparison correctly
    const sortedCandidates = [...candidatePool].sort((a, b) => {
      const amountA = BigInt(a.amount);
      const amountB = BigInt(b.amount);
      if (amountA < amountB) return 1;
      if (amountA > amountB) return -1;
      return 0;
    });

    // Get selected candidates for comparison
    const selectedCandidates =
      await api.query.parachainStaking.selectedCandidates();
    const selectedSet = new Set(selectedCandidates.map((c) => c.toString()));

    // Track total stake in pool
    let totalStake = BigInt(0);

    // Display each candidate's information
    console.log('\nDetailed Candidate Information:');
    for (const [index, candidate] of sortedCandidates.entries()) {
      const { owner, amount } = candidate;
      totalStake += BigInt(amount);

      // Get candidate info
      const candidateInfo =
        await api.query.parachainStaking.candidateInfo(owner);

      console.log(`\nCandidate #${index + 1}:`);
      console.log('Address:', owner.toString());
      console.log('Total Stake:', amount.toString(), 'Wei');
      console.log(
        'Total Stake in DEV:',
        (BigInt(amount) / BigInt(10 ** 18)).toString(),
        'DEV'
      );
      console.log('Is Selected Collator:', selectedSet.has(owner.toString()));

      if (candidateInfo.isSome) {
        const info = candidateInfo.unwrap();
        console.log('Self Bond:', info.bond.toString(), 'Wei');
        console.log(
          'Self Bond in DEV:',
          (BigInt(info.bond) / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log('Delegation Count:', info.delegationCount.toString());
        console.log('Status:', info.status.toString());
      }

      // Get auto-compounding delegations count
      const autoCompounding =
        await api.query.parachainStaking.autoCompoundingDelegations(owner);
      console.log('Auto-compounding Delegations:', autoCompounding.length);

      // Get recent points (last 3 rounds)
      const currentRound = round.current.toNumber();
      let totalPoints = 0;
      console.log('Recent Points:');
      for (let i = 0; i < 3; i++) {
        const roundNumber = currentRound - i;
        const points = await api.query.parachainStaking.awardedPts(
          roundNumber,
          owner
        );
        console.log(`  Round ${roundNumber}: ${points.toString()} points`);
        totalPoints += points.toNumber();
      }
      console.log(
        'Average Points (last 3 rounds):',
        (totalPoints / 3).toFixed(2)
      );
    }

    // Display pool statistics
    console.log('\nPool Statistics:');
    console.log('Total Candidates:', candidatePool.length);
    console.log('Selected Collators:', selectedCandidates.length);
    console.log('Total Stake in Pool:', totalStake.toString(), 'Wei');
    console.log(
      'Total Stake in Pool (DEV):',
      (totalStake / BigInt(10 ** 18)).toString(),
      'DEV'
    );
    console.log(
      'Average Stake per Candidate (DEV):',
      (totalStake / BigInt(candidatePool.length) / BigInt(10 ** 18)).toString(),
      'DEV'
    );

    // Calculate stake distribution
    const stakes = sortedCandidates.map((c) => BigInt(c.amount));
    const median = stakes[Math.floor(stakes.length / 2)];
    const highest = stakes[0];
    const lowest = stakes[stakes.length - 1];

    console.log('\nStake Distribution:');
    console.log(
      'Highest Stake (DEV):',
      (highest / BigInt(10 ** 18)).toString()
    );
    console.log('Median Stake (DEV):', (median / BigInt(10 ** 18)).toString());
    console.log('Lowest Stake (DEV):', (lowest / BigInt(10 ** 18)).toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying candidate pool:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
candidateState(AccountId20) - deprecated as of runtime 1200 - use candidateInfo instead
  • AccountId20 - the collator account to query

Deprecated as of runtime 1200 - use candidateInfo instead

Deprecated as of runtime 1200 - use candidateInfo instead

collatorCommission() - returns the commission percent taken off of rewards for all collators

None

The percent collator commission, e.g. 20.00%

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Query collator commission
    const commission = await api.query.parachainStaking.collatorCommission();

    // Get the current round for context
    const round = await api.query.parachainStaking.round();

    // Get selected candidates count for context
    const selectedCandidates =
      await api.query.parachainStaking.selectedCandidates();

    console.log('\nCollator Commission Information:');
    console.log('Current Round:', round.current.toString());
    console.log('Commission Rate:', commission.toString(), 'Per Billion');
    // Convert to percentage (commission is stored as parts per billion)
    const commissionPercent = (Number(commission) / 10_000_000).toFixed(2);
    console.log('Commission Percentage:', commissionPercent + '%');

    console.log('\nNetwork Context:');
    console.log('Active Collators:', selectedCandidates.length);

    // Example calculation for a reward
    const exampleReward = BigInt(1000000000000000000); // 1 DEV
    const commissionAmount =
      (exampleReward * BigInt(commission)) / BigInt(1000000000);

    console.log('\nExample Reward Calculation:');
    console.log('For a reward of 1 DEV:');
    console.log(
      'Commission Amount:',
      (commissionAmount / BigInt(10 ** 18)).toString(),
      'DEV'
    );
    console.log(
      'Remaining Reward:',
      ((exampleReward - commissionAmount) / BigInt(10 ** 18)).toString(),
      'DEV'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying collator commission:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
collatorState2(AccountId20) - deprecated as of runtime 1001 - use candidateInfo instead
  • AccountId20 - the collator to query

Deprecated as of runtime 1001* - use candidateInfo instead

Deprecated as of runtime 1001* - use candidateInfo instead

delayedPayouts(u32) - returns the delayed payouts for all rounds or for a given round
  • u32 - the round to query. If omitted, the latest round information will be returned

The round issuance, the total staking reward, and collator commission.

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get current round information
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    console.log('Current Round:', currentRound);

    // Query several recent rounds for delayed payouts
    const roundsToCheck = 5;
    const rounds = Array.from(
      { length: roundsToCheck },
      (_, i) => currentRound - i
    );

    console.log(
      '\nChecking Delayed Payouts for the Last',
      roundsToCheck,
      'Rounds:'
    );

    // Track statistics
    let totalPayouts = 0;
    let totalRewards = BigInt(0);

    for (const roundNumber of rounds) {
      console.log(`\nRound ${roundNumber}:`);

      const delayedPayout =
        await api.query.parachainStaking.delayedPayouts(roundNumber);

      if (delayedPayout.isSome) {
        const payout = delayedPayout.unwrap();

        // Debug log to see the structure
        console.log(
          'Raw payout data:',
          JSON.stringify(payout.toJSON(), null, 2)
        );

        // Safely access the data
        const payoutData = payout.toJSON();

        console.log('Found Delayed Payout:');
        if (payoutData) {
          totalPayouts++;

          // Calculate total rewards if data is available
          if (payoutData.colReward && payoutData.delReward) {
            const roundReward =
              BigInt(payoutData.colReward) + BigInt(payoutData.delReward);
            totalRewards += roundReward;

            console.log('Collator:', payoutData.toCollator);
            console.log('Collator Reward:', payoutData.colReward, 'Wei');
            console.log(
              'Collator Reward in DEV:',
              (BigInt(payoutData.colReward) / BigInt(10 ** 18)).toString(),
              'DEV'
            );
            console.log('Total Delegator Reward:', payoutData.delReward, 'Wei');
            console.log(
              'Total Delegator Reward in DEV:',
              (BigInt(payoutData.delReward) / BigInt(10 ** 18)).toString(),
              'DEV'
            );
            console.log('Total Round Reward:', roundReward.toString(), 'Wei');
            console.log(
              'Total Round Reward in DEV:',
              (roundReward / BigInt(10 ** 18)).toString(),
              'DEV'
            );

            // Get collator information if available
            if (payoutData.toCollator) {
              const collatorInfo =
                await api.query.parachainStaking.candidateInfo(
                  payoutData.toCollator
                );
              if (collatorInfo.isSome) {
                const info = collatorInfo.unwrap();
                console.log('\nCollator Information:');
                console.log(
                  'Delegation Count:',
                  info.delegationCount.toString()
                );
                console.log('Self Bond:', info.bond.toString(), 'Wei');
                console.log(
                  'Self Bond in DEV:',
                  (BigInt(info.bond) / BigInt(10 ** 18)).toString(),
                  'DEV'
                );
              }

              // Get awarded points for context
              const points = await api.query.parachainStaking.awardedPts(
                roundNumber,
                payoutData.toCollator
              );
              console.log('Points earned in round:', points.toString());
            }
          }
        }
      } else {
        console.log('No delayed payout found');
      }
    }

    // Display statistics
    console.log('\nPayout Statistics:');
    console.log('Total Rounds with Payouts:', totalPayouts);
    console.log(
      'Average Payouts per Round:',
      (totalPayouts / roundsToCheck).toFixed(2)
    );
    if (totalPayouts > 0) {
      console.log(
        'Average Reward per Payout:',
        (totalRewards / BigInt(totalPayouts) / BigInt(10 ** 18)).toString(),
        'DEV'
      );
      console.log(
        'Total Rewards:',
        (totalRewards / BigInt(10 ** 18)).toString(),
        'DEV'
      );
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying delayed payouts:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
delegationScheduledRequests(AccountId20) - returns the outstanding scheduled delegation requests for all collators or for a given collator's address
  • AccountId20 - the address of the collator. If omitted, information about all collators will be returned

The set of pending scheduled delegation requests including the delegator's address, the action requested, and eligible block at which the action can be executed.

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Example collator address
    const collatorAddress = 'INSERT_COLLATOR_ADDRESS';

    // Get current round information for context
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    console.log('Query Parameters:');
    console.log('Collator address:', collatorAddress);
    console.log('Current round:', currentRound);

    // Get collator info for context
    const collatorInfo =
      await api.query.parachainStaking.candidateInfo(collatorAddress);
    if (collatorInfo.isSome) {
      const info = collatorInfo.unwrap();
      console.log('\nCollator Information:');
      console.log('Delegation Count:', info.delegationCount.toString());
      console.log('Current Bond:', info.bond.toString(), 'Wei');
      console.log(
        'Current Bond in DEV:',
        (BigInt(info.bond) / BigInt(10 ** 18)).toString(),
        'DEV'
      );
    }

    // Query scheduled delegation requests
    const requests =
      await api.query.parachainStaking.delegationScheduledRequests(
        collatorAddress
      );

    console.log('\nScheduled Delegation Requests:');
    if (requests.length > 0) {
      console.log('Total requests:', requests.length);

      // Process each request
      requests.forEach((request, index) => {
        console.log(`\nRequest #${index + 1}:`);
        const { delegator, whenExecutable, action } = request;
        console.log('Delegator:', delegator.toString());
        console.log('Executable at round:', whenExecutable.toString());
        console.log(
          'Rounds until executable:',
          whenExecutable.toNumber() - currentRound
        );

        // Handle different types of actions
        if (action.isDecrease) {
          const amount = action.asDecrease;
          console.log('Action: Decrease');
          console.log('Amount:', amount.toString(), 'Wei');
          console.log(
            'Amount in DEV:',
            (BigInt(amount) / BigInt(10 ** 18)).toString(),
            'DEV'
          );
        } else if (action.isRevoke) {
          const amount = action.asRevoke;
          console.log('Action: Revoke');
          console.log('Amount:', amount.toString(), 'Wei');
          console.log(
            'Amount in DEV:',
            (BigInt(amount) / BigInt(10 ** 18)).toString(),
            'DEV'
          );
        }
      });

      // Calculate some statistics
      let totalDecreaseAmount = BigInt(0);
      let totalRevokeAmount = BigInt(0);
      let decreaseCount = 0;
      let revokeCount = 0;

      requests.forEach((request) => {
        if (request.action.isDecrease) {
          totalDecreaseAmount += BigInt(request.action.asDecrease);
          decreaseCount++;
        } else if (request.action.isRevoke) {
          totalRevokeAmount += BigInt(request.action.asRevoke);
          revokeCount++;
        }
      });

      console.log('\nRequest Statistics:');
      console.log('Decrease requests:', decreaseCount);
      if (decreaseCount > 0) {
        console.log(
          'Total decrease amount:',
          totalDecreaseAmount.toString(),
          'Wei'
        );
        console.log(
          'Total decrease amount in DEV:',
          (totalDecreaseAmount / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log(
          'Average decrease amount in DEV:',
          (
            totalDecreaseAmount /
            BigInt(decreaseCount) /
            BigInt(10 ** 18)
          ).toString(),
          'DEV'
        );
      }

      console.log('Revoke requests:', revokeCount);
      if (revokeCount > 0) {
        console.log(
          'Total revoke amount:',
          totalRevokeAmount.toString(),
          'Wei'
        );
        console.log(
          'Total revoke amount in DEV:',
          (totalRevokeAmount / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log(
          'Average revoke amount in DEV:',
          (
            totalRevokeAmount /
            BigInt(revokeCount) /
            BigInt(10 ** 18)
          ).toString(),
          'DEV'
        );
      }

      // Show impact on collator's delegation
      const totalImpact = totalDecreaseAmount + totalRevokeAmount;
      console.log('\nTotal Impact:');
      console.log('Total amount to be removed:', totalImpact.toString(), 'Wei');
      console.log(
        'Total amount to be removed in DEV:',
        (totalImpact / BigInt(10 ** 18)).toString(),
        'DEV'
      );
    } else {
      console.log('No scheduled delegation requests found');
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying delegation requests:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
delegatorState(AccountId20) - returns delegator information such as their delegations, delegation status, and total delegation amount for all delegators or for a given delegator's address
  • AccountId20 - the address of the delegator to query

Delegator state information including the collators delegated and their respective amounts

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Example delegator address
    const delegatorAddress = 'INSERT_DELEGATOR_ADDRESS';

    // Get current round information for context
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    console.log('Query Parameters:');
    console.log('Delegator address:', delegatorAddress);
    console.log('Current round:', currentRound);

    // Query delegator state
    const delegatorState =
      await api.query.parachainStaking.delegatorState(delegatorAddress);

    if (delegatorState.isSome) {
      const state = delegatorState.unwrap();
      const delegations = state.delegations;

      console.log('\nDelegator Information:');
      console.log('Total Delegations:', delegations.length);

      // Calculate total delegated amount
      let totalDelegated = BigInt(0);
      delegations.forEach((d) => {
        totalDelegated += BigInt(d.amount);
      });

      console.log('Total Amount Delegated:', totalDelegated.toString(), 'Wei');
      console.log(
        'Total Amount Delegated in DEV:',
        (totalDelegated / BigInt(10 ** 18)).toString(),
        'DEV'
      );

      // Show detailed delegation information
      console.log('\nDetailed Delegations:');
      for (const [index, delegation] of delegations.entries()) {
        console.log(`\nDelegation #${index + 1}:`);
        console.log('Collator:', delegation.owner.toString());
        console.log('Amount:', delegation.amount.toString(), 'Wei');
        console.log(
          'Amount in DEV:',
          (BigInt(delegation.amount) / BigInt(10 ** 18)).toString(),
          'DEV'
        );

        // Get collator information
        const collatorInfo = await api.query.parachainStaking.candidateInfo(
          delegation.owner
        );
        if (collatorInfo.isSome) {
          const info = collatorInfo.unwrap();
          console.log('Collator Status:', info.status.toString());
          console.log('Collator Total Bond:', info.bond.toString(), 'Wei');
          console.log(
            'Collator Delegation Count:',
            info.delegationCount.toString()
          );
        }

        // Check auto-compound setting
        const autoCompoundDelegations =
          await api.query.parachainStaking.autoCompoundingDelegations(
            delegation.owner
          );
        const autoCompound = autoCompoundDelegations.find(
          (d) =>
            d.delegator.toString().toLowerCase() ===
            delegatorAddress.toLowerCase()
        );
        if (autoCompound) {
          console.log(
            'Auto-compound Percentage:',
            autoCompound.value.toString(),
            '%'
          );
        } else {
          console.log('Auto-compound: Not set');
        }

        // Check for scheduled requests
        const requests =
          await api.query.parachainStaking.delegationScheduledRequests(
            delegation.owner
          );
        const delegatorRequests = requests.filter(
          (r) =>
            r.delegator.toString().toLowerCase() ===
            delegatorAddress.toLowerCase()
        );

        if (delegatorRequests.length > 0) {
          console.log('\nPending Requests:');
          delegatorRequests.forEach((request) => {
            console.log(
              'Executable at round:',
              request.whenExecutable.toString()
            );
            if (request.action.isDecrease) {
              console.log('Action: Decrease');
              console.log(
                'Amount:',
                request.action.asDecrease.toString(),
                'Wei'
              );
              console.log(
                'Amount in DEV:',
                (
                  BigInt(request.action.asDecrease) / BigInt(10 ** 18)
                ).toString(),
                'DEV'
              );
            } else if (request.action.isRevoke) {
              console.log('Action: Revoke');
              console.log('Amount:', request.action.asRevoke.toString(), 'Wei');
              console.log(
                'Amount in DEV:',
                (BigInt(request.action.asRevoke) / BigInt(10 ** 18)).toString(),
                'DEV'
              );
            }
          });
        }
      }

      // Calculate statistics
      const amounts = delegations.map((d) => BigInt(d.amount));
      const averageDelegation = totalDelegated / BigInt(delegations.length);
      const maxDelegation = amounts.reduce(
        (a, b) => (a > b ? a : b),
        BigInt(0)
      );
      const minDelegation = amounts.reduce(
        (a, b) => (a < b ? a : b),
        amounts[0] || BigInt(0)
      );

      console.log('\nDelegation Statistics:');
      console.log(
        'Average Delegation:',
        (averageDelegation / BigInt(10 ** 18)).toString(),
        'DEV'
      );
      console.log(
        'Largest Delegation:',
        (maxDelegation / BigInt(10 ** 18)).toString(),
        'DEV'
      );
      console.log(
        'Smallest Delegation:',
        (minDelegation / BigInt(10 ** 18)).toString(),
        'DEV'
      );

      // Get network context
      const selectedCandidates =
        await api.query.parachainStaking.selectedCandidates();
      console.log('\nNetwork Context:');
      console.log('Total Selected Collators:', selectedCandidates.length);
      console.log(
        'Delegating to Selected Collators:',
        delegations.filter((d) =>
          selectedCandidates.some((c) => c.toString() === d.owner.toString())
        ).length
      );
    } else {
      console.log('\nNo delegator state found for this address');
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying delegator state:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
enabledMarkingOffline() - returns a boolean indicating whether or not the marking offline feature for inactive collators is enabled

None

boolean - Indicating whether or not the marking offline feature for inactive collators is enabled

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get marking offline status with the correct method name
    const isEnabled = await api.query.parachainStaking.enableMarkingOffline();

    console.log('Marking Offline Feature Status:', isEnabled.toHuman());

    process.exit(0);
  } catch (error) {
    console.error('Error querying marking offline status:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
inflationConfig() - returns the inflation configuration

None

A JSON object that contains the minimum, ideal, and maximum inflation parameters in each of the following thresholds: expected, annual, and round.

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Query inflation configuration
    const inflationConfig = await api.query.parachainStaking.inflationConfig();

    // Get current round info for context
    const round = await api.query.parachainStaking.round();

    console.log('Current Round:', round.current.toString());

    console.log('\nInflation Configuration (Human Readable):');
    const config = inflationConfig.toHuman();
    console.log(JSON.stringify(config, null, 2));

    // Access the nested structure correctly
    const rawConfig = inflationConfig.toJSON();

    console.log('\nDetailed Configuration Breakdown:');

    // Expected rewards
    console.log('\nExpected Rewards:');
    console.log('Min:', rawConfig.expect.min);
    console.log('Ideal:', rawConfig.expect.ideal);
    console.log('Max:', rawConfig.expect.max);

    // Annual inflation rates (divide by 10^7 to get percentage)
    console.log('\nAnnual Inflation Rates:');
    console.log('Min:', (rawConfig.annual.min / 10_000_000).toFixed(2) + '%');
    console.log(
      'Ideal:',
      (rawConfig.annual.ideal / 10_000_000).toFixed(2) + '%'
    );
    console.log('Max:', (rawConfig.annual.max / 10_000_000).toFixed(2) + '%');

    // Round inflation rates
    console.log('\nRound Inflation Rates:');
    console.log('Min:', (rawConfig.round.min / 10_000_000).toFixed(4) + '%');
    console.log(
      'Ideal:',
      (rawConfig.round.ideal / 10_000_000).toFixed(4) + '%'
    );
    console.log('Max:', (rawConfig.round.max / 10_000_000).toFixed(4) + '%');

    // Example calculations for 100 DEV with annual rates
    const exampleStake = 100n * BigInt(10 ** 18); // 100 DEV
    console.log('\nExample Annual Returns for 100 DEV stake:');

    // Convert to BigInt for calculations
    const annualMin =
      (BigInt(rawConfig.annual.min) * exampleStake) /
      BigInt(10_000_000) /
      BigInt(10 ** 18);
    const annualIdeal =
      (BigInt(rawConfig.annual.ideal) * exampleStake) /
      BigInt(10_000_000) /
      BigInt(10 ** 18);
    const annualMax =
      (BigInt(rawConfig.annual.max) * exampleStake) /
      BigInt(10_000_000) /
      BigInt(10 ** 18);

    console.log('Min:', annualMin.toString(), 'DEV');
    console.log('Ideal:', annualIdeal.toString(), 'DEV');
    console.log('Max:', annualMax.toString(), 'DEV');

    process.exit(0);
  } catch (error) {
    console.error('Error querying inflation configuration:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
nominatorState2(AccountId20) - deprecated as of runtime 1001 - use delegatorState instead
  • AccountId20 - The account to query

Deprecated as of runtime 1001* - use delegatorState instead

Deprecated as of runtime 1001* - use delegatorState instead

palletVersion() - returns the current pallet version

None

u16 - current pallet version

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Query pallet version
    const version = await api.query.parachainStaking.palletVersion();

    console.log('Parachain Staking Pallet Version:', version.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying pallet version:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
points(u32) - returns the total points awarded to collators for block production in all rounds or for a given round
  • u32 - a round number. If omitted, the data for the last three rounds will be returned
  • u32 - total points awarded to collators in the given round
import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get current round information
    const round = await api.query.parachainStaking.round();
    const currentRound = round.current.toNumber();

    // Query points for several recent rounds
    const roundsToCheck = 5;
    const rounds = Array.from(
      { length: roundsToCheck },
      (_, i) => currentRound - i
    );

    console.log('Current Round:', currentRound);

    // Get selected candidates for context
    const selectedCandidates =
      await api.query.parachainStaking.selectedCandidates();
    console.log('Number of Selected Collators:', selectedCandidates.length);

    // Check each round
    for (const roundNumber of rounds) {
      console.log(`\nPoints for Round ${roundNumber}:`);
      const roundPoints = await api.query.parachainStaking.points(roundNumber);

      if (roundPoints.toNumber() === 0) {
        console.log('No points recorded for this round');
      } else {
        console.log('Total Points:', roundPoints.toString());

        // Get individual collator points for this round
        let collatorPoints = [];
        for (const collator of selectedCandidates) {
          const points = await api.query.parachainStaking.awardedPts(
            roundNumber,
            collator
          );
          if (points.toNumber() > 0) {
            collatorPoints.push({
              collator: collator.toString(),
              points: points.toNumber(),
            });
          }
        }

        // Sort collators by points
        collatorPoints.sort((a, b) => b.points - a.points);

        // Display collator points
        if (collatorPoints.length > 0) {
          console.log('\nCollator Performance:');
          collatorPoints.forEach(({ collator, points }) => {
            console.log(`Collator ${collator}: ${points} points`);
          });

          // Calculate statistics
          const totalPoints = collatorPoints.reduce(
            (sum, { points }) => sum + points,
            0
          );
          const averagePoints = totalPoints / collatorPoints.length;
          const maxPoints = collatorPoints[0].points;
          const minPoints = collatorPoints[collatorPoints.length - 1].points;

          console.log('\nRound Statistics:');
          console.log('Active Collators:', collatorPoints.length);
          console.log('Average Points:', averagePoints.toFixed(2));
          console.log('Highest Points:', maxPoints);
          console.log('Lowest Points:', minPoints);
        }
      }
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying points:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
round() - returns the current round number, the first block of the current round, and the length of the round

None

Returns the current round number, the first block of the current round, and the length of the round

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Query round information
    const roundInfo = await api.query.parachainStaking.round();

    console.log('Round Information:');
    console.log('Current Round:', roundInfo.current.toString());
    console.log('First Block of Round:', roundInfo.first.toString());
    console.log('Round Length:', roundInfo.length.toString());

    // Calculate some additional useful information
    const currentBlock = await api.rpc.chain.getBlock();
    const currentBlockNumber = currentBlock.block.header.number.toNumber();

    // Calculate blocks remaining in current round
    const blocksIntoRound = currentBlockNumber - roundInfo.first.toNumber();
    const blocksRemaining = roundInfo.length.toNumber() - blocksIntoRound;

    console.log('\nAdditional Information:');
    console.log('Current Block:', currentBlockNumber);
    console.log('Blocks Into Current Round:', blocksIntoRound);
    console.log('Blocks Remaining in Round:', blocksRemaining);

    process.exit(0);
  } catch (error) {
    console.error('Error querying round information:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
selectedCandidates() - returns the collator candidates selected to be in the active set for the current round

None

A set of AccountId20s - collator candidates selected to be in the active set for the current round

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get current round for context
    const round = await api.query.parachainStaking.round();
    console.log('Current Round:', round.current.toString());

    // Query selected candidates
    const selectedCandidates =
      await api.query.parachainStaking.selectedCandidates();

    console.log('\nSelected Candidates:');
    console.log('Total Selected:', selectedCandidates.length);

    // Get detailed information for each candidate
    console.log('\nDetailed Candidate Information:');
    for (const [index, candidate] of selectedCandidates.entries()) {
      const candidateInfo =
        await api.query.parachainStaking.candidateInfo(candidate);

      if (candidateInfo.isSome) {
        const info = candidateInfo.unwrap();
        console.log(`\nCandidate #${index + 1}:`);
        console.log('Address:', candidate.toString());
        console.log('Bond:', info.bond.toString(), 'Wei');
        console.log(
          'Bond in DEV:',
          (BigInt(info.bond) / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log('Delegation Count:', info.delegationCount.toString());
        console.log('Status:', info.status.toString());

        // Get recent points for context (last 3 rounds)
        const currentRound = round.current.toNumber();
        let recentPoints = 0;
        console.log('Recent Points:');
        for (let i = 0; i < 3; i++) {
          const roundPoints = await api.query.parachainStaking.awardedPts(
            currentRound - i,
            candidate
          );
          console.log(`  Round ${currentRound - i}: ${roundPoints.toString()}`);
          recentPoints += roundPoints.toNumber();
        }
        console.log('Total Points (last 3 rounds):', recentPoints);
      }
    }

    // Calculate some statistics
    let totalBond = BigInt(0);
    let totalDelegations = 0;

    for (const candidate of selectedCandidates) {
      const candidateInfo =
        await api.query.parachainStaking.candidateInfo(candidate);
      if (candidateInfo.isSome) {
        const info = candidateInfo.unwrap();
        totalBond += BigInt(info.bond);
        totalDelegations += info.delegationCount.toNumber();
      }
    }

    console.log('\nCollective Statistics:');
    console.log('Total Bonded:', totalBond.toString(), 'Wei');
    console.log(
      'Total Bonded in DEV:',
      (totalBond / BigInt(10 ** 18)).toString(),
      'DEV'
    );
    console.log(
      'Average Bond in DEV:',
      (
        totalBond /
        BigInt(selectedCandidates.length) /
        BigInt(10 ** 18)
      ).toString(),
      'DEV'
    );
    console.log(
      'Average Delegations per Candidate:',
      (totalDelegations / selectedCandidates.length).toFixed(2)
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying selected candidates:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
topDelegations(AccountId20) - returns at the most the top 300 delegations for all collators or for a given collator's address
  • AccountId20 - Address of the given collator. If no address is provided then the top 300 delegations for all collators is returned.

Returns up to the top 300 delegations for a given collator, including the address of the delegator and the amount delegated

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Example collator address
    const collatorAddress = 'INSERT_COLLATOR_ADDRESS';

    // Get collator info first
    const candidateInfo =
      await api.query.parachainStaking.candidateInfo(collatorAddress);

    console.log('Query Parameters:');
    console.log('Collator address:', collatorAddress);

    if (candidateInfo.isSome) {
      const info = candidateInfo.unwrap();
      console.log('\nCollator Information:');
      console.log('Total delegations:', info.delegationCount.toString());
      console.log('Self bond:', info.bond.toString(), 'Wei');
      console.log(
        'Self bond in DEV:',
        (BigInt(info.bond) / BigInt(10 ** 18)).toString(),
        'DEV'
      );
    }

    // Query top delegations
    const topDelegations =
      await api.query.parachainStaking.topDelegations(collatorAddress);

    if (topDelegations.isSome) {
      const delegations = topDelegations.unwrap();
      console.log('\nTop Delegations:');
      console.log('Total delegations found:', delegations.delegations.length);
      console.log(
        'Total amount delegated:',
        delegations.total.toString(),
        'Wei'
      );
      console.log(
        'Total amount delegated in DEV:',
        (BigInt(delegations.total) / BigInt(10 ** 18)).toString(),
        'DEV'
      );

      // Sort delegations by amount in descending order
      const sortedDelegations = [...delegations.delegations].sort(
        (a, b) => BigInt(b.amount) - BigInt(a.amount)
      );

      // Display each delegation
      console.log('\nDelegation Details:');
      sortedDelegations.forEach((delegation, index) => {
        console.log(`\nDelegation #${index + 1}:`);
        console.log('Delegator:', delegation.owner.toString());
        console.log('Amount:', delegation.amount.toString(), 'Wei');
        console.log(
          'Amount in DEV:',
          (BigInt(delegation.amount) / BigInt(10 ** 18)).toString(),
          'DEV'
        );
      });

      // Calculate statistics
      if (sortedDelegations.length > 0) {
        const amounts = sortedDelegations.map((d) => BigInt(d.amount));
        const total = amounts.reduce((a, b) => a + b, BigInt(0));
        const average = total / BigInt(sortedDelegations.length);
        const highest = amounts[0];
        const lowest = amounts[amounts.length - 1];
        const median = amounts[Math.floor(amounts.length / 2)];

        console.log('\nDelegation Statistics:');
        console.log(
          'Average delegation:',
          (average / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log(
          'Highest delegation:',
          (highest / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log(
          'Median delegation:',
          (median / BigInt(10 ** 18)).toString(),
          'DEV'
        );
        console.log(
          'Lowest delegation:',
          (lowest / BigInt(10 ** 18)).toString(),
          'DEV'
        );

        // Distribution analysis
        const totalDelegated = BigInt(delegations.total);
        console.log('\nStake Distribution:');
        console.log(
          'Top 5 delegators control:',
          (
            (amounts.slice(0, 5).reduce((a, b) => a + b, BigInt(0)) *
              BigInt(100)) /
            totalDelegated
          ).toString() + '%'
        );
        if (sortedDelegations.length >= 10) {
          console.log(
            'Top 10 delegators control:',
            (
              (amounts.slice(0, 10).reduce((a, b) => a + b, BigInt(0)) *
                BigInt(100)) /
              totalDelegated
            ).toString() + '%'
          );
        }
      }

      // Check auto-compound settings
      const autoCompoundDelegations =
        await api.query.parachainStaking.autoCompoundingDelegations(
          collatorAddress
        );
      console.log('\nAuto-compound Settings:');
      console.log(
        'Delegators with auto-compound:',
        autoCompoundDelegations.length
      );
    } else {
      console.log('\nNo top delegations found for this collator');
    }

    process.exit(0);
  } catch (error) {
    console.error('Error querying top delegations:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
total() - returns the total capital locked in the staking pallet

None

u128 - returns the total capital locked in the staking pallet

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get total staked amount
    const totalStaked = await api.query.parachainStaking.total();

    console.log('Total Staked:');
    console.log('Amount:', totalStaked.toString(), 'Wei');
    console.log(
      'Amount in DEV:',
      (BigInt(totalStaked) / BigInt(10 ** 18)).toString(),
      'DEV'
    );

    // Get some context information
    const selectedCandidates =
      await api.query.parachainStaking.selectedCandidates();
    console.log('\nNetwork Context:');
    console.log('Number of Selected Collators:', selectedCandidates.length);

    // Get total issuance for percentage calculation
    const totalIssuance = await api.query.balances.totalIssuance();
    const percentageStaked =
      (BigInt(totalStaked) * BigInt(100)) / BigInt(totalIssuance);
    console.log('\nStaking Metrics:');
    console.log(
      'Total Issuance:',
      (BigInt(totalIssuance) / BigInt(10 ** 18)).toString(),
      'DEV'
    );
    console.log(
      'Percentage of Total Supply Staked:',
      percentageStaked.toString() + '%'
    );

    // Calculate average stake per collator
    const averageStakePerCollator =
      BigInt(totalStaked) / BigInt(selectedCandidates.length);
    console.log(
      'Average Stake per Collator:',
      (averageStakePerCollator / BigInt(10 ** 18)).toString(),
      'DEV'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying total staked:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
totalSelected() - returns the total number of collator candidates that can be selected for the active set

None

u32 - returns the total number of collator candidates that can be selected for the active set

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get total number of collators that can be selected
    const totalSelected = await api.query.parachainStaking.totalSelected();

    console.log(
      'Maximum Number of Collators that can be Selected:',
      totalSelected.toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying total selected:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});

Pallet Constants

The parachain staking pallet includes the following read-only functions to obtain pallet constants:

candidateBondLessDelay() - returns the number of rounds that must be waited until a candidate's scheduled request to decrease their self bond can be executed

None

u32 - returns the number of rounds that must be waited until a candidate's scheduled request to decrease their self bond can be executed

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the bond less delay constant
    const delay = await api.consts.parachainStaking.candidateBondLessDelay;

    console.log('Candidate Bond Less Delay:', delay.toString(), 'rounds');

    process.exit(0);
  } catch (error) {
    console.error('Error querying candidate bond less delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
defaultBlocksPerRound() - deprecated as of runtime 1900 - returns the default number of blocks per round

None

Deprecated as of runtime 1900

Deprecated as of runtime 1900

defaultCollatorCommission() - deprecated as of runtime 1900 - returns the default commission due to collators

None

Deprecated as of runtime 1900

Deprecated as of runtime 1900

defaultParachainBondReservePercent() - deprecated as of runtime 1900 - returns the default percent of inflation set aside for the parachain bond account

None

Deprecated as of runtime 1900

Deprecated as of runtime 1900

delegationBondLessDelay() - returns the number of rounds that must be waited until a scheduled request to decrease a delegation can be executed

None

u32 - returns the number of rounds that must be waited until a scheduled request to decrease a delegation can be executed

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the delegation bond less delay constant
    const delay = await api.consts.parachainStaking.delegationBondLessDelay;

    console.log('Delegation Bond Less Delay:', delay.toString(), 'rounds');

    process.exit(0);
  } catch (error) {
    console.error('Error querying delegation bond less delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
leaveCandidatesDelay() - returns the number of rounds that must be waited before a scheduled request for a candidate to leave the candidate pool can be executed

None

u32 - returns the number of rounds that must be waited before a scheduled request for a candidate to leave the candidate pool can be executed

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the leaveCandidatesDelay constant from the parachainStaking module
    const leaveCandidatesDelay =
      await api.consts.parachainStaking.leaveCandidatesDelay;

    console.log(
      'Leave Candidates Delay:',
      leaveCandidatesDelay.toString(),
      'rounds'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying leave candidates delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
leaveDelegatorsDelay() - returns the number of rounds that must be waited before a scheduled request for a delegator to leave the set of delegators can be executed

None

u32 - returns the number of rounds that must be waited before a scheduled request for a delegator to leave the set of delegators can be executed

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the leaveDelegatorsDelay constant from the parachainStaking module
    const leaveDelegatorsDelay =
      await api.consts.parachainStaking.leaveDelegatorsDelay;

    console.log(
      'Leave Delegators Delay:',
      leaveDelegatorsDelay.toString(),
      'rounds'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying leave delegators delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxBottomDelegationsPerCandidate() - returns the maximum number of bottom delegations per candidate

None

u32 - returns the maximum number of bottom delegations per candidate

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maxBottomDelegationsPerCandidate constant from the parachainStaking module
    const maxBottomDelegationsPerCandidate =
      await api.consts.parachainStaking.maxBottomDelegationsPerCandidate;

    console.log(
      'Max Bottom Delegations Per Candidate:',
      maxBottomDelegationsPerCandidate.toString()
    );

    process.exit(0);
  } catch (error) {
    console.error(
      'Error querying max bottom delegations per candidate:',
      error
    );
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxCandidates() - returns the maximum number of candidates allowed in the candidate pool

None

u32 - returns the maximum number of candidates allowed in the candidate pool

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maximum number of candidates allowed
    const maxCandidates = await api.consts.parachainStaking.maxCandidates;

    console.log('Maximum Allowed Candidates:', maxCandidates.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying max candidates:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxDelegationsPerDelegator() - returns the maximum number of delegations per delegator

None

u32 - returns the maximum number of delegations per delegator

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maximum number of delegations per delegator
    const maxDelegations =
      await api.consts.parachainStaking.maxDelegationsPerDelegator;

    console.log(
      'Maximum Delegations Per Delegator:',
      maxDelegations.toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying max delegations per delegator:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxOfflineRounds() - returns the number of rounds that must pass before a collator that has stopped producing blocks is marked as inactive

None

u32 - returns the number of rounds that must pass before a collator that has stopped producing blocks is marked as inactive

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maximum number of offline rounds
    const maxOfflineRounds = await api.consts.parachainStaking.maxOfflineRounds;

    console.log('Maximum Offline Rounds:', maxOfflineRounds.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying max offline rounds:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
maxTopDelegationsPerCandidate() - returns the maximum number of top delegations per candidate

None

u32 - returns the maximum number of top delegations per candidate

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the maximum number of top delegations per candidate
    const maxTopDelegations =
      await api.consts.parachainStaking.maxTopDelegationsPerCandidate;

    console.log(
      'Maximum Top Delegations Per Candidate:',
      maxTopDelegations.toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying max top delegations per candidate:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
minBlocksPerRound() - returns the minimum number of blocks per round

None

u32 - returns the minimum number of blocks per round

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the minimum number of blocks per round
    const minBlocksPerRound =
      await api.consts.parachainStaking.minBlocksPerRound;

    console.log('Minimum Blocks Per Round:', minBlocksPerRound.toString());

    process.exit(0);
  } catch (error) {
    console.error('Error querying min blocks per round:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
minCandidateStk() - returns the minimum stake required for a candidate to be a collator candidate

None

u128 - returns the minimum stake required for a candidate to be a collator candidate

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the minimum candidate stake required
    const minCandidateStake = await api.consts.parachainStaking.minCandidateStk;

    console.log(
      'Minimum Candidate Stake:',
      minCandidateStake.toString(),
      'Wei'
    );
    console.log(
      'Minimum Candidate Stake in DEV:',
      (BigInt(minCandidateStake) / BigInt(10 ** 18)).toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying min candidate stake:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
minCollatorStk() - deprecated as of runtime 2400 - returns the minimum stake required for a candidate to be in the active set

None

Deprecated as of runtime 2400

Deprecated as of runtime 2400

minDelegation() - returns the minimum delegation amount

None

u128 - returns the minimum delegation amount

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the minimum delegation amount
    const minDelegation = await api.consts.parachainStaking.minDelegation;

    console.log('Minimum Delegation Amount:', minDelegation.toString(), 'Wei');
    console.log(
      'Minimum Delegation Amount in DEV:',
      (BigInt(minDelegation) / BigInt(10 ** 18)).toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying min delegation amount:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
minDelegatorStk() - deprecated as of runtime 2500 - returns the minimum stake for an account to be a delegator

None

Deprecated as of runtime 2500

Deprecated as of runtime 2500

minSelectedCandidates() - returns the minimum number of selected candidates in the active set every round

None

u32 - the minimum number of selected candidates in the active set every round

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the minimum number of selected candidates
    const minSelectedCandidates =
      await api.consts.parachainStaking.minSelectedCandidates;

    console.log(
      'Minimum Selected Candidates:',
      minSelectedCandidates.toString()
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying min selected candidates:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
revokeDelegationDelay() - returns the number of rounds that must be waited before a scheduled request to revoke a delegation can be executed

None

u32 - the number of rounds that must be waited before a scheduled request to revoke a delegation can be executed

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the revoke delegation delay
    const revokeDelegationDelay =
      await api.consts.parachainStaking.revokeDelegationDelay;

    console.log(
      'Revoke Delegation Delay:',
      revokeDelegationDelay.toString(),
      'rounds'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying revoke delegation delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
rewardPaymentDelay() - returns the number of rounds that must be waited after which block authors are rewarded

None

u32 - The number of rounds that must be waited after which block authors are rewarded

import { ApiPromise, WsProvider } from '@polkadot/api';

const main = async () => {
  // Initialize the API
  const api = await ApiPromise.create({
    provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'),
  });

  try {
    // Get the reward payment delay
    const rewardPaymentDelay =
      await api.consts.parachainStaking.rewardPaymentDelay;

    console.log(
      'Reward Payment Delay:',
      rewardPaymentDelay.toString(),
      'rounds'
    );

    process.exit(0);
  } catch (error) {
    console.error('Error querying reward payment delay:', error);
    process.exit(1);
  }
};

// Execute the script
main().catch((error) => {
  console.error('Script error:', error);
  process.exit(1);
});
Last update: November 22, 2024
| Created: July 9, 2022