@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
159 lines • 7.2 kB
JavaScript
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