@polkadot/types/interfaces#DispatchInfo TypeScript Examples

The following examples show how to use @polkadot/types/interfaces#DispatchInfo. 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: block.ts    From moonbeam with GNU General Public License v3.0 6 votes vote down vote up
export function mapExtrinsics(
  extrinsics: Extrinsic[] | any,
  records: FrameSystemEventRecord[] | any,
  fees?: RuntimeDispatchInfo[] | any
): TxWithEventAndFee[] {
  return extrinsics.map((extrinsic, index): TxWithEventAndFee => {
    let dispatchError: DispatchError | undefined;
    let dispatchInfo: DispatchInfo | undefined;

    const events = records
      .filter(({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index))
      .map(({ event }) => {
        if (event.section === "system") {
          if (event.method === "ExtrinsicSuccess") {
            dispatchInfo = event.data[0] as any as DispatchInfo;
          } else if (event.method === "ExtrinsicFailed") {
            dispatchError = event.data[0] as any as DispatchError;
            dispatchInfo = event.data[1] as any as DispatchInfo;
          }
        }

        return event as any;
      });

    return { dispatchError, dispatchInfo, events, extrinsic, fee: fees ? fees[index] : undefined };
  });
}
Example #2
Source File: Row.tsx    From gear-js with GNU General Public License v3.0 5 votes vote down vote up
Row = ({ extrinsic, events }: Props) => {
  const getEvents = () => events.map((event, index) => <Event key={index} value={event} className={styles.event} />);

  const getInfoEvent = () =>
    events.find(({ section, method }) => {
      const isSystem = section === Sections.SYSTEM;
      const isExtrinsic = method === Methods.EXTRINSIC_FAILED || method === Methods.EXTRINSIC_SUCCESS;

      return isSystem && isExtrinsic;
    });

  const getDispatchInfo = () => {
    const infoEvent = getInfoEvent();

    if (infoEvent) {
      const { method, data } = infoEvent;
      const isSuccess = method === Methods.EXTRINSIC_SUCCESS;
      const index = isSuccess ? 0 : 1;

      return data[index] as DispatchInfo;
    }
  };

  const { isSigned, signer } = extrinsic;
  const { weight } = getDispatchInfo() || {};

  const formattedSigner = isSigned && signer.toString();
  const formattedWeight = weight?.toHuman();
  const textClassName = clsx(styles.cell, styles.text);

  return (
    <>
      <div className={styles.cell}>
        <Extrinsic extrinsic={extrinsic} className={styles.event} />
      </div>
      <div className={styles.cell}>{getEvents()}</div>
      <div className={textClassName}>{formattedWeight}</div>
      <div className={textClassName}>{formattedSigner}</div>
    </>
  );
}
Example #3
Source File: block.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
verifyBlockFees = async (
  context: DevTestContext,
  fromBlockNumber: number,
  toBlockNumber: number,
  expect,
  expectedBalanceDiff: bigint
) => {
  const api = context.polkadotApi;
  debug(`========= Checking block ${fromBlockNumber}...${toBlockNumber}`);
  let sumBlockFees = 0n;
  let sumBlockBurnt = 0n;
  let blockCount = 0;

  // Get from block hash and totalSupply
  const fromPreBlockHash = (await api.rpc.chain.getBlockHash(fromBlockNumber - 1)).toString();
  const fromPreSupply = (await (
    await api.at(fromPreBlockHash)
  ).query.balances.totalIssuance()) as any;
  let previousBlockHash = fromPreBlockHash;

  // Get to block hash and totalSupply
  const toBlockHash = (await api.rpc.chain.getBlockHash(toBlockNumber)).toString();
  const toSupply = (await (await api.at(toBlockHash)).query.balances.totalIssuance()) as any;

  // fetch block information for all blocks in the range
  await exploreBlockRange(
    api,
    { from: fromBlockNumber, to: toBlockNumber, concurrency: 5 },
    async (blockDetails) => {
      blockCount++;
      let blockFees = 0n;
      let blockBurnt = 0n;

      // iterate over every extrinsic
      for (const { events, extrinsic, fee } of blockDetails.txWithEvents) {
        // This hash will only exist if the transaction was executed through ethereum.
        let ethereumAddress = "";

        if (extrinsic.method.section == "ethereum") {
          // Search for ethereum execution
          events.forEach((event) => {
            if (event.section == "ethereum" && event.method == "Executed") {
              ethereumAddress = event.data[0].toString();
            }
          });
        }

        let txFees = 0n;
        let txBurnt = 0n;

        // For every extrinsic, iterate over every event
        // and search for ExtrinsicSuccess or ExtrinsicFailed
        for (const event of events) {
          if (
            event.section == "system" &&
            (event.method == "ExtrinsicSuccess" || event.method == "ExtrinsicFailed")
          ) {
            const dispatchInfo =
              event.method == "ExtrinsicSuccess"
                ? (event.data[0] as DispatchInfo)
                : (event.data[1] as DispatchInfo);

            // We are only interested in fee paying extrinsics:
            // Either ethereum transactions or signed extrinsics with fees (substrate tx)
            // TODO: sudo should not have paysFee
            if (
              dispatchInfo.paysFee.isYes &&
              extrinsic.method.section !== "sudo" &&
              (!extrinsic.signer.isEmpty || extrinsic.method.section == "ethereum")
            ) {
              if (extrinsic.method.section == "ethereum") {
                // For Ethereum tx we caluculate fee by first converting weight to gas
                const gasFee = dispatchInfo.weight.toBigInt() / WEIGHT_PER_GAS;
                let ethTxWrapper = extrinsic.method.args[0] as any;
                let gasPrice;
                // Transaction is an enum now with as many variants as supported transaction types.
                if (ethTxWrapper.isLegacy) {
                  gasPrice = ethTxWrapper.asLegacy.gasPrice.toBigInt();
                } else if (ethTxWrapper.isEip2930) {
                  gasPrice = ethTxWrapper.asEip2930.gasPrice.toBigInt();
                } else if (ethTxWrapper.isEip1559) {
                  let number = blockDetails.block.header.number.toNumber();
                  // The on-chain base fee used by the transaction. Aka the parent block's base fee.
                  //
                  // Note on 1559 fees: no matter what the user was willing to pay (maxFeePerGas),
                  // the transaction fee is ultimately computed using the onchain base fee. The
                  // additional tip eventually paid by the user (maxPriorityFeePerGas) is purely a
                  // prioritization component: the EVM is not aware of it and thus not part of the
                  // weight cost of the extrinsic.
                  gasPrice = BigInt((await context.web3.eth.getBlock(number - 1)).baseFeePerGas);
                }
                // And then multiplying by gasPrice
                txFees = gasFee * gasPrice;
              } else {
                // For a regular substrate tx, we use the partialFee
                txFees = fee.partialFee.toBigInt();
              }
              txBurnt += (txFees * 80n) / 100n; // 20% goes to treasury

              blockFees += txFees;
              blockBurnt += txBurnt;

              const origin = extrinsic.signer.isEmpty
                ? ethereumAddress
                : extrinsic.signer.toString();

              // Get balance of the origin account both before and after extrinsic execution
              const fromBalance = (await (
                await api.at(previousBlockHash)
              ).query.system.account(origin)) as any;
              const toBalance = (await (
                await api.at(blockDetails.block.hash)
              ).query.system.account(origin)) as any;

              expect(txFees.toString()).to.eq(
                (
                  (((fromBalance.data.free.toBigInt() as any) -
                    toBalance.data.free.toBigInt()) as any) - expectedBalanceDiff
                ).toString()
              );
            }
          }
        }
        // Then search for Deposit event from treasury
        // This is for bug detection when the fees are not matching the expected value
        // TODO: sudo should not have treasury event
        for (const event of events) {
          if (
            event.section == "treasury" &&
            event.method == "Deposit" &&
            extrinsic.method.section !== "sudo"
          ) {
            const deposit = (event.data[0] as any).toBigInt();
            // Compare deposit event amont to what should have been sent to deposit
            // (if they don't match, which is not a desired behavior)
            expect(txFees - txBurnt).to.eq(deposit);
            if (txFees - txBurnt !== deposit) {
              debug("Desposit Amount Discrepancy!");
              debug(`fees not burnt : ${(txFees - txBurnt).toString().padStart(30, " ")}`);
              debug(`       deposit : ${deposit.toString().padStart(30, " ")}`);
            }
          }
        }
      }
      sumBlockFees += blockFees;
      sumBlockBurnt += blockBurnt;
      previousBlockHash = blockDetails.block.hash.toString();
    }
  );

  expect(fromPreSupply.toBigInt() - toSupply.toBigInt()).to.eq(sumBlockBurnt);

  // Log difference in supply, we should be equal to the burnt fees
  debug(
    `  supply diff: ${(fromPreSupply.toBigInt() - toSupply.toBigInt())
      .toString()
      .padStart(30, " ")}`
  );
  debug(`  burnt fees : ${sumBlockBurnt.toString().padStart(30, " ")}`);
  debug(`  total fees : ${sumBlockFees.toString().padStart(30, " ")}`);
}