UNPKG

@kaiachain/web3js-ext

Version:
146 lines (142 loc) 6.49 kB
/* This file is part of web3.js. web3.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. web3.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see <http://www.gnu.org/licenses/>. */ // Taken from https://github.com/web3/web3.js/blob/v4.3.0/packages/web3-eth/src/utils/send_tx_helper.ts import { ContractExecutionError, InvalidResponseError, TransactionRevertedWithoutReasonError, TransactionRevertInstructionError, TransactionRevertWithCustomError, } from "web3-errors"; import { ALL_EVENTS_ABI, decodeEventABI, } from "web3-eth"; import { ethRpcMethods } from "web3-rpc-methods"; import { ETH_DATA_FORMAT, } from "web3-types"; import { isNullish } from "web3-validator"; import { getRevertReason } from "./get_revert_reason.js"; import { getTransactionError } from "./get_transaction_error.js"; import { getTransactionGasPricing } from "./get_transaction_gas_pricing.js"; import { trySendTransaction } from "./try_send_transaction.js"; import { watchTransactionForConfirmations } from "./watch_transaction_for_confirmations.js"; export class SendTxHelper { constructor({ options, web3Context, promiEvent, returnFormat, }) { this.options = { checkRevertBeforeSending: true, }; this.options = options; this.web3Context = web3Context; this.promiEvent = promiEvent; this.returnFormat = returnFormat; } getReceiptWithEvents(data) { const result = { ...(data ?? {}) }; if (this.options?.contractAbi && result.logs && result.logs.length > 0) { result.events = {}; for (const log of result.logs) { const event = decodeEventABI(ALL_EVENTS_ABI, log, this.options?.contractAbi, this.returnFormat); if (event.event) { result.events[event.event] = event; } } } return result; } async checkRevertBeforeSending(tx) { if (this.options.checkRevertBeforeSending !== false) { const reason = await getRevertReason(this.web3Context, tx, this.options.contractAbi); if (reason !== undefined) { throw await getTransactionError(this.web3Context, tx, undefined, undefined, this.options.contractAbi, reason); } } } emitSending(tx) { if (this.promiEvent.listenerCount("sending") > 0) { // @ts-ignore: web3.js has the same error this.promiEvent.emit("sending", tx); } } async populateGasPrice({ transactionFormatted, transaction, }) { let result = transactionFormatted; if (!this.options?.ignoreGasPricing && isNullish(transactionFormatted.gasPrice) && (isNullish(transaction.maxPriorityFeePerGas) || isNullish(transaction.maxFeePerGas))) { result = { ...transactionFormatted, // TODO gasPrice, maxPriorityFeePerGas, maxFeePerGas // should not be included if undefined, but currently are ...(await getTransactionGasPricing( // @ts-ignore: web3.js has the same error transactionFormatted, this.web3Context, ETH_DATA_FORMAT)), }; } return result; } async signAndSend({ wallet, tx, }) { if (wallet) { // @ts-ignore: web3.js has the same error const signedTransaction = await wallet.signTransaction(tx); return trySendTransaction(this.web3Context, async () => ethRpcMethods.sendRawTransaction(this.web3Context.requestManager, signedTransaction.rawTransaction), signedTransaction.transactionHash); } return trySendTransaction(this.web3Context, async () => ethRpcMethods.sendTransaction(this.web3Context.requestManager, tx)); } emitSent(tx) { if (this.promiEvent.listenerCount("sent") > 0) { // @ts-ignore: web3.js has the same error this.promiEvent.emit("sent", tx); } } emitTransactionHash(hash) { if (this.promiEvent.listenerCount("transactionHash") > 0) { this.promiEvent.emit("transactionHash", hash); } } emitReceipt(receipt) { if (this.promiEvent.listenerCount("receipt") > 0) { this.promiEvent.emit("receipt", // @ts-expect-error unknown type fix receipt); } } async handleError({ error, tx }) { let _error = error; if (_error instanceof ContractExecutionError && this.web3Context.handleRevert) { _error = await getTransactionError(this.web3Context, tx, undefined, undefined, this.options?.contractAbi); } if ((_error instanceof InvalidResponseError || _error instanceof ContractExecutionError || _error instanceof TransactionRevertWithCustomError || _error instanceof TransactionRevertedWithoutReasonError || _error instanceof TransactionRevertInstructionError) && this.promiEvent.listenerCount("error") > 0) { this.promiEvent.emit("error", _error); } return _error; } emitConfirmation({ receipt, transactionHash, }) { if (this.promiEvent.listenerCount("confirmation") > 0) { watchTransactionForConfirmations(this.web3Context, this.promiEvent, receipt, transactionHash, this.returnFormat); } } async handleResolve({ receipt, tx }) { if (this.options?.transactionResolver) { return this.options?.transactionResolver(receipt); } if (receipt.status === BigInt(0)) { const error = await getTransactionError(this.web3Context, tx, // @ts-ignore: web3.js has the same error receipt, undefined, this.options?.contractAbi); if (this.promiEvent.listenerCount("error") > 0) { this.promiEvent.emit("error", error); } throw error; } else { return receipt; } } }