UNPKG

viem

Version:

TypeScript Interface for Ethereum

147 lines 5.97 kB
import { parseAccount } from '../../accounts/utils/parseAccount.js'; import { BaseFeeScalarError } from '../../errors/fee.js'; import { getTransactionError, } from '../../utils/errors/getTransactionError.js'; import { extract } from '../../utils/formatters/extract.js'; import { formatTransaction, } from '../../utils/formatters/transaction.js'; import { formatTransactionRequest, } from '../../utils/formatters/transactionRequest.js'; import { getAction } from '../../utils/getAction.js'; import { assertRequest } from '../../utils/transaction/assertRequest.js'; import { getBlock } from './getBlock.js'; import { getChainId as getChainId_ } from './getChainId.js'; /** * Fills a transaction request with the necessary fields to be signed over. * * - Docs: https://viem.sh/docs/actions/public/fillTransaction * * @param client - Client to use * @param parameters - {@link FillTransactionParameters} * @returns The filled transaction. {@link FillTransactionReturnType} * * @example * import { createPublicClient, http } from 'viem' * import { mainnet } from 'viem/chains' * import { fillTransaction } from 'viem/public' * * const client = createPublicClient({ * chain: mainnet, * transport: http(), * }) * const result = await fillTransaction(client, { * account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', * to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', * value: parseEther('1'), * }) */ export async function fillTransaction(client, parameters) { const { account = client.account, accessList, authorizationList, chain = client.chain, blobVersionedHashes, blobs, data, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce: nonce_, nonceManager, to, type, value, ...rest } = parameters; const nonce = await (async () => { if (!account) return nonce_; if (!nonceManager) return nonce_; if (typeof nonce_ !== 'undefined') return nonce_; const account_ = parseAccount(account); const chainId = chain ? chain.id : await getAction(client, getChainId_, 'getChainId')({}); return await nonceManager.consume({ address: account_.address, chainId, client, }); })(); assertRequest(parameters); const chainFormat = chain?.formatters?.transactionRequest?.format; const format = chainFormat || formatTransactionRequest; const request = format({ // Pick out extra data that might exist on the chain's transaction request type. ...extract(rest, { format: chainFormat }), account: account ? parseAccount(account) : undefined, accessList, authorizationList, blobs, blobVersionedHashes, data, gas, gasPrice, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, nonce, to, type, value, }, 'fillTransaction'); try { const response = await client.request({ method: 'eth_fillTransaction', params: [request], }); const format = chain?.formatters?.transaction?.format || formatTransaction; const transaction = format(response.tx); // Remove unnecessary fields. delete transaction.blockHash; delete transaction.blockNumber; delete transaction.r; delete transaction.s; delete transaction.transactionIndex; delete transaction.v; delete transaction.yParity; // Rewrite fields. transaction.data = transaction.input; // Preference supplied fees (some nodes do not take these preferences). if (transaction.gas) transaction.gas = parameters.gas ?? transaction.gas; if (transaction.gasPrice) transaction.gasPrice = parameters.gasPrice ?? transaction.gasPrice; if (transaction.maxFeePerBlobGas) transaction.maxFeePerBlobGas = parameters.maxFeePerBlobGas ?? transaction.maxFeePerBlobGas; if (transaction.maxFeePerGas) transaction.maxFeePerGas = parameters.maxFeePerGas ?? transaction.maxFeePerGas; if (transaction.maxPriorityFeePerGas) transaction.maxPriorityFeePerGas = parameters.maxPriorityFeePerGas ?? transaction.maxPriorityFeePerGas; if (transaction.nonce) transaction.nonce = parameters.nonce ?? transaction.nonce; // Build fee multiplier function. const feeMultiplier = await (async () => { if (typeof chain?.fees?.baseFeeMultiplier === 'function') { const block = await getAction(client, getBlock, 'getBlock')({}); return chain.fees.baseFeeMultiplier({ block, client, request: parameters, }); } return chain?.fees?.baseFeeMultiplier ?? 1.2; })(); if (feeMultiplier < 1) throw new BaseFeeScalarError(); const decimals = feeMultiplier.toString().split('.')[1]?.length ?? 0; const denominator = 10 ** decimals; const multiplyFee = (base) => (base * BigInt(Math.ceil(feeMultiplier * denominator))) / BigInt(denominator); // Apply fee multiplier. if (transaction.maxFeePerGas && !parameters.maxFeePerGas) transaction.maxFeePerGas = multiplyFee(transaction.maxFeePerGas); if (transaction.gasPrice && !parameters.gasPrice) transaction.gasPrice = multiplyFee(transaction.gasPrice); return { raw: response.raw, transaction: { from: request.from, ...transaction, }, }; } catch (err) { throw getTransactionError(err, { ...parameters, chain: client.chain, }); } } //# sourceMappingURL=fillTransaction.js.map