UNPKG

viem

Version:

TypeScript Interface for Ethereum

194 lines 7.77 kB
import { parseAccount, } from '../../accounts/utils/parseAccount.js'; import { internal_estimateFeesPerGas, } from '../../actions/public/estimateFeesPerGas.js'; import { estimateGas, } from '../../actions/public/estimateGas.js'; import { getBlock as getBlock_, } from '../../actions/public/getBlock.js'; import { getTransactionCount, } from '../../actions/public/getTransactionCount.js'; import { Eip1559FeesNotSupportedError, MaxFeePerGasTooLowError, } from '../../errors/fee.js'; import { blobsToCommitments } from '../../utils/blob/blobsToCommitments.js'; import { blobsToProofs } from '../../utils/blob/blobsToProofs.js'; import { commitmentsToVersionedHashes } from '../../utils/blob/commitmentsToVersionedHashes.js'; import { toBlobSidecars } from '../../utils/blob/toBlobSidecars.js'; import { getAction } from '../../utils/getAction.js'; import { assertRequest, } from '../../utils/transaction/assertRequest.js'; import { getTransactionType, } from '../../utils/transaction/getTransactionType.js'; import { getChainId as getChainId_ } from '../public/getChainId.js'; export const defaultParameters = [ 'blobVersionedHashes', 'chainId', 'fees', 'gas', 'nonce', 'type', ]; /** @internal */ export const eip1559NetworkCache = /*#__PURE__*/ new Map(); /** * Prepares a transaction request for signing. * * - Docs: https://viem.sh/docs/actions/wallet/prepareTransactionRequest * * @param args - {@link PrepareTransactionRequestParameters} * @returns The transaction request. {@link PrepareTransactionRequestReturnType} * * @example * import { createWalletClient, custom } from 'viem' * import { mainnet } from 'viem/chains' * import { prepareTransactionRequest } from 'viem/actions' * * const client = createWalletClient({ * chain: mainnet, * transport: custom(window.ethereum), * }) * const request = await prepareTransactionRequest(client, { * account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', * to: '0x0000000000000000000000000000000000000000', * value: 1n, * }) * * @example * // Account Hoisting * import { createWalletClient, http } from 'viem' * import { privateKeyToAccount } from 'viem/accounts' * import { mainnet } from 'viem/chains' * import { prepareTransactionRequest } from 'viem/actions' * * const client = createWalletClient({ * account: privateKeyToAccount('0x…'), * chain: mainnet, * transport: custom(window.ethereum), * }) * const request = await prepareTransactionRequest(client, { * to: '0x0000000000000000000000000000000000000000', * value: 1n, * }) */ export async function prepareTransactionRequest(client, args) { const { account: account_ = client.account, blobs, chain, gas, kzg, nonce, nonceManager, parameters = defaultParameters, type, } = args; const account = account_ ? parseAccount(account_) : account_; const request = { ...args, ...(account ? { from: account?.address } : {}) }; let block; async function getBlock() { if (block) return block; block = await getAction(client, getBlock_, 'getBlock')({ blockTag: 'latest' }); return block; } let chainId; async function getChainId() { if (chainId) return chainId; if (chain) return chain.id; if (typeof args.chainId !== 'undefined') return args.chainId; const chainId_ = await getAction(client, getChainId_, 'getChainId')({}); chainId = chainId_; return chainId; } if (parameters.includes('nonce') && typeof nonce === 'undefined' && account) { if (nonceManager) { const chainId = await getChainId(); request.nonce = await nonceManager.consume({ address: account.address, chainId, client, }); } else { request.nonce = await getAction(client, getTransactionCount, 'getTransactionCount')({ address: account.address, blockTag: 'pending', }); } } if ((parameters.includes('blobVersionedHashes') || parameters.includes('sidecars')) && blobs && kzg) { const commitments = blobsToCommitments({ blobs, kzg }); if (parameters.includes('blobVersionedHashes')) { const versionedHashes = commitmentsToVersionedHashes({ commitments, to: 'hex', }); request.blobVersionedHashes = versionedHashes; } if (parameters.includes('sidecars')) { const proofs = blobsToProofs({ blobs, commitments, kzg }); const sidecars = toBlobSidecars({ blobs, commitments, proofs, to: 'hex', }); request.sidecars = sidecars; } } if (parameters.includes('chainId')) request.chainId = await getChainId(); if ((parameters.includes('fees') || parameters.includes('type')) && typeof type === 'undefined') { try { request.type = getTransactionType(request); } catch { let isEip1559Network = eip1559NetworkCache.get(client.uid); if (typeof isEip1559Network === 'undefined') { const block = await getBlock(); isEip1559Network = typeof block?.baseFeePerGas === 'bigint'; eip1559NetworkCache.set(client.uid, isEip1559Network); } request.type = isEip1559Network ? 'eip1559' : 'legacy'; } } if (parameters.includes('fees')) { // TODO(4844): derive blob base fees once https://github.com/ethereum/execution-apis/pull/486 is merged. if (request.type !== 'legacy' && request.type !== 'eip2930') { // EIP-1559 fees if (typeof request.maxFeePerGas === 'undefined' || typeof request.maxPriorityFeePerGas === 'undefined') { const block = await getBlock(); const { maxFeePerGas, maxPriorityFeePerGas } = await internal_estimateFeesPerGas(client, { block: block, chain, request: request, }); if (typeof args.maxPriorityFeePerGas === 'undefined' && args.maxFeePerGas && args.maxFeePerGas < maxPriorityFeePerGas) throw new MaxFeePerGasTooLowError({ maxPriorityFeePerGas, }); request.maxPriorityFeePerGas = maxPriorityFeePerGas; request.maxFeePerGas = maxFeePerGas; } } else { // Legacy fees if (typeof args.maxFeePerGas !== 'undefined' || typeof args.maxPriorityFeePerGas !== 'undefined') throw new Eip1559FeesNotSupportedError(); if (typeof args.gasPrice === 'undefined') { const block = await getBlock(); const { gasPrice: gasPrice_ } = await internal_estimateFeesPerGas(client, { block: block, chain, request: request, type: 'legacy', }); request.gasPrice = gasPrice_; } } } if (parameters.includes('gas') && typeof gas === 'undefined') request.gas = await getAction(client, estimateGas, 'estimateGas')({ ...request, account: account ? { address: account.address, type: 'json-rpc' } : account, }); assertRequest(request); delete request.parameters; return request; } //# sourceMappingURL=prepareTransactionRequest.js.map