@polkadot/api/types#ApiDecoration TypeScript Examples

The following examples show how to use @polkadot/api/types#ApiDecoration. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: test-author-filter-consistency.ts    From moonbeam with GNU General Public License v3.0 6 votes vote down vote up
describeSmokeSuite(`Verify author filter consistency`, { wssUrl, relayWssUrl }, (context) => {
  const accounts: { [account: string]: FrameSystemAccountInfo } = {};

  let atBlockNumber: number = 0;
  let apiAt: ApiDecoration<"promise"> = null;
  let specVersion: number = 0;

  before("Setup api", async function () {
    atBlockNumber = (await context.polkadotApi.rpc.chain.getHeader()).number.toNumber();
    apiAt = await context.polkadotApi.at(
      await context.polkadotApi.rpc.chain.getBlockHash(atBlockNumber)
    );
    specVersion = (await apiAt.query.system.lastRuntimeUpgrade()).unwrap().specVersion.toNumber();
  });

  it("should have eligibility > 0", async function () {
    if (specVersion < 1500) {
      const eligibilityRatio = await apiAt.query.authorFilter.eligibleRatio();
      expect(eligibilityRatio.toBigInt() > 0n).to.be.true;
    }
    if (specVersion >= 1500) {
      // TODO remove `as any` once api-augment is updated
      const eligibilityCount = (await apiAt.query.authorFilter.eligibleCount()) as any;
      expect(eligibilityCount.toNumber() > 0).to.be.true;
    }
    debug(`Verified eligibility`);
  });
});
Example #2
Source File: test-treasury-consistency.ts    From moonbeam with GNU General Public License v3.0 6 votes vote down vote up
describeSmokeSuite(`Verify treasury consistency`, { wssUrl, relayWssUrl }, (context) => {
  const accounts: { [account: string]: FrameSystemAccountInfo } = {};

  let atBlockNumber: number = 0;
  let apiAt: ApiDecoration<"promise"> = null;

  before("Setup api", async function () {
    atBlockNumber = (await context.polkadotApi.rpc.chain.getHeader()).number.toNumber();
    apiAt = await context.polkadotApi.at(
      await context.polkadotApi.rpc.chain.getBlockHash(atBlockNumber)
    );
  });

  it("should have value > 0", async function () {
    // Load data
    const treasuryPalletId = await context.polkadotApi.consts.treasury.palletId;
    const treasuryAccount = await apiAt.query.system.account(
      `0x6d6f646C${treasuryPalletId.toString().slice(2)}0000000000000000`
    );

    expect(treasuryAccount.data.free.toBigInt() > 0n).to.be.true;
    expect(treasuryAccount.data.reserved.toBigInt()).to.be.equal(0n);

    debug(`Verified treasury free/reserved balance`);
  });
});
Example #3
Source File: test-balances-consistency.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeSmokeSuite(`Verify balances consistency`, { wssUrl, relayWssUrl }, (context) => {
  const accounts: { [account: string]: FrameSystemAccountInfo } = {};

  let atBlockNumber: number = 0;
  let apiAt: ApiDecoration<"promise"> = null;
  let specVersion: number = 0;

  before("Retrieve all balances", async function () {
    // It takes time to load all the accounts.
    this.timeout(3600000); // 1 hour should be enough

    const limit = 1000;
    let last_key = "";
    let count = 0;

    atBlockNumber = process.env.BLOCK_NUMBER
      ? parseInt(process.env.BLOCK_NUMBER)
      : (await context.polkadotApi.rpc.chain.getHeader()).number.toNumber();
    apiAt = await context.polkadotApi.at(
      await context.polkadotApi.rpc.chain.getBlockHash(atBlockNumber)
    );
    specVersion = (await apiAt.query.system.lastRuntimeUpgrade()).unwrap().specVersion.toNumber();

    if (process.env.ACCOUNT_ID) {
      const userId = process.env.ACCOUNT_ID.toLowerCase();
      accounts[userId] = await apiAt.query.system.account(userId);
      return;
    }

    // loop over all system accounts
    while (true) {
      let query = await apiAt.query.system.account.entriesPaged({
        args: [],
        pageSize: limit,
        startKey: last_key,
      });

      if (query.length == 0) {
        break;
      }
      count += query.length;

      for (const user of query) {
        let accountId = `0x${user[0].toHex().slice(-40)}`;
        last_key = user[0].toString();
        accounts[accountId] = user[1];
      }
      if (count % (10 * limit) == 0) {
        debug(`Retrieved ${count} accounts`);
      }
    }
    debug(`Retrieved ${count} total accounts`);
  });

  it("should have matching deposit/reserved", async function () {
    this.timeout(240000);
    // Load data
    const [
      proxies,
      proxyAnnouncements,
      treasuryProposals,
      mappingWithDeposit,
      candidateInfo,
      delegatorState,
      identities,
      subItentities,
      democracyDeposits,
      preimages,
      assets,
      assetsMetadata,
      localAssets,
      localAssetsMetadata,
      localAssetDeposits,
      namedReserves,
    ] = await Promise.all([
      apiAt.query.proxy.proxies.entries(),
      apiAt.query.proxy.announcements.entries(),
      apiAt.query.treasury.proposals.entries(),
      apiAt.query.authorMapping.mappingWithDeposit.entries(),
      apiAt.query.parachainStaking.candidateInfo.entries(),
      apiAt.query.parachainStaking.delegatorState.entries(),
      apiAt.query.identity.identityOf.entries(),
      apiAt.query.identity.subsOf.entries(),
      apiAt.query.democracy.depositOf.entries(),
      apiAt.query.democracy.preimages.entries(),
      apiAt.query.assets.asset.entries(),
      apiAt.query.assets.metadata.entries(),
      apiAt.query.localAssets.asset.entries(),
      apiAt.query.localAssets.metadata.entries(),
      apiAt.query.assetManager.localAssetDeposit.entries(),
      apiAt.query.balances.reserves.entries(),
    ]);

    const expectedReserveByAccount: {
      [accountId: string]: { total: bigint; reserved: { [key: string]: bigint } };
    } = [
      treasuryProposals.map((proposal) => ({
        accountId: `0x${proposal[1].unwrap().proposer.toHex().slice(-40)}`,
        reserved: {
          treasury: proposal[1].unwrap().bond.toBigInt(),
        },
      })),
      proxies.map((proxy) => ({
        accountId: `0x${proxy[0].toHex().slice(-40)}`,
        reserved: {
          proxy: proxy[1][1].toBigInt(),
        },
      })),
      proxyAnnouncements.map((announcement) => ({
        accountId: `0x${announcement[0].toHex().slice(-40)}`,
        reserved: {
          announcement: announcement[1][1].toBigInt(),
        },
      })),
      mappingWithDeposit.map((mapping) => ({
        accountId: `0x${mapping[1].unwrap().account.toHex().slice(-40)}`,
        reserved: {
          mapping: mapping[1].unwrap().deposit.toBigInt(),
        },
      })),
      candidateInfo.map((candidate) => ({
        accountId: `0x${candidate[0].toHex().slice(-40)}`,
        reserved: {
          candidate: candidate[1].unwrap().bond.toBigInt(),
        },
      })),
      delegatorState.map((delegator) => ({
        accountId: `0x${delegator[0].toHex().slice(-40)}`,
        reserved: {
          delegator: delegator[1].unwrap().total.toBigInt(),
        },
      })),
      identities.map((identity) => ({
        accountId: `0x${identity[0].toHex().slice(-40)}`,
        reserved: {
          identity: identity[1].unwrap().deposit.toBigInt(),
        },
      })),
      subItentities.map((subIdentity) => ({
        accountId: `0x${subIdentity[0].toHex().slice(-40)}`,
        reserved: {
          identity: subIdentity[1][0].toBigInt(),
        },
      })),
      Object.values(
        democracyDeposits
          .map((depositOf) =>
            depositOf[1].unwrap()[0].map((deposit) => ({
              accountId: deposit.toHex(),
              reserved: depositOf[1].unwrap()[1].toBigInt(),
            }))
          )
          .flat()
          .reduce(
            (p, deposit) => {
              // We merge multiple reserves together for same account
              if (!p[deposit.accountId]) {
                p[deposit.accountId] = {
                  accountId: deposit.accountId,
                  reserved: {
                    democratyDeposit: 0n,
                  },
                };
              }
              p[deposit.accountId].reserved.democratyDeposit += deposit.reserved;
              return p;
            },
            {} as {
              [accountId: string]: { accountId: string; reserved: { [key: string]: bigint } };
            }
          )
      ),
      preimages
        .filter((preimage) => preimage[1].unwrap().isAvailable)
        .map((preimage) => ({
          accountId: preimage[1].unwrap().asAvailable.provider.toHex(),
          reserved: {
            preimage: preimage[1].unwrap().asAvailable.deposit.toBigInt(),
          },
        })),
      assets.map((asset) => ({
        accountId: `0x${asset[1].unwrap().owner.toHex().slice(-40)}`,
        reserved: {
          asset: asset[1].unwrap().deposit.toBigInt(),
        },
      })),
      assetsMetadata.map((assetMetadata) => ({
        accountId: `0x${assets
          .find((asset) => asset[0].toHex().slice(-64) == assetMetadata[0].toHex().slice(-64))[1]
          .unwrap()
          .owner.toHex()
          .slice(-40)}`,
        reserved: {
          assetMetadata: assetMetadata[1].deposit.toBigInt(),
        },
      })),
      localAssets.map((localAsset) => ({
        accountId: `0x${localAsset[1].unwrap().owner.toHex().slice(-40)}`,
        reserved: {
          localAsset: localAsset[1].unwrap().deposit.toBigInt(),
        },
      })),
      localAssetsMetadata.map((localAssetMetadata) => ({
        accountId: `0x${localAssets
          .find(
            (localAsset) =>
              localAsset[0].toHex().slice(-64) == localAssetMetadata[0].toHex().slice(-64)
          )[1]
          .unwrap()
          .owner.toHex()
          .slice(-40)}`,
        reserved: {
          localAssetMetadata: localAssetMetadata[1].deposit.toBigInt(),
        },
      })),
      localAssetDeposits.map((assetDeposit) => ({
        accountId: assetDeposit[1].unwrap().creator.toHex(),
        reserved: {
          localAssetDeposit: assetDeposit[1].unwrap().deposit.toBigInt(),
        },
      })),
      namedReserves.map((namedReservesOf) => ({
        accountId: `0x${namedReservesOf[0].toHex().slice(-40)}`,
        reserved: {
          named: namedReservesOf[1]
            .map((namedDeposit) => namedDeposit.amount.toBigInt())
            .reduce((accumulator, curr) => accumulator + curr),
        },
      })),
    ]
      .flat()
      .reduce((p, v) => {
        if (!p[v.accountId]) {
          p[v.accountId] = {
            total: 0n,
            reserved: {},
          };
        }
        p[v.accountId].total += Object.keys(v.reserved).reduce((p, key) => p + v.reserved[key], 0n);
        p[v.accountId].reserved = { ...p[v.accountId].reserved, ...v.reserved };
        return p;
      }, {});

    debug(`Retrieved ${Object.keys(expectedReserveByAccount).length} deposits`);

    for (const accountId of Object.keys(accounts)) {
      let reserved = accounts[accountId].data.reserved.toBigInt();
      const expectedReserve = expectedReserveByAccount[accountId]?.total || 0n;

      expect(reserved).to.equal(
        expectedReserve,
        `${accountId} (reserved: ${reserved} vs expected: ${expectedReserve})\n (${Object.keys(
          expectedReserveByAccount[accountId]?.reserved || {}
        )
          .map(
            (key) =>
              `${key}: ${printTokens(
                context.polkadotApi,
                expectedReserveByAccount[accountId].reserved[key]
              )}`
          )
          .join(` - `)})`
      );
    }
    debug(`Verified ${Object.keys(accounts).length} total reserved balance`);
  });

  it("should match total supply", async function () {
    const totalIssuance = await apiAt.query.balances.totalIssuance();

    expect(
      Object.keys(accounts).reduce(
        (p, accountId) =>
          accounts[accountId].data.free.toBigInt() +
          accounts[accountId].data.reserved.toBigInt() +
          p,
        0n
      )
    ).to.equal(totalIssuance.toBigInt());
    debug(`Verified total issuance`);
  });
});
Example #4
Source File: test-relay-xcm-fees.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeSmokeSuite(`Verify XCM weight fees for relay`, { wssUrl, relayWssUrl }, (context) => {
  const accounts: { [account: string]: FrameSystemAccountInfo } = {};

  let atBlockNumber: number = 0;
  let relayAtBlockNumber: number = 0;
  let apiAt: ApiDecoration<"promise"> = null;
  let relayApiAt: ApiDecoration<"promise"> = null;

  before("Setup api", async function () {
    atBlockNumber = (await context.polkadotApi.rpc.chain.getHeader()).number.toNumber();
    apiAt = await context.polkadotApi.at(
      await context.polkadotApi.rpc.chain.getBlockHash(atBlockNumber)
    );

    relayAtBlockNumber = (await context.relayApi.rpc.chain.getHeader()).number.toNumber();
    relayApiAt = await context.relayApi.at(
      await context.relayApi.rpc.chain.getBlockHash(relayAtBlockNumber)
    );
  });

  it("should have value over relay expected fees", async function () {
    // Load data
    const relayRuntime = context.relayApi.runtimeVersion.specName.toString();
    console.log(relayRuntime);
    const relayMultiLocation: MultiLocation = context.polkadotApi.createType(
      "MultiLocation",
      JSON.parse('{ "parents": 1, "interior": "Here" }')
    );

    const units = relayRuntime.startsWith("polkadot")
      ? 10_000_000_000n
      : relayRuntime.startsWith("kusama") ||
        relayRuntime.startsWith("rococo") ||
        relayRuntime.startsWith("westend")
      ? 1_000_000_000_000n
      : 1_000_000_000_000n;

    const seconds = 1_000_000_000_000n;

    const cent =
      relayRuntime.startsWith("polkadot") ||
      relayRuntime.startsWith("rococo") ||
      relayRuntime.startsWith("westend")
        ? units / 100n
        : relayRuntime.startsWith("kusama")
        ? units / 30_000n
        : units / 100n;
    const coef = cent / 10n;

    const relayBaseWeight =
      relayApiAt.consts.system.blockWeights.perClass.normal.baseExtrinsic.toBigInt();

    const expectedFeePerSecond = (coef * seconds) / relayBaseWeight;

    const parachainRuntime = context.polkadotApi.runtimeVersion.specVersion.toNumber();

    let feePerSecondValueForRelay;
    if (parachainRuntime >= 1600) {
      feePerSecondValueForRelay = (
        (await apiAt.query.xcmTransactor.destinationAssetFeePerSecond(relayMultiLocation)) as any
      ).unwrap();
    } else {
      feePerSecondValueForRelay = (
        await apiAt.query.xcmTransactor.transactInfoWithWeightLimit(relayMultiLocation)
      ).unwrap().feePerSecond;
    }
    expect(
      feePerSecondValueForRelay.toBigInt() >= expectedFeePerSecond,
      `failed check: feePerSecond: ${feePerSecondValueForRelay} > expected ${expectedFeePerSecond}`
    ).to.be.true;
    expect(
      // Conservative approach to allow up to 2 time the fees
      feePerSecondValueForRelay.toBigInt() < expectedFeePerSecond * 2n,
      `failed check: feePerSecond: ${feePerSecondValueForRelay} < expected ${
        expectedFeePerSecond * 2n
      }`
    ).to.be.true;

    debug(
      `Verified feePerSecond for ${relayMultiLocation} transactInfos ` +
        `within relay base weight range`
    );
  });
});
Example #5
Source File: test-staking-consistency.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeSmokeSuite(`Verify staking consistency`, { wssUrl, relayWssUrl }, (context) => {
  let atBlockNumber: number = 0;
  let apiAt: ApiDecoration<"promise"> = null;
  let specVersion: number = 0;
  let maxTopDelegationsPerCandidate: number = 0;
  let allCandidateInfo: [StorageKey<[AccountId20]>, Option<ParachainStakingCandidateMetadata>][];
  let candidatePool: ParachainStakingSetOrderedSetBond;
  let allDelegatorState: [StorageKey<[AccountId20]>, Option<ParachainStakingDelegator>][];
  let allTopDelegations: [StorageKey<[AccountId20]>, Option<ParachainStakingDelegations>][];
  let delegatorsPerCandidates: {
    [index: string]: {
      delegator: string;
      delegation: ParachainStakingBond;
    }[];
  };

  before("Setup apiAt", async function () {
    // It takes time to load all the accounts.
    this.timeout(180000);

    atBlockNumber = (await context.polkadotApi.rpc.chain.getHeader()).number.toNumber();
    apiAt = await context.polkadotApi.at(
      await context.polkadotApi.rpc.chain.getBlockHash(atBlockNumber)
    );
    specVersion = (await apiAt.query.system.lastRuntimeUpgrade()).unwrap().specVersion.toNumber();
    maxTopDelegationsPerCandidate =
      apiAt.consts.parachainStaking.maxTopDelegationsPerCandidate.toNumber();

    allCandidateInfo = await apiAt.query.parachainStaking.candidateInfo.entries();
    allDelegatorState = await apiAt.query.parachainStaking.delegatorState.entries();
    candidatePool = await apiAt.query.parachainStaking.candidatePool();
    allTopDelegations = await apiAt.query.parachainStaking.topDelegations.entries();

    delegatorsPerCandidates = allDelegatorState.reduce((p, state) => {
      for (const delegation of state[1].unwrap().delegations) {
        if (!p[delegation.owner.toHex()]) {
          p[delegation.owner.toHex()] = [];
        }
        p[delegation.owner.toHex()].push({
          delegator: `0x${state[0].toHex().slice(-40)}`,
          delegation,
        });
      }
      return p;
    }, {});
  });

  it("candidate totalCounted matches top X delegations", async function () {
    for (const candidate of allCandidateInfo) {
      const accountId = `0x${candidate[0].toHex().slice(-40)}`;
      const delegators = delegatorsPerCandidates[accountId] || [];

      const expectedTotalCounted =
        delegators
          .map((d) => d.delegation.amount.toBigInt())
          .sort((a, b) => (a < b ? 1 : a > b ? -1 : 0))
          .filter((_, i) => i < maxTopDelegationsPerCandidate)
          .reduce((p, amount) => p + amount, 0n) + candidate[1].unwrap().bond.toBigInt();

      expect(candidate[1].unwrap().totalCounted.toBigInt(), `Candidate: ${accountId}`).to.equal(
        expectedTotalCounted
      );
    }

    debug(
      `Verified ${Object.keys(allCandidateInfo).length} candidates and ${
        allDelegatorState.length
      } delegators`
    );
  });

  it("candidate topDelegator total matches the sum", async function () {
    for (const topDelegation of allTopDelegations) {
      expect(
        topDelegation[1].unwrap().total.toBigInt(),
        `topDelegations of 0x${topDelegation[0].toHex().slice(-40)}`
      ).to.equal(
        topDelegation[1]
          .unwrap()
          .delegations.reduce((p, delegation) => p + delegation.amount.toBigInt(), 0n)
      );
    }
  });

  it("candidate topDelegator total matches candidate totalCounted - bond", async function () {
    for (const candidate of allCandidateInfo) {
      const accountId = `0x${candidate[0].toHex().slice(-40)}`;
      const topDelegation = allTopDelegations
        .find((t) => `0x${t[0].toHex().slice(-40)}` == accountId)[1]
        .unwrap();
      expect(topDelegation.total.toBigInt()).to.equal(
        candidate[1].unwrap().totalCounted.toBigInt() - candidate[1].unwrap().bond.toBigInt()
      );
    }
  });

  it("candidate topDelegations matches top X delegators", async function () {
    for (const candidate of allCandidateInfo) {
      const accountId = `0x${candidate[0].toHex().slice(-40)}`;
      const delegators = delegatorsPerCandidates[accountId] || [];

      const topDelegators = delegators
        .sort((a, b) =>
          a.delegation.amount.toBigInt() < b.delegation.amount.toBigInt()
            ? 1
            : a.delegation.amount.toBigInt() > b.delegation.amount.toBigInt()
            ? -1
            : 0
        )
        .filter((_, i) => i < maxTopDelegationsPerCandidate);

      const topDelegations = allTopDelegations
        .find((t) => `0x${t[0].toHex().slice(-40)}` == accountId)[1]
        .unwrap();

      expect(topDelegations.total.toBigInt()).to.equal(
        topDelegators
          .map((d) => d.delegation.amount.toBigInt())
          .reduce((p, amount) => p + amount, 0n)
      );

      // Verify matching length
      expect(topDelegations.delegations.length).to.equal(topDelegators.length);

      // Verify each delegation amount matches
      // It is not possible to verify the account as there is no deterministic
      // way to differenciate the order of 2 delegators with same amount
      for (const index in topDelegators) {
        expect(
          topDelegators[index].delegation.amount.toBigInt(),
          `topDelegators[${index}] - ${topDelegators[index].delegator}`
        ).to.equal(topDelegations.delegations[index].amount.toBigInt());
      }
    }

    debug(
      `Verified ${Object.keys(allCandidateInfo).length} candidates and ${
        allDelegatorState.length
      } delegators`
    );
  });

  it("all delegators lessTotal matches revoke/decrease requests", async function () {
    let checks = 0;
    if (specVersion >= 1500) {
      const delegationScheduledRequests =
        await apiAt.query.parachainStaking.delegationScheduledRequests.entries();
      const delegatorRequests = delegationScheduledRequests.reduce((p, requests: any) => {
        for (const request of requests[1]) {
          const delegator = request.delegator.toHex();
          if (!p[delegator]) {
            p[delegator] = [];
          }
          p[delegator].push(request);
        }
        return p;
      }, {} as { [delegator: string]: { delegator: any; whenExecutable: any; action: any }[] });

      for (const state of allDelegatorState) {
        const delegator = `0x${state[0].toHex().slice(-40)}`;
        const totalRequestAmount = (delegatorRequests[delegator] || []).reduce(
          (p, v) =>
            p +
            (v.action.isDecrease ? v.action.asDecrease.toBigInt() : v.action.asRevoke.toBigInt()),
          0n
        );

        expect((state[1].unwrap() as any).lessTotal.toBigInt(), `delegator: ${delegator}`).to.equal(
          totalRequestAmount
        );
        checks++;
      }
    }

    if (specVersion < 1500) {
      for (const state of allDelegatorState) {
        const delegator = `0x${state[0].toHex().slice(-40)}`;
        const totalRequestAmount = Array.from(state[1].unwrap().requests.requests.values()).reduce(
          (p, v) => p + v.amount.toBigInt(),
          0n
        );

        expect(state[1].unwrap().requests.lessTotal.toBigInt(), `delegator: ${delegator}`).to.equal(
          totalRequestAmount
        );
        checks++;
      }
    }

    debug(`Verified ${checks} lessTotal (runtime: ${specVersion})`);
  });

  it("candidatePool matches candidateInfo", async function () {
    let foundCandidateInPool = 0;
    for (const candidate of allCandidateInfo) {
      const candidateId = `0x${candidate[0].toHex().slice(-40)}`;
      const candidateData = candidate[1].unwrap();

      if (candidateData.status.isLeaving || candidateData.status.isIdle) {
        expect(
          candidatePool.find((c) => c.owner.toHex() == candidateId),
          `Candidate ${candidateId} is leaving and should not be in the candidate pool`
        ).to.be.undefined;
      } else {
        expect(
          candidatePool.find((c) => c.owner.toHex() == candidateId),
          `Candidate ${candidateId} is active and should be in the candidate pool`
        ).to.not.be.undefined;
        foundCandidateInPool++;
      }
    }

    expect(foundCandidateInPool, "Candidate in pool not matching expected number").to.be.equal(
      candidatePool.length
    );

    debug(
      `Verified ${Object.keys(allCandidateInfo).length} candidates info and ${
        candidatePool.length
      } in the pool`
    );
  });
});