ethers-tools
Version:
Contains tools for work with web3 contracts.
148 lines (134 loc) • 4.01 kB
JavaScript
import { config } from '../config.js';
import { checkSignals, createTimeoutSignal } from '../utils/index.js';
/**
* @param {import('ethers').Provider} provider
* @param {import('ethers').Signer} signer
* @param {import('ethers').Contract} contract
* @param {string} method
* @param {any[]} [args=[]]
* @param {import('../../types/entities').PriorityCallOptions} [options={}]
* @returns {Promise<import('ethers').TransactionResponse>}
*/
export async function priorityCall(
provider,
signer,
contract,
method,
args = [],
options = {}
) {
const txn = await formTx(provider, signer, contract, method, args, options);
return signer.sendTransaction(txn);
}
/**
* @param {import('ethers').Provider} provider
* @param {import('ethers').Signer} signer
* @param {import('ethers').Contract} contract
* @param {string} method
* @param {any[]} [args=[]]
* @param {import('../../types/entities').PriorityCallOptions} [options={}]
* @returns {Promise<bigint>}
*/
export async function priorityCallEstimate(
provider,
signer,
contract,
method,
args = [],
options = {}
) {
const txn = await formTx(provider, signer, contract, method, args, options);
return signer.estimateGas(txn);
}
/**
* @param {import('ethers').Provider} provider
* @param {import('ethers').Signer} signer
* @param {import('ethers').Contract} contract
* @param {string} method
* @param {any[]} [args=[]]
* @param {import('../../types/entities').PriorityCallOptions} [options={}]
* @returns {Promise<import('ethers').TransactionLike<string>>}
*/
async function formTx(
provider,
signer,
contract,
method,
args = [],
options = {}
) {
const localOptions = {
multiplier: config.priorityCalls.multiplier,
...options,
};
const localSignals = [];
if (localOptions.signals) localSignals.push(...localOptions.signals);
if (localOptions.timeoutMs)
localSignals.push(createTimeoutSignal(localOptions.timeoutMs));
checkSignals(localSignals);
const [originalFeeData, originalGasLimit] = await gatherOriginalData(
provider,
contract,
method,
args,
localOptions.asynchronous,
localSignals
);
const maxFeePerGas = Math.ceil(
localOptions.multiplier * Number(originalFeeData.maxFeePerGas)
);
const maxPriorityFeePerGas = Math.ceil(
localOptions.multiplier * Number(originalFeeData.maxPriorityFeePerGas)
);
const gasLimit = Math.ceil(
localOptions.multiplier * Number(originalGasLimit)
);
checkSignals(localSignals);
const txn = await contract.getFunction(method).populateTransaction(...args, {
gasLimit,
maxFeePerGas,
maxPriorityFeePerGas,
});
// Prevents conflicts when using signer.sendTransaction(txn), as the signer should determine the from address.
// Avoids potential issues if from is incorrectly set or differs from the signer's address.
delete txn.from;
if (localOptions.provideChainId) {
checkSignals(localSignals);
const network = await provider.getNetwork();
txn.chainId = network.chainId;
} else {
if (localOptions.chainId) txn.chainId = localOptions.chainId;
}
return txn;
}
/**
* @param {import('ethers').Provider} provider
* @param {import('ethers').Contract} contract
* @param {string} method
* @param {any[]} [args]
* @param {boolean} asynchronous
* @param {AbortSignal[]} signals
* @returns {Promise<[import('ethers').FeeData, bigint]>}
*/
async function gatherOriginalData(
provider,
contract,
method,
args,
asynchronous,
signals
) {
let originalFeeData, originalGasLimit;
checkSignals(signals);
if (asynchronous) {
[originalFeeData, originalGasLimit] = await Promise.all([
provider.getFeeData(),
contract.getFunction(method).estimateGas(...args),
]);
return [originalFeeData, originalGasLimit];
}
originalFeeData = await provider.getFeeData();
checkSignals(signals);
originalGasLimit = await contract.getFunction(method).estimateGas(...args);
return [originalFeeData, originalGasLimit];
}