Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gas multiplier option #259

Merged
merged 3 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ Other optional arguments are:
- `-w` or `--wallet-count`, Number of wallet to submit transactions with, requirs `--mnemonic`. Will override the 'WALLET_COUNT' in env variables
- `-t` or `--topup-amount`, The initial topup amount of excess wallets, requirs `--mnemonic`. Will override the 'TOPUP_AMOUNT' in env variables
- `--gas-price-multiplier`, Option to multiply the gas price fetched from the rpc as percentage, default is 107, ie +7%. Will override the 'GAS_PRICE_MULTIPLIER' in env variables
- `--gas-limit-multiplier`, Option to multiply the gas limit estimation from the rpc as percentage, default is 105, ie +5%. Will override the 'GAS_LIMIT_MULTIPLIER' in env variables
- `--tx-gas`, Option to set a static gas limit for all submitting txs. Will override the 'TX_GAS' in env variables
- `-V` or `--version`, output the version number
- `-h` or `--help`, output usage information

Expand Down Expand Up @@ -256,6 +258,12 @@ ROUTE="single"

# Option to multiply the gas price fetched from the rpc as percentage, default is 107, ie +7%
GAS_PRICE_MULTIPLIER=

# Option to multiply the gas limit estimation from the rpc as percentage, default is 105, ie +5%
GAS_LIMIT_MULTIPLIER=

# Option to set a static gas limit for all submitting txs
TX_GAS=
```
If both env variables and CLI argument are set, the CLI arguments will be prioritized and override the env variables.

Expand Down
6 changes: 6 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ ROUTE="single"
# Option to multiply the gas price fetched from the rpc as percentage, default is 107, ie +7%
GAS_PRICE_MULTIPLIER=

# Option to multiply the gas limit estimation from the rpc as percentage, default is 105, ie +5%
GAS_LIMIT_MULTIPLIER=

# Option to set a static gas limit for all submitting txs
TX_GAS=


# test rpcs vars
TEST_POLYGON_RPC=
Expand Down
66 changes: 58 additions & 8 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const ENV_OPTIONS = {
botMinBalance: process?.env?.BOT_MIN_BALANCE,
selfFundOrders: process?.env?.SELF_FUND_ORDERS,
gasPriceMultiplier: process?.env?.GAS_PRICE_MULTIPLIER,
gasLimitMultiplier: process?.env?.GAS_LIMIT_MULTIPLIER,
txGas: process?.env?.TX_GAS,
route: process?.env?.ROUTE,
rpc: process?.env?.RPC_URL
? Array.from(process?.env?.RPC_URL.matchAll(/[^,\s]+/g)).map((v) => v[0])
Expand Down Expand Up @@ -168,6 +170,14 @@ const getOptions = async (argv: any, version?: string) => {
"--gas-price-multiplier <integer>",
"Option to multiply the gas price fetched from the rpc as percentage, default is 107, ie +7%. Will override the 'GAS_PRICE_MULTIPLIER' in env variables",
)
.option(
"--gas-limit-multiplier <integer>",
"Option to multiply the gas limit estimation from the rpc as percentage, default is 105, ie +5%. Will override the 'GAS_LIMIT_MULTIPLIER' in env variables",
)
.option(
"--tx-gas <integer>",
"Option to set a static gas limit for all submitting txs. Will override the 'TX_GAS' in env variables",
)
.description(
[
"A NodeJS app to find and take arbitrage trades for Rain Orderbook orders against some DeFi liquidity providers, requires NodeJS v18 or higher.",
Expand Down Expand Up @@ -203,6 +213,8 @@ const getOptions = async (argv: any, version?: string) => {
cmdOptions.topupAmount = cmdOptions.topupAmount || ENV_OPTIONS.topupAmount;
cmdOptions.selfFundOrders = cmdOptions.selfFundOrders || ENV_OPTIONS.selfFundOrders;
cmdOptions.gasPriceMultiplier = cmdOptions.gasPriceMultiplier || ENV_OPTIONS.gasPriceMultiplier;
cmdOptions.gasLimitMultiplier = cmdOptions.gasLimitMultiplier || ENV_OPTIONS.gasLimitMultiplier;
cmdOptions.txGas = cmdOptions.txGas || ENV_OPTIONS.txGas;
cmdOptions.botMinBalance = cmdOptions.botMinBalance || ENV_OPTIONS.botMinBalance;
cmdOptions.route = cmdOptions.route || ENV_OPTIONS.route;
cmdOptions.bundle = cmdOptions.bundle ? ENV_OPTIONS.bundle : false;
Expand Down Expand Up @@ -251,7 +263,7 @@ export const arbRound = async (
if (!ordersDetails.length) {
span.setStatus({ code: SpanStatusCode.OK, message: "found no orders" });
span.end();
return { txs: [], foundOpp: false, avgGasCost: undefined };
return { txs: [], foundOpp: false, didClear: false, avgGasCost: undefined };
}
} catch (e: any) {
const snapshot = errorSnapshot("", e);
Expand All @@ -260,12 +272,13 @@ export const arbRound = async (
span.setAttribute("didClear", false);
span.setAttribute("foundOpp", false);
span.end();
return { txs: [], foundOpp: false, avgGasCost: undefined };
return { txs: [], foundOpp: false, didClear: false, avgGasCost: undefined };
}

try {
let txs;
let foundOpp = false;
let didClear = false;
const { reports = [], avgGasCost = undefined } = await clear(
config,
ordersDetails,
Expand All @@ -277,14 +290,22 @@ export const arbRound = async (
if (txs.length) {
foundOpp = true;
span.setAttribute("txUrls", txs);
span.setAttribute("didClear", true);
span.setAttribute("foundOpp", true);
} else if (
reports.some((v) => v.status === ProcessPairReportStatus.FoundOpportunity)
) {
foundOpp = true;
span.setAttribute("foundOpp", true);
}
if (
reports.some(
(v) =>
v.status === ProcessPairReportStatus.FoundOpportunity && !v.reason,
)
) {
didClear = true;
span.setAttribute("didClear", true);
}
} else {
span.setAttribute("didClear", false);
}
Expand All @@ -293,7 +314,7 @@ export const arbRound = async (
}
span.setStatus({ code: SpanStatusCode.OK });
span.end();
return { txs, foundOpp, avgGasCost };
return { txs, foundOpp, didClear, avgGasCost };
} catch (e: any) {
if (e?.startsWith?.("Failed to batch quote orders")) {
span.setAttribute("severity", ErrorSeverity.LOW);
Expand All @@ -307,7 +328,7 @@ export const arbRound = async (
span.setAttribute("didClear", false);
span.setAttribute("foundOpp", false);
span.end();
return { txs: [], foundOpp: false, avgGasCost: undefined };
return { txs: [], foundOpp: false, didClear: false, avgGasCost: undefined };
}
} catch (e: any) {
const snapshot = errorSnapshot("Unexpected error occured", e);
Expand All @@ -317,7 +338,7 @@ export const arbRound = async (
span.setAttribute("didClear", false);
span.setAttribute("foundOpp", false);
span.end();
return { txs: [], foundOpp: false, avgGasCost: undefined };
return { txs: [], foundOpp: false, didClear: false, avgGasCost: undefined };
}
});
};
Expand Down Expand Up @@ -389,6 +410,32 @@ export async function startup(argv: any, version?: string, tracer?: Tracer, ctx?
} else {
options.gasPriceMultiplier = 107;
}
if (options.gasLimitMultiplier) {
if (typeof options.gasLimitMultiplier === "number") {
if (options.gasLimitMultiplier <= 0 || !Number.isInteger(options.gasLimitMultiplier))
throw "invalid gasLimitMultiplier value, must be an integer greater than zero";
} else if (
typeof options.gasLimitMultiplier === "string" &&
/^[0-9]+$/.test(options.gasLimitMultiplier)
) {
options.gasLimitMultiplier = Number(options.gasLimitMultiplier);
if (options.gasLimitMultiplier <= 0)
throw "invalid gasLimitMultiplier value, must be an integer greater than zero";
} else throw "invalid gasLimitMultiplier value, must be an integer greater than zero";
} else {
options.gasLimitMultiplier = 105;
}
if (options.txGas) {
if (typeof options.txGas === "number") {
if (options.txGas <= 0 || !Number.isInteger(options.txGas))
throw "invalid txGas value, must be an integer greater than zero";
else options.txGas = BigInt(options.txGas);
} else if (typeof options.txGas === "string" && /^[0-9]+$/.test(options.txGas)) {
options.txGas = BigInt(options.txGas);
if (options.txGas <= 0n)
throw "invalid txGas value, must be an integer greater than zero";
} else throw "invalid txGas value, must be an integer greater than zero";
}
const poolUpdateInterval = _poolUpdateInterval * 60 * 1000;
let ordersDetails: any[] = [];
if (!process?.env?.TEST)
Expand Down Expand Up @@ -559,16 +606,19 @@ export const main = async (argv: any, version?: string) => {
try {
await rotateProviders(config, update);
const roundResult = await arbRound(tracer, roundCtx, options, config);
let txs, foundOpp, roundAvgGasCost;
let txs, foundOpp, didClear, roundAvgGasCost;
if (roundResult) {
txs = roundResult.txs;
foundOpp = roundResult.foundOpp;
didClear = roundResult.didClear;
roundAvgGasCost = roundResult.avgGasCost;
}
if (txs && txs.length) {
roundSpan.setAttribute("txUrls", txs);
roundSpan.setAttribute("didClear", true);
roundSpan.setAttribute("foundOpp", true);
} else if (didClear) {
roundSpan.setAttribute("foundOpp", true);
roundSpan.setAttribute("didClear", true);
} else if (foundOpp) {
roundSpan.setAttribute("foundOpp", true);
roundSpan.setAttribute("didClear", false);
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ export async function getConfig(
config.route = route;
config.rpcRecords = rpcRecords;
config.gasPriceMultiplier = options.gasPriceMultiplier;
config.gasLimitMultiplier = options.gasLimitMultiplier;
config.txGas = options.txGas;

// init accounts
const { mainAccount, accounts } = await initAccounts(walletKey, config, options, tracer, ctx);
Expand Down
6 changes: 6 additions & 0 deletions src/modes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ export async function findOpp({

if (allResults.some((v) => v.status === "fulfilled")) {
// pick and return the highest profit
allResults.forEach((v, i) => {
if (v.status === "fulfilled") {
v.value.spanAttributes["clearModePick"] =
i === 0 ? "rp4" : i === 1 ? "intra" : "inter";
}
});
const res = allResults.filter(
(v) => v.status === "fulfilled",
) as PromiseFulfilledResult<DryrunResult>[];
Expand Down
20 changes: 17 additions & 3 deletions src/modes/interOrderbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,14 @@ export async function dryrun({
evaluable: {
interpreter: orderPairObject.takeOrders[0].takeOrder.order.evaluable.interpreter,
store: orderPairObject.takeOrders[0].takeOrder.order.evaluable.store,
bytecode: "0x",
bytecode:
config.gasCoveragePercentage === "0"
? "0x"
: getBountyEnsureBytecode(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
ethers.constants.Zero,
),
},
signedContext: [],
};
Expand All @@ -102,7 +109,9 @@ export async function dryrun({
try {
blockNumber = Number(await viemClient.getBlockNumber());
spanAttributes["blockNumber"] = blockNumber;
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx));
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx))
.mul(config.gasLimitMultiplier)
.div(100);
} catch (e) {
const isNodeError = containsNodeError(e as BaseError);
const errMsg = errorSnapshot("", e);
Expand Down Expand Up @@ -144,7 +153,9 @@ export async function dryrun({
try {
blockNumber = Number(await viemClient.getBlockNumber());
spanAttributes["blockNumber"] = blockNumber;
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx));
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx))
.mul(config.gasLimitMultiplier)
.div(100);
rawtx.gas = gasLimit.toBigInt();
gasCost = gasLimit.mul(gasPrice);
task.evaluable.bytecode = getBountyEnsureBytecode(
Expand Down Expand Up @@ -179,6 +190,9 @@ export async function dryrun({
}
}
rawtx.gas = gasLimit.toBigInt();
if (typeof config.txGas === "bigint") {
rawtx.gas = config.txGas;
}

// if reached here, it means there was a success and found opp
spanAttributes["oppBlockNumber"] = blockNumber;
Expand Down
57 changes: 37 additions & 20 deletions src/modes/intraOrderbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ export async function dryrun({
const inputBountyVaultId = "1";
const outputBountyVaultId = "1";
const obInterface = new ethers.utils.Interface(orderbookAbi);
const task = {
evaluable: {
interpreter: orderPairObject.takeOrders[0].takeOrder.order.evaluable.interpreter,
store: orderPairObject.takeOrders[0].takeOrder.order.evaluable.store,
bytecode: getWithdrawEnsureBytecode(
signer.account.address,
orderPairObject.buyToken,
orderPairObject.sellToken,
inputBalance,
outputBalance,
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
ethers.constants.Zero,
),
},
signedContext: [],
};
const withdrawInputCalldata = obInterface.encodeFunctionData("withdraw2", [
orderPairObject.buyToken,
inputBountyVaultId,
Expand All @@ -59,7 +76,7 @@ export async function dryrun({
orderPairObject.sellToken,
outputBountyVaultId,
ethers.constants.MaxUint256,
[],
config.gasCoveragePercentage === "0" ? [] : [task],
]);
const clear2Calldata = obInterface.encodeFunctionData("clear2", [
orderPairObject.takeOrders[0].takeOrder.order,
Expand Down Expand Up @@ -89,7 +106,9 @@ export async function dryrun({
try {
blockNumber = Number(await viemClient.getBlockNumber());
spanAttributes["blockNumber"] = blockNumber;
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx));
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx))
.mul(config.gasLimitMultiplier)
.div(100);
} catch (e) {
// reason, code, method, transaction, error, stack, message
const isNodeError = containsNodeError(e as BaseError);
Expand Down Expand Up @@ -118,23 +137,16 @@ export async function dryrun({
// sender output which is already called above
if (config.gasCoveragePercentage !== "0") {
const headroom = (Number(config.gasCoveragePercentage) * 1.03).toFixed();
const task = {
evaluable: {
interpreter: orderPairObject.takeOrders[0].takeOrder.order.evaluable.interpreter,
store: orderPairObject.takeOrders[0].takeOrder.order.evaluable.store,
bytecode: getWithdrawEnsureBytecode(
signer.account.address,
orderPairObject.buyToken,
orderPairObject.sellToken,
inputBalance,
outputBalance,
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
gasCost.mul(headroom).div("100"),
),
},
signedContext: [],
};
task.evaluable.bytecode = getWithdrawEnsureBytecode(
signer.account.address,
orderPairObject.buyToken,
orderPairObject.sellToken,
inputBalance,
outputBalance,
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
gasCost.mul(headroom).div("100"),
);
withdrawOutputCalldata = obInterface.encodeFunctionData("withdraw2", [
orderPairObject.sellToken,
outputBountyVaultId,
Expand All @@ -148,7 +160,9 @@ export async function dryrun({
try {
blockNumber = Number(await viemClient.getBlockNumber());
spanAttributes["blockNumber"] = blockNumber;
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx));
gasLimit = ethers.BigNumber.from(await signer.estimateGas(rawtx))
.mul(config.gasLimitMultiplier)
.div(100);
rawtx.gas = gasLimit.toBigInt();
gasCost = gasLimit.mul(gasPrice);
task.evaluable.bytecode = getWithdrawEnsureBytecode(
Expand Down Expand Up @@ -192,6 +206,9 @@ export async function dryrun({
}
}
rawtx.gas = gasLimit.toBigInt();
if (typeof config.txGas === "bigint") {
rawtx.gas = config.txGas;
}

// if reached here, it means there was a success and found opp
spanAttributes["oppBlockNumber"] = blockNumber;
Expand Down
Loading
Loading