@ethersproject/abstract-provider#TransactionReceipt TypeScript Examples

The following examples show how to use @ethersproject/abstract-provider#TransactionReceipt. 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: snapshot.ts    From trident with GNU General Public License v3.0 6 votes vote down vote up
export async function snapshotGasCost(
  x:
    | TransactionResponse
    | Promise<TransactionResponse>
    | ContractTransaction
    | Promise<ContractTransaction>
    | TransactionReceipt
    | Promise<BigNumber>
    | BigNumber
    | Contract
    | Promise<Contract>
): Promise<void> {
  const resolved = await x;
  if ("deployTransaction" in resolved) {
    const receipt = await resolved.deployTransaction.wait();
    expect(receipt.gasUsed.toNumber()).toMatchSnapshot();
  } else if ("wait" in resolved) {
    const waited = await resolved.wait();
    expect(waited.gasUsed.toNumber()).toMatchSnapshot();
  } else if (BigNumber.isBigNumber(resolved)) {
    expect(resolved.toNumber()).toMatchSnapshot();
  }
}
Example #2
Source File: Provider.ts    From evm-provider.js with Apache License 2.0 6 votes vote down vote up
/**
   * Unimplemented, will always fail.
   */
  async waitForTransaction(
    transactionHash: string,
    confirmations?: number,
    timeout?: number
  ): Promise<TransactionReceipt> {
    return this._fail('waitForTransaction');
  }
Example #3
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
_getTxReceiptFromCache = async (txHash: string): Promise<TransactionReceipt | null> => {
    const targetBlockNumber = this.localMode
      ? await runWithRetries(this._cache!.getBlockNumber.bind(this._cache!), [txHash])
      : this._cache?.getBlockNumber(txHash);

    if (!targetBlockNumber) return null;

    const targetBlockHash = this.localMode
      ? await runWithRetries(async () => this.api.rpc.chain.getBlockHash(targetBlockNumber))
      : await this.api.rpc.chain.getBlockHash(targetBlockNumber);

    return this.getTransactionReceiptAtBlock(txHash, targetBlockHash.toHex());
  };
Example #4
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
_getMinedTXReceipt = async (txHash: string): Promise<TransactionReceipt | TransactionReceiptGQL | null> => {
    const txFromCache = await this._getTxReceiptFromCache(txHash);
    if (txFromCache) return txFromCache;

    const txFromSubql = await this.subql?.getTxReceiptByHash(txHash);
    const res = txFromSubql || null;
    if (res) {
      res.blockNumber = +res.blockNumber;
      res.transactionIndex = +res.transactionIndex;
      res.gasUsed = BigNumber.from(res.gasUsed);
    }
    return res;
  };
Example #5
Source File: DataProvider.ts    From evm-provider.js with Apache License 2.0 6 votes vote down vote up
/**
   * Get the transaction receipt for a transaction.
   * @param txHash The transaction hash to get the receipt for
   * @param resolveBlockNumber The block the transaction was resolved
   * @returns A promise resolving to the transaction's receipt
   */
  abstract getTransactionReceipt(
    txHash: string,
    resolveBlockNumber: (
      blockTag?: BlockTag | Promise<BlockTag>
    ) => Promise<number | undefined>
  ): Promise<TransactionReceipt>;
Example #6
Source File: eip1193-bridge.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
/**
   * Returns the receipt of a transaction by transaction hash. Note That the receipt is not available for pending transactions.
   * @param DATA, 32 Bytes - hash of a transaction
   * @returns TransactionReceipt, A transaction receipt object, or null when no receipt was found:
   */
  async eth_getTransactionReceipt(params: any[]): Promise<TransactionReceipt | null> {
    validate([{ type: 'blockHash' }], params);

    const res = await this.#provider.getTXReceiptByHash(params[0]);
    if (!res) return null;

    // @ts-ignore
    delete res.byzantium;
    // @ts-ignore
    delete res.confirmations;
    return hexlifyRpcResult(res);
  }
Example #7
Source File: DataProvider.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
/**
   * Get the transaction receipt for a transaction.
   * @param txHash The transaction hash to get the receipt for
   * @param resolveBlockNumber The block the transaction was resolved
   * @returns A promise resolving to the transaction's receipt
   */
  abstract getTransactionReceipt(
    txHash: string,
    resolveBlockNumber: (blockTag?: BlockTag | Promise<BlockTag>) => Promise<number | undefined>
  ): Promise<TransactionReceipt>;
Example #8
Source File: EthService.ts    From sakeperp-arbitrageur with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
static async supervise(
        signer: Wallet,
        tx: TransactionResponse,
        timeout: number,
        retry = 3,
    ): Promise<TransactionReceipt> {
        return new Promise((resolve, reject) => {
            // Set timeout for sending cancellation tx at double the gas price
            const timeoutId = setTimeout(async () => {
                const cancelTx = await signer.sendTransaction({
                    to: signer.address,
                    value: 0,
                    gasPrice: tx.gasPrice.mul(2), // TODO Make configurable?
                    nonce: tx.nonce,
                })

                await EthService.log.warn(
                    JSON.stringify({
                        event: "txCancelling",
                        params: {
                            tx: tx.hash,
                            txGasPrice: tx.gasPrice.toString(),
                            cancelTx: cancelTx.hash,
                            cancelTxGasPrice: cancelTx.gasPrice.toString(),
                            nonce: cancelTx.nonce,
                        },
                    }),
                )

                // Yo dawg I heard you like cancelling tx so
                // we put a cancel in your cancel tx so you can supervise while you supervise
                if (retry > 0) {
                    await EthService.supervise(signer, cancelTx, timeout, retry - 1)
                } else {
                    await cancelTx.wait()
                }
                reject({
                    reason: "timeout",
                    tx: tx.hash,
                    cancelTx: cancelTx.hash,
                })
            }, timeout)

            // Otherwise, resolve normally if the original tx is confirmed
            tx.wait().then(result => {
                clearTimeout(timeoutId)
                resolve(result)
            })
        })
    }
Example #9
Source File: Provider.ts    From evm-provider.js with Apache License 2.0 5 votes vote down vote up
async getTransactionReceipt(txHash: string): Promise<TransactionReceipt> {
    if (!this.dataProvider) return this._fail('getTransactionReceipt');
    return this.dataProvider.getTransactionReceipt(
      txHash,
      this._resolveBlockNumber
    );
  }
Example #10
Source File: transactionsUpdater.ts    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
TransactionsUpdater = (): null => {
  const account = useAccount()
  const accountPrev = usePrevious(account)
  const provider = useSignerOrProvider()
  const blockNumber = useBlockNow()

  const state = useTransactionsState()
  const { check, finalize, reset } = useTransactionsDispatch()

  /**
   * Reset transactions state on account change
   */
  useEffect(() => {
    if (accountPrev !== account) {
      reset()
    }
  }, [account, accountPrev, reset])

  /**
   * Check pending transaction status on new blocks, and finalize if possible.
   */
  useEffect(
    (): (() => void) | void => {
      if (provider && blockNumber) {
        let stale = false
        Object.values(state)
          .filter(tx => STATUS_NEEDS_CHECK.includes(tx.status) && tx.hash && tx.blockNumber !== blockNumber)
          .forEach(tx => {
            ;(((provider as Signer).provider || provider) as Provider)
              .getTransactionReceipt(tx.hash as string)
              .then((receipt: TransactionReceipt) => {
                if (!stale) {
                  if (!receipt) {
                    if (tx?.manifest?.id) {
                      check(tx.manifest.id, blockNumber)
                    }
                  } else {
                    finalize(tx.manifest, receipt)
                  }
                }
              })
              .catch(() => {
                if (tx?.manifest?.id) {
                  check(tx.manifest.id, blockNumber)
                }
              })
          })

        return () => {
          stale = true
        }
      }
      return undefined
    },
    // `blockNumber` and `provider` should be the only deps; otherwise it will
    // check too often.
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [blockNumber, provider],
  )

  return null
}
Example #11
Source File: contractCallOutOfGasMock.ts    From useDApp with MIT License 5 votes vote down vote up
transferOutOfGasMock = (): TransactionResponse => {
  return {
    wait: (): Promise<TransactionReceipt> => {
      return Promise.reject({ reason: 'out of gas' })
    },
  } as TransactionResponse
}
Example #12
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
waitForTransaction = (
    transactionHash: string,
    confirmations?: number,
    timeout?: number
  ): Promise<TransactionReceipt> => throwNotImplemented('waitForTransaction');
Example #13
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
getTransactionReceipt = async (txHash: string): Promise<TransactionReceipt> => {
    // @TODO
    // @ts-ignore
    return this.getTXReceiptByHash(txHash);
  };
Example #14
Source File: base-provider.ts    From bodhi.js with Apache License 2.0 5 votes vote down vote up
// @TODO Testing
  getTransactionReceiptAtBlock = async (
    hashOrNumber: number | string | Promise<string>,
    _blockTag: BlockTag | Promise<BlockTag>
  ): Promise<TransactionReceipt> => {
    const blockTag = await this._ensureSafeModeBlockTagFinalization(_blockTag);

    hashOrNumber = await hashOrNumber;
    const header = await this._getBlockHeader(blockTag);
    const blockHash = header.hash.toHex();
    const blockNumber = header.number.toNumber();

    const [block, blockEvents] = await Promise.all([
      this.api.rpc.chain.getBlock(blockHash),
      this.queryStorage<Vec<FrameSystemEventRecord>>('system.events', [], blockHash)
    ]);

    const { transactionHash, transactionIndex, extrinsicIndex, isExtrinsicFailed } = getTransactionIndexAndHash(
      hashOrNumber,
      block.block.extrinsics,
      blockEvents
    );

    const extrinsicEvents = blockEvents.filter(
      (event) => event.phase.isApplyExtrinsic && event.phase.asApplyExtrinsic.toNumber() === extrinsicIndex
    );

    if (isExtrinsicFailed) {
      const [dispatchError] = extrinsicEvents[extrinsicEvents.length - 1].event.data as any[];

      let message = dispatchError.type;

      if (dispatchError.isModule) {
        try {
          const mod = dispatchError.asModule;
          const error = this.api.registry.findMetaError(new Uint8Array([mod.index.toNumber(), mod.error.toNumber()]));
          message = `${error.section}.${error.name}: ${error.docs}`;
        } catch (error) {
          // swallow
        }
      }

      return logger.throwError(`ExtrinsicFailed: ${message}`, Logger.errors.UNKNOWN_ERROR, {
        hash: transactionHash,
        blockHash
      });
    }

    // @TODO
    const evmEvent = findEvmEvent(extrinsicEvents);

    if (!evmEvent) {
      return logger.throwError(`evm event not found`, Logger.errors.UNKNOWN_ERROR, {
        hash: transactionHash,
        blockHash
      });
    }

    const transactionInfo = { transactionIndex, blockHash, transactionHash, blockNumber };

    const partialTransactionReceipt = getPartialTransactionReceipt(evmEvent);

    // to and contractAddress may be undefined
    return this.formatter.receipt({
      confirmations: (await this._getBlockHeader('latest')).number.toNumber() - blockNumber,
      ...transactionInfo,
      ...partialTransactionReceipt,
      logs: partialTransactionReceipt.logs.map((log) => ({
        ...transactionInfo,
        ...log
      }))
    }) as any;
  };
Example #15
Source File: Provider.ts    From evm-provider.js with Apache License 2.0 4 votes vote down vote up
async _resolveTransactionReceipt(
    transactionHash: string,
    blockHash: string,
    from: string
  ): Promise<TransactionReceipt> {
    const detail = await this.scanner.getBlockDetail({
      blockHash: blockHash
    });

    const blockNumber = detail.number;
    const extrinsic = detail.extrinsics.find(
      ({ hash }) => hash === transactionHash
    );

    if (!extrinsic) {
      return logger.throwError(`Transaction hash not found`);
    }

    const transactionIndex = extrinsic.index;

    const events = detail.events.filter(
      ({ phaseIndex }) => phaseIndex === transactionIndex
    );

    const findCreated = events.find(
      (x) =>
        x.section.toUpperCase() === 'EVM' &&
        x.method.toUpperCase() === 'CREATED'
    );

    const findExecuted = events.find(
      (x) =>
        x.section.toUpperCase() === 'EVM' &&
        x.method.toUpperCase() === 'EXECUTED'
    );

    const result = events.find(
      (x) =>
        x.section.toUpperCase() === 'SYSTEM' &&
        x.method.toUpperCase() === 'EXTRINSICSUCCESS'
    );

    if (!result) {
      return logger.throwError(`Can't find event`);
    }

    const status = findCreated || findExecuted ? 1 : 0;

    const contractAddress = findCreated ? findCreated.args[0] : null;

    const to = findExecuted ? findExecuted.args[0] : null;

    const logs = events
      .filter((e) => {
        return (
          e.method.toUpperCase() === 'LOG' && e.section.toUpperCase() === 'EVM'
        );
      })
      .map((log, index) => {
        return {
          transactionHash,
          blockNumber,
          blockHash,
          transactionIndex,
          removed: false,
          address: log.args[0].address,
          data: log.args[0].data,
          topics: log.args[0].topics,
          logIndex: index
        };
      });

    const gasUsed = BigNumber.from(result.args[0].weight);

    return {
      to,
      from,
      contractAddress,
      transactionIndex,
      gasUsed,
      logsBloom: '0x',
      blockHash,
      transactionHash,
      logs,
      blockNumber,
      confirmations: 4,
      cumulativeGasUsed: gasUsed,
      byzantium: false,
      status,
      effectiveGasPrice: BigNumber.from('1'),
      type: 0
    };
  }
Example #16
Source File: Signer.ts    From evm-provider.js with Apache License 2.0 4 votes vote down vote up
/**
   *
   * @param transaction
   * @returns A promise that resolves to the transaction's response
   */
  async sendTransaction(
    _transaction: Deferrable<TransactionRequest>
  ): Promise<TransactionResponse> {
    this._checkProvider('sendTransaction');

    const signerAddress = await this.getSubstrateAddress();
    const evmAddress = await this.getAddress();

    // estimateResources requires the from parameter.
    // However, when creating the contract, there is no from parameter in the tx
    const transaction = {
      from: evmAddress,
      ..._transaction
    };

    const resources = await this.provider.estimateResources(transaction);

    // Multiply by 3.1
    const gasLimit: BigNumber = resources.gas.mul(31).div(10);
    let storageLimit: BigNumber;

    // If the storage limit is supplied, override it from the estimateResources
    if (transaction.customData) {
      if ('storageLimit' in transaction.customData) {
        storageLimit = transaction.customData.storageLimit;
        if (isNumber(storageLimit)) {
          storageLimit = BigNumber.from(storageLimit);
        }
      }
    } else {
      storageLimit = resources.storage.mul(31).div(10);
    }

    let totalLimit = await transaction.gasLimit;

    if (totalLimit === null || totalLimit === undefined) {
      totalLimit = gasLimit.add(storageLimit);
    }

    transaction.gasLimit = totalLimit;

    const tx = await this.populateTransaction(transaction);

    const data = tx.data;
    const from = tx.from;

    if (!data) {
      return logger.throwError('Request data not found');
    }

    if (!from) {
      return logger.throwError('Request from not found');
    }

    let extrinsic: SubmittableExtrinsic<'promise'>;

    // @TODO create contract
    if (!tx.to) {
      extrinsic = this.provider.api.tx.evm.create(
        tx.data,
        toBN(tx.value),
        toBN(gasLimit),
        toBN(storageLimit.isNegative() ? 0 : storageLimit)
      );
    } else {
      extrinsic = this.provider.api.tx.evm.call(
        tx.to,
        tx.data,
        toBN(tx.value),
        toBN(gasLimit),
        toBN(storageLimit.isNegative() ? 0 : storageLimit)
      );
    }

    await extrinsic.signAsync(signerAddress);

    return new Promise((resolve, reject) => {
      extrinsic
        .send((result: SubmittableResult) => {
          handleTxResponse(result, this.provider.api)
            .then(() => {
              resolve({
                hash: extrinsic.hash.toHex(),
                from: from || '',
                confirmations: 0,
                nonce: toBN(tx.nonce).toNumber(),
                gasLimit: BigNumber.from(tx.gasLimit || '0'),
                gasPrice: BigNumber.from(0),
                data: dataToString(data),
                value: BigNumber.from(tx.value || '0'),
                chainId: 13939,
                wait: (confirmations?: number): Promise<TransactionReceipt> => {
                  return this.provider._resolveTransactionReceipt(
                    extrinsic.hash.toHex(),
                    result.status.asInBlock.toHex(),
                    from
                  );
                }
              });
            })
            .catch(({ message, result }) => {
              reject(message);
            });
        })
        .catch((error) => {
          reject(error && error.message);
        });
    });
  }
Example #17
Source File: Signer.ts    From bodhi.js with Apache License 2.0 4 votes vote down vote up
/**
   *
   * @param transaction
   * @returns A promise that resolves to the transaction's response
   */
  async sendTransaction(_transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse> {
    this._checkProvider('sendTransaction');

    const signerAddress = await this.getSubstrateAddress();
    const evmAddress = await this.getAddress();

    // estimateResources requires the from parameter.
    // However, when creating the contract, there is no from parameter in the tx
    const transaction = {
      from: evmAddress,
      ..._transaction
    };

    const resources = await this.provider.estimateResources(transaction);

    let gasLimit: BigNumber;
    let storageLimit: BigNumber;

    let totalLimit = await transaction.gasLimit;

    if (totalLimit === null || totalLimit === undefined) {
      gasLimit = resources.gas;
      storageLimit = resources.storage;
      totalLimit = resources.gas.add(resources.storage);
    } else {
      const estimateTotalLimit = resources.gas.add(resources.storage);
      gasLimit = BigNumber.from(totalLimit).mul(resources.gas).div(estimateTotalLimit).add(1);
      storageLimit = BigNumber.from(totalLimit).mul(resources.storage).div(estimateTotalLimit).add(1);
    }

    transaction.gasLimit = totalLimit;

    const tx = await this.populateTransaction(transaction);

    const data = tx.data;
    const from = tx.from;

    if (!data) {
      return logger.throwError('Request data not found');
    }

    if (!from) {
      return logger.throwError('Request from not found');
    }

    let extrinsic: SubmittableExtrinsic<'promise'>;

    // @TODO create contract
    if (!tx.to) {
      extrinsic = this.provider.api.tx.evm.create(
        tx.data,
        toBN(tx.value),
        toBN(gasLimit),
        toBN(storageLimit.isNegative() ? 0 : storageLimit),
        tx.accessList || []
      );
    } else {
      extrinsic = this.provider.api.tx.evm.call(
        tx.to,
        tx.data,
        toBN(tx.value),
        toBN(gasLimit),
        toBN(storageLimit.isNegative() ? 0 : storageLimit),
        tx.accessList || []
      );
    }

    await extrinsic.signAsync(signerAddress);

    return new Promise((resolve, reject) => {
      extrinsic
        .send((result: SubmittableResult) => {
          handleTxResponse(result, this.provider.api)
            .then(() => {
              resolve({
                hash: extrinsic.hash.toHex(),
                from: from || '',
                confirmations: 0,
                nonce: toBN(tx.nonce).toNumber(),
                gasLimit: BigNumber.from(tx.gasLimit || '0'),
                gasPrice: BigNumber.from(1),
                data: dataToString(data),
                value: BigNumber.from(tx.value || '0'),
                chainId: +this.provider.api.consts.evmAccounts.chainId.toString(),
                wait: (confirmations?: number): Promise<TransactionReceipt> => {
                  const hex = result.status.isInBlock
                    ? result.status.asInBlock.toHex()
                    : result.status.asFinalized.toHex();
                  return this.provider.getTransactionReceiptAtBlock(extrinsic.hash.toHex(), hex);
                }
              });
            })
            .catch(reject);
        })
        .catch(reject);
    });
  }