viem
Version:
147 lines • 5.97 kB
JavaScript
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