@rarible/estimate-middleware
Version:
120 lines (119 loc) • 5.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createEstimateGasMiddleware = void 0;
const tslib_1 = require("tslib");
const json_rpc_engine_1 = require("json-rpc-engine");
const index_1 = require("@rarible/utils/bn/index");
const utils_js_1 = require("./utils.js");
/**
* Creates async middleware for gas estimation if gas not defined
* @param engine JsonRpcEngine to use for gas estimation
* @param force set true if estimate tx even if gas is provided
*/
function createEstimateGasMiddleware(engine, force = false, threshold = 1.03, multiplier = 2) {
return (0, json_rpc_engine_1.createAsyncMiddleware)((req, res, next) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (req.method === "eth_subscribe") {
res.error = new utils_js_1.RpcError("Notifications not supported", -32000);
return next();
}
if (req.method === "eth_sendTransaction") {
try {
const params = getTransactionParams(req);
if (force || !params.gas) {
const gasLimitResponse = yield engine.handle({
jsonrpc: "2.0",
id: (0, json_rpc_engine_1.getUniqueId)(),
params: [getEstimateParams(params)],
method: "eth_estimateGas",
});
const limitRaw = handleHexResponse(gasLimitResponse);
if (limitRaw) {
const limitHex = extractHex(limitRaw);
const multiplied = (0, index_1.toBn)(limitHex, 16).multipliedBy(threshold).toFixed(0);
params["gas"] = withPrefix((0, index_1.toBn)(multiplied).toString(16));
}
const maxPriorityFeePerGasResponse = yield engine.handle({
jsonrpc: "2.0",
id: (0, json_rpc_engine_1.getUniqueId)(),
params: [],
method: "eth_maxPriorityFeePerGas",
});
const maxPriorityFeePerGasResponseRaw = handleHexResponse(maxPriorityFeePerGasResponse);
const blockResponse = yield engine.handle({
jsonrpc: "2.0",
id: (0, json_rpc_engine_1.getUniqueId)(),
params: ["pending", false],
method: "eth_getBlockByNumber",
});
const baseFeeRaw = extractBaseFeePerGas(blockResponse);
if (maxPriorityFeePerGasResponseRaw && baseFeeRaw) {
if (params.gasPrice !== undefined) {
delete params.gasPrice;
}
const baseFee = (0, index_1.toBn)(extractHex(baseFeeRaw), 16).multipliedBy(multiplier).toFixed(0);
const maxPriorityFeePerGas = extractHex(maxPriorityFeePerGasResponseRaw);
const maxFeePerGasHex = (0, index_1.toBn)(maxPriorityFeePerGas, 16).plus(baseFee).toString(16);
params["maxPriorityFeePerGas"] = maxPriorityFeePerGasResponseRaw;
params["maxFeePerGas"] = withPrefix(maxFeePerGasHex);
}
}
}
catch (error) {
res.error = (0, utils_js_1.extractError)(error);
}
}
return next();
}));
}
exports.createEstimateGasMiddleware = createEstimateGasMiddleware;
function withPrefix(value) {
return `0x${value}`;
}
function extractHex(value) {
return value.startsWith("0x") ? value.substring(2) : value;
}
function handleHexResponse(response) {
if (isJSONRpcResponse(response)) {
if (response.error) {
throw response.error;
}
if (typeof response.result === "string") {
return response.result;
}
}
throw new utils_js_1.RpcError("Can't handle JSON rpc response", -32700);
}
function extractBaseFeePerGas(response) {
if (isJSONRpcResponse(response)) {
if (response.error) {
throw response.error;
}
if (typeof response.result === "object") {
return response.result.baseFeePerGas;
}
}
throw new utils_js_1.RpcError("Can't handle JSON rpc response", -32700);
}
function getTransactionParams(request) {
if (request.params) {
const [tx] = request.params;
if (isSendParams(tx)) {
return tx;
}
}
throw new utils_js_1.RpcError("Can't parse eth_sendTransaction params", -32600);
}
function isJSONRpcResponse(x) {
return typeof x === "object" && x !== null && "jsonrpc" in x && "id" in x;
}
function isSendParams(x) {
return typeof x === "object" && x !== null && "to" in x;
}
function getEstimateParams(params) {
return {
to: params.to,
data: params.data,
value: params.value,
from: params.from,
};
}