viem
Version:
194 lines • 7.77 kB
JavaScript
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