UNPKG

@moonwall/util

Version:

Testing framework for the Moon family of projects

219 lines 7.95 kB
// src/classes/eth-tester.ts import { ContractFactory } from "ethers"; var DEFAULT_TRANSACTION = {}; var EthTester = class { /** * @name defaultType: Default type of Ethereum transaction */ defaultType; /** * @name defaultType: Default account to sign Ethereum transactions (usually sudo account) */ defaultAccount; /** * @name logger: Logger to use */ logger; /** * @name web3: Web3 instance */ web3; /** * @name constructor * @param web3: Web3 instance * @param privateKey: Private key of the default account * @param logger: Logger to use * @param type: Default type of Ethereum transaction * @returns Web3Tester instance * @description Creates a new Web3Tester instance * @example * const web3 = new Web3("http://localhost:9944"); * const web3Tester = new Web3Tester(web3, alith.privateKey, logger, "EIP1559"); * const rawTransaction = await web3Tester.genSignedTransfer({ * to: baltathar.address, * value: web3.utils.toWei("1", "ether"), * }); */ constructor(web3, privateKey, logger, type = "Legacy") { this.web3 = web3; this.logger = logger; this.defaultType = type; this.defaultAccount = web3.eth.accounts.privateKeyToAccount(privateKey); } /** * @name genSignedTransaction * @param options: Transaction options * @param txType: Type of Ethereum transaction * @returns Signed transaction * @description Generates a signed Ethereum transaction * @example * const rawTransaction = await web3Tester.genSignedTransaction({ * to: baltathar.address, * to: authorMapping.address, * data: authorMapping.encodeFunctionData("setKeys", [keys]), * }); */ genSignedTransaction = async (options = DEFAULT_TRANSACTION, txType) => { const type = txType || this.defaultType; const isLegacy = type === "Legacy"; const isEip2930 = type === "EIP2930"; const isEip1559 = type === "EIP1559"; if (options.gasPrice && options.maxFeePerGas) { throw new Error("txn has both gasPrice and maxFeePerGas!"); } if (options.gasPrice && options.maxPriorityFeePerGas) { throw new Error("txn has both gasPrice and maxPriorityFeePerGas!"); } if (typeof options.gasPrice === "bigint") { options.gasPrice = `0x${options.gasPrice.toString(16)}`; } if (typeof options.maxFeePerGas === "bigint") { options.maxFeePerGas = `0x${options.maxFeePerGas.toString(16)}`; } if (typeof options.maxPriorityFeePerGas === "bigint") { options.maxPriorityFeePerGas = `0x${options.maxPriorityFeePerGas.toString(16)}`; } let maxFeePerGas; let maxPriorityFeePerGas; if (options.gasPrice) { maxFeePerGas = options.gasPrice; maxPriorityFeePerGas = options.gasPrice; } else { maxFeePerGas = options.maxFeePerGas || BigInt(await this.web3.eth.getGasPrice()); maxPriorityFeePerGas = options.maxPriorityFeePerGas || 0; } const gasPrice = options.gasPrice !== void 0 ? options.gasPrice : `0x${BigInt(await this.web3.eth.getGasPrice()).toString(16)}`; const value = options.value !== void 0 ? options.value : "0x00"; const from = options.from || this.defaultAccount.address; const privateKey = options.privateKey !== void 0 ? options.privateKey : this.defaultAccount.privateKey; let error; const estimatedGas = await this.web3.eth.estimateGas({ from, to: options.to, data: options.data }).catch((e) => { error = e; return 0; }); const gas = options.gas || estimatedGas; const accessList = options.accessList || []; const nonce = options.nonce != null ? options.nonce : await this.web3.eth.getTransactionCount(from, "pending"); let data; let rawTransaction; if (isLegacy) { data = { from, to: options.to, value: value?.toString(), gasPrice, gas, nonce, data: options.data }; const tx = await this.web3.eth.accounts.signTransaction(data, privateKey); rawTransaction = tx.rawTransaction; } else { const chainId = await this.web3.eth.getChainId(); if (isEip2930) { data = { from, to: options.to, value: value?.toString(), gasPrice, gasLimit: gas, nonce, data: options.data, accessList, chainId, type: 1 }; } else if (isEip1559) { data = { from, to: options.to, value: value?.toString(), maxFeePerGas, maxPriorityFeePerGas, gasLimit: gas, nonce, data: options.data, accessList, chainId, type: 2 }; } const tx = await this.web3.eth.accounts.signTransaction(data, privateKey); rawTransaction = tx.rawTransaction; } this.logger.debug( `Tx [${/:([0-9]+)$/.exec(this.web3.currentProvider.host)?.[1]}] from: ${`${data.from.substr(0, 5)}...${data.from.substr(data.from.length - 3)}`}, ${data.to ? `to: ${`${data.to.substr(0, 5)}...${data.to.substr(data.to.length - 3)}`}, ` : ""}${data.value ? `value: ${data.value.toString()}, ` : ""}${data.gasPrice ? `gasPrice: ${data.gasPrice.toString()}, ` : ""}${data.maxFeePerGas ? `maxFeePerGas: ${data.maxFeePerGas.toString()}, ` : ""}${data.maxPriorityFeePerGas ? `maxPriorityFeePerGas: ${data.maxPriorityFeePerGas.toString()}, ` : ""}${data.accessList ? `accessList: ${data.accessList.toString()}, ` : ""}${data.gas ? `gas: ${data.gas.toString()}, ` : ""}${data.nonce ? `nonce: ${data.nonce.toString()}, ` : ""}${!data.data ? "" : `data: ${data.data.length < 50 ? data.data : `${data.data.substr(0, 5)}...${data.data.substr(data.data.length - 3)}`}, `}${error ? `ERROR: ${error.toString()}, ` : ""}` ); return rawTransaction; }; /** * @name genSignedTransfer * @param to Address of the recipient * @param value Amount of Wei to send * @param options Transaction options * @description Generates a signed Ethereum transactiosn * @returns Signed transaction */ genSignedTransfer = async (to, value, options = DEFAULT_TRANSACTION) => { return await this.genSignedTransaction({ ...options, value: value.toString(), to }); }; /** * @name genSignedContractDeployment * @description Generates a signed contract deployment transaction * @param contractCreation Contract creation object * @param options Transaction options * @returns Signed transaction */ genSignedContractDeployment = async (contractCreation, options = DEFAULT_TRANSACTION) => { const factory = new ContractFactory(contractCreation.abi, contractCreation.byteCode); return await this.genSignedTransaction({ ...options, data: (await factory.getDeployTransaction(...contractCreation.arguments || [])).data }); }; /** * @name sendSignedTransaction * @description Sends a signed transaction, without waiting for it to be produced. * @param rawTransaction Signed transaction * @returns Transaction JSON RPC response */ sendSignedTransaction = async (rawTransaction) => { return new Promise(async (resolve, reject) => { try { if (typeof this.web3.currentProvider === "string") { reject("Web3 provider is not a valid provider"); return; } this.web3.currentProvider.send( { jsonrpc: "2.0", id: 1, method: "eth_sendRawTransaction", params: [await rawTransaction] }, (error, result) => { if (error) { reject(`Failed to send signed transaction: ${error.message || error.toString()}`); } resolve(result); } ); } catch (e) { reject(e); } }); }; }; export { DEFAULT_TRANSACTION, EthTester }; //# sourceMappingURL=index.js.map