UNPKG

@solarity/hardhat-migrate

Version:
171 lines (131 loc) 5.21 kB
import { AddressLike, JsonRpcProvider, Transaction, TransactionLike, TransactionRequest, TransactionResponse, VoidSigner, } from "ethers"; import { HardhatEthersProvider, HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/types"; import { MigrateError } from "../../utils/index.js"; import { getTrezorAddress, initTrezor, signWithTrezor } from "../integrations/trezor-integration.js"; import { CastSignOptions, getCastVersion, getCastWalletAddress, getSignedTxViaCast, } from "../integrations/cast-integration.js"; import { networkManager } from "./NetworkManager.js"; import { connection, migratorConfig } from "./EthersProvider.js"; export class ExtendedHardhatEthersSigner { public readonly provider: JsonRpcProvider | HardhatEthersProvider; public readonly ethersSigner: VoidSigner | HardhatEthersSigner; public readonly signerIdentifier: AddressLike; private _initialized: boolean = false; constructor(ethersSigner: VoidSigner | HardhatEthersSigner, signerName?: AddressLike) { this.ethersSigner = ethersSigner; this.provider = connection!.ethers.provider; this.signerIdentifier = this._determineSignerIdentifier(signerName); } static async fromSignerName(signerName?: AddressLike): Promise<ExtendedHardhatEthersSigner> { let ethersSigner: VoidSigner | HardhatEthersSigner; try { ethersSigner = await networkManager?.getEthersSigner(signerName as any)!; } catch { const ethers = await import("ethers"); const address = ethers.isAddress(signerName) ? signerName : ethers.ZeroAddress; ethersSigner = new ethers.VoidSigner(address, connection!.ethers.provider); } return new ExtendedHardhatEthersSigner(ethersSigner, signerName); } public async getAddress(): Promise<string> { if (this._isCastEnabled()) { return getCastWalletAddress(this._getCastOptions()); } if (migratorConfig!.trezorWallet.enabled) { return getTrezorAddress(migratorConfig!.trezorWallet.mnemonicIndex || 0); } if ("getAddress" in this.ethersSigner) { return this.ethersSigner.getAddress(); } throw new MigrateError("No valid signer configuration found to determine address"); } public async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> { await this._ensureInitialized(); if (!this._isCastEnabled() && !migratorConfig!.trezorWallet.enabled) { return this.ethersSigner.sendTransaction(tx); } const voidSigner = new connection!.ethers.VoidSigner(await this.getAddress(), connection!.ethers.provider); let preparedTx = await voidSigner.populateTransaction(tx); if (connection!.networkConfig.gasPrice) { try { preparedTx.gasPrice = connection?.ethers.parseUnits(connection!.networkConfig.gasPrice.toString(), "gwei"); } catch { /* empty */ } } if (connection!.networkConfig.gasMultiplier) { preparedTx.gasLimit = String( (BigInt(preparedTx.gasLimit!) * BigInt(connection!.networkConfig.gasMultiplier * 100)) / 100n, ); } delete preparedTx.from; if (migratorConfig!.trezorWallet.enabled) { preparedTx = await this._prepareTrezorTransaction(preparedTx); } const signedTx = await this._signTransaction(connection!.ethers.Transaction.from(preparedTx)); return connection!.ethers.provider.broadcastTransaction(signedTx); } private _determineSignerIdentifier(signerName?: AddressLike): AddressLike { if (signerName) { return signerName; } if (this._isCastEnabled()) { return (migratorConfig!.castWallet.account || migratorConfig!.castWallet.keystore)!; } if (migratorConfig!.trezorWallet.enabled) { return "trezor"; } return this.ethersSigner.getAddress(); } private async _ensureInitialized(): Promise<void> { if (this._initialized) return; if (migratorConfig!.trezorWallet.enabled) { await initTrezor(); } if (this._isCastEnabled()) { await getCastVersion(); } this._initialized = true; } private async _prepareTrezorTransaction(tx: TransactionLike): Promise<TransactionLike> { delete tx.maxFeePerBlobGas; delete tx.maxFeePerGas; delete tx.maxPriorityFeePerGas; tx.type = 1; tx.gasPrice = await connection!.ethers.provider.send("eth_gasPrice", []); return tx; } private async _signTransaction(tx: Transaction): Promise<string> { if (this._isCastEnabled()) { return getSignedTxViaCast(tx, this._getCastOptions()); } if (migratorConfig!.trezorWallet.enabled) { const mnemonicIndex = migratorConfig!.trezorWallet.mnemonicIndex || 0; return signWithTrezor(tx, mnemonicIndex); } throw new MigrateError("No valid signer configuration found to sign transaction"); } private _getCastOptions(): CastSignOptions { const config = migratorConfig!.castWallet; return { keystore: config.keystore, passwordFile: config.passwordFile, account: config.account, }; } private _isCastEnabled(): boolean { return migratorConfig!.castWallet.account !== undefined || migratorConfig!.castWallet.keystore !== undefined; } }