UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

159 lines 7.2 kB
import { encodeSecp256k1Pubkey } from '@cosmjs/amino'; import { wasmTypes } from '@cosmjs/cosmwasm-stargate'; import { toUtf8 } from '@cosmjs/encoding'; import { Uint53 } from '@cosmjs/math'; import { Registry } from '@cosmjs/proto-signing'; import { StargateClient, defaultRegistryTypes } from '@cosmjs/stargate'; import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx.js'; import { assert } from '@hyperlane-xyz/utils'; import { ProviderType, } from './ProviderType.js'; export async function estimateTransactionFeeEthersV5({ transaction, provider, sender, }) { const ethersProvider = provider.provider; const gasUnits = await ethersProvider.estimateGas({ ...transaction.transaction, from: sender, }); return estimateTransactionFeeEthersV5ForGasUnits({ provider: ethersProvider, gasUnits: BigInt(gasUnits.toString()), }); } // Separating out inner function to allow WarpCore to reuse logic export async function estimateTransactionFeeEthersV5ForGasUnits({ provider, gasUnits, }) { const feeData = await provider.getFeeData(); return computeEvmTxFee(gasUnits, feeData.gasPrice ? BigInt(feeData.gasPrice.toString()) : undefined, feeData.maxFeePerGas ? BigInt(feeData.maxFeePerGas.toString()) : undefined, feeData.maxPriorityFeePerGas ? BigInt(feeData.maxPriorityFeePerGas.toString()) : undefined); } export async function estimateTransactionFeeViem({ transaction, provider, sender, }) { const gasUnits = await provider.provider.estimateGas({ ...transaction.transaction, blockNumber: undefined, account: sender, }); // Cast to silence overly-protective type enforcement from viem here const feeData = await provider.provider.estimateFeesPerGas(); return computeEvmTxFee(gasUnits, feeData.gasPrice, feeData.maxFeePerGas, feeData.maxPriorityFeePerGas); } function computeEvmTxFee(gasUnits, gasPrice, maxFeePerGas, maxPriorityFeePerGas) { let estGasPrice; if (maxFeePerGas && maxPriorityFeePerGas) { estGasPrice = maxFeePerGas + maxPriorityFeePerGas; } else if (gasPrice) { estGasPrice = gasPrice; } else { throw new Error('Invalid fee data, neither 1559 nor legacy'); } return { gasUnits, gasPrice: estGasPrice, fee: gasUnits * estGasPrice, }; } export async function estimateTransactionFeeSolanaWeb3({ provider, transaction, }) { const connection = provider.provider; const { value } = await connection.simulateTransaction(transaction.transaction); assert(!value.err, `Solana gas estimation failed: ${JSON.stringify(value)}`); const gasUnits = BigInt(value.unitsConsumed || 0); const recentFees = await connection.getRecentPrioritizationFees(); const gasPrice = BigInt(recentFees[0].prioritizationFee); return { gasUnits, gasPrice, fee: gasUnits * gasPrice, }; } // This is based on a reverse-engineered version of the // SigningStargateClient's simulate function. It cannot be // used here because it requires access to the private key. // https://github.com/cosmos/cosmjs/issues/1568 export async function estimateTransactionFeeCosmJs({ transaction, provider, estimatedGasPrice, sender, senderPubKey, memo, }) { const stargateClient = await provider.provider; const message = transaction.transaction; const registry = new Registry([...defaultRegistryTypes, ...wasmTypes]); const encodedMsg = registry.encodeAsAny(message); const encodedPubkey = encodeSecp256k1Pubkey(Buffer.from(senderPubKey, 'hex')); const { sequence } = await stargateClient.getSequence(sender); const { gasInfo } = await stargateClient // @ts-ignore force access to protected method .forceGetQueryClient() .tx.simulate([encodedMsg], memo, encodedPubkey, sequence); assert(gasInfo, 'Gas estimation failed'); const gasUnits = Uint53.fromString(gasInfo.gasUsed.toString()).toNumber(); const gasPrice = parseFloat(estimatedGasPrice.toString()); return { gasUnits, gasPrice, fee: Math.floor(gasUnits * gasPrice), }; } export async function estimateTransactionFeeCosmJsWasm({ transaction, provider, estimatedGasPrice, sender, senderPubKey, memo, }) { const message = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender, contract: transaction.transaction.contractAddress, msg: toUtf8(JSON.stringify(transaction.transaction.msg)), funds: [...(transaction.transaction.funds || [])], }), }; const wasmClient = await provider.provider; // @ts-ignore access a private field here to extract client URL const url = wasmClient.cometClient.client.url; const stargateClient = StargateClient.connect(url); return estimateTransactionFeeCosmJs({ transaction: { type: ProviderType.CosmJs, transaction: message }, provider: { type: ProviderType.CosmJs, provider: stargateClient }, estimatedGasPrice, sender, senderPubKey, memo, }); } export function estimateTransactionFee({ transaction, provider, chainMetadata, sender, senderPubKey, }) { if (transaction.type === ProviderType.EthersV5 && provider.type === ProviderType.EthersV5) { return estimateTransactionFeeEthersV5({ transaction, provider, sender }); } else if (transaction.type === ProviderType.Viem && provider.type === ProviderType.Viem) { return estimateTransactionFeeViem({ transaction, provider, sender }); } else if (transaction.type === ProviderType.SolanaWeb3 && provider.type === ProviderType.SolanaWeb3) { return estimateTransactionFeeSolanaWeb3({ transaction, provider }); } else if (transaction.type === ProviderType.CosmJs && provider.type === ProviderType.CosmJs) { const { transactionOverrides } = chainMetadata; const estimatedGasPrice = transactionOverrides?.gasPrice; assert(estimatedGasPrice, 'gasPrice required for CosmJS gas estimation'); assert(senderPubKey, 'senderPubKey required for CosmJS gas estimation'); return estimateTransactionFeeCosmJs({ transaction, provider, estimatedGasPrice, sender, senderPubKey, }); } else if (transaction.type === ProviderType.CosmJsWasm && provider.type === ProviderType.CosmJsWasm) { const { transactionOverrides } = chainMetadata; const estimatedGasPrice = transactionOverrides?.gasPrice; assert(estimatedGasPrice, 'gasPrice required for CosmJS gas estimation'); assert(senderPubKey, 'senderPubKey required for CosmJS gas estimation'); return estimateTransactionFeeCosmJsWasm({ transaction, provider, estimatedGasPrice, sender, senderPubKey, }); } else { throw new Error(`Unsupported transaction type ${transaction.type} or provider type ${provider.type} for gas estimation`); } } //# sourceMappingURL=transactionFeeEstimators.js.map