Skip to content

Commit

Permalink
Merge pull request #262 from rainlanguage/2024-11-20-tackle-fee-cap-l…
Browse files Browse the repository at this point in the history
…ow-err

tackle fee cap low err
  • Loading branch information
rouzwelt authored Nov 23, 2024
2 parents 172aa0c + 9c8a24c commit 30b4859
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 271 deletions.
21 changes: 13 additions & 8 deletions src/account.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChainId, RPParams } from "sushi";
import { BigNumber, ethers } from "ethers";
import { ErrorSeverity, errorSnapshot } from "./error";
import { Native, Token, WNATIVE } from "sushi/currency";
import { ROUTE_PROCESSOR_4_ADDRESS } from "sushi/config";
import { getRpSwap, PoolBlackList, sleep } from "./utils";
import { createViemClient, getDataFetcher } from "./config";
import { ChainId, LiquidityProviders, RPParams } from "sushi";
import { mnemonicToAccount, privateKeyToAccount } from "viem/accounts";
import { erc20Abi, multicall3Abi, orderbookAbi, routeProcessor3Abi } from "./abis";
import { context, Context, SpanStatusCode, trace, Tracer } from "@opentelemetry/api";
Expand Down Expand Up @@ -157,10 +157,10 @@ export async function manageAccounts(
) {
const removedWallets: ViemClient[] = [];
let accountsToAdd = 0;
const gasPrice = await config.viemClient.getGasPrice();
for (let i = config.accounts.length - 1; i >= 0; i--) {
if (config.accounts[i].BALANCE.lt(avgGasCost.mul(4))) {
try {
const gasPrice = await config.viemClient.getGasPrice();
await sweepToMainWallet(
config.accounts[i],
config.mainAccount,
Expand Down Expand Up @@ -529,16 +529,20 @@ export async function sweepToMainWallet(
}
}

if (cumulativeGasLimit.mul(gasPrice).gt(fromWallet.BALANCE)) {
if (cumulativeGasLimit.mul(gasPrice).mul(125).div(100).gt(fromWallet.BALANCE)) {
const span = tracer?.startSpan("fund-wallet-to-sweep", undefined, mainCtx);
span?.setAttribute("details.wallet", fromWallet.account.address);
try {
const transferAmount = cumulativeGasLimit.mul(gasPrice).sub(fromWallet.BALANCE);
const transferAmount = cumulativeGasLimit
.mul(gasPrice)
.mul(125)
.div(100)
.sub(fromWallet.BALANCE);
span?.setAttribute("details.amount", ethers.utils.formatUnits(transferAmount));
const hash = await toWallet.sendTransaction({
to: fromWallet.account.address,
value: transferAmount.toBigInt(),
nonce: await getNonce(fromWallet),
nonce: await getNonce(toWallet),
});
const receipt = await toWallet.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -636,6 +640,7 @@ export async function sweepToMainWallet(
if (transferAmount.gt(0)) {
span?.setAttribute("details.amount", ethers.utils.formatUnits(transferAmount));
const hash = await fromWallet.sendTransaction({
gasPrice,
to: toWallet.account.address,
value: transferAmount.toBigInt(),
gas: gasLimit.toBigInt(),
Expand Down Expand Up @@ -742,7 +747,7 @@ export async function sweepToEth(config: BotConfig, tracer?: Tracer, ctx?: Conte
rp4Address,
config.dataFetcher,
gasPrice,
Object.values(LiquidityProviders).filter((v) => v !== LiquidityProviders.CurveSwap),
config.lps,
);
let routeText = "";
route.legs.forEach((v, i) => {
Expand Down Expand Up @@ -799,7 +804,7 @@ export async function sweepToEth(config: BotConfig, tracer?: Tracer, ctx?: Conte
const rawtx = { to: rp4Address, data: "0x" as `0x${string}` };
let gas = 0n;
let amountOutMin = ethers.constants.Zero;
for (let j = 50; j > 0; j--) {
for (let j = 50; j > 39; j--) {
amountOutMin = ethers.BigNumber.from(rpParams.amountOutMin)
.mul(2 * j)
.div(100);
Expand All @@ -815,7 +820,7 @@ export async function sweepToEth(config: BotConfig, tracer?: Tracer, ctx?: Conte
gas = await config.mainAccount.estimateGas(rawtx);
break;
} catch (error) {
if (j === 1) throw error;
if (j === 40) throw error;
}
}
const gasCost = gasPrice.mul(gas).mul(15).div(10);
Expand Down
34 changes: 29 additions & 5 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ import { BotConfig, CliOptions, ViemClient } from "./types";
import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { manageAccounts, rotateProviders, sweepToMainWallet, sweepToEth } from "./account";
import {
sweepToEth,
manageAccounts,
rotateProviders,
sweepToMainWallet,
getBatchEthBalance,
} from "./account";
import {
diag,
trace,
Expand Down Expand Up @@ -310,7 +316,7 @@ export const arbRound = async (
span.setAttribute("didClear", false);
}
if (avgGasCost) {
span.setAttribute("avgGasCost", avgGasCost.toString());
span.setAttribute("avgGasCost", ethers.utils.formatUnits(avgGasCost));
}
span.setStatus({ code: SpanStatusCode.OK });
span.end();
Expand Down Expand Up @@ -627,6 +633,19 @@ export const main = async (argv: any, version?: string) => {
roundSpan.setAttribute("didClear", false);
}

// fecth account's balances
if (foundOpp && config.accounts.length) {
try {
const balances = await getBatchEthBalance(
config.accounts.map((v) => v.account.address),
config.viemClient as any as ViemClient,
);
config.accounts.forEach((v, i) => (v.BALANCE = balances[i]));
} catch {
/**/
}
}

// keep avg gas cost
if (roundAvgGasCost) {
const _now = Date.now();
Expand Down Expand Up @@ -713,10 +732,15 @@ export const main = async (argv: any, version?: string) => {
roundSpan.setStatus({ code: SpanStatusCode.ERROR, message: snapshot });
}
if (config.accounts.length) {
roundSpan.setAttribute(
"circulatingAccounts",
config.accounts.map((v) => v.account.address),
const accountsWithBalance: Record<string, string> = {};
config.accounts.forEach(
(v) =>
(accountsWithBalance[v.account.address] = ethers.utils.formatUnits(
v.BALANCE,
)),
);
roundSpan.setAttribute("circulatingAccounts", JSON.stringify(accountsWithBalance));
roundSpan.setAttribute("lastAccountIndex", lastUsedAccountIndex);
}
if (avgGasCost) {
roundSpan.setAttribute("avgGasCost", ethers.utils.formatUnits(avgGasCost));
Expand Down
22 changes: 17 additions & 5 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import { abi as genericArbAbi } from "../test/abis/GenericPoolOrderBookV4ArbOrde
import {
isHex,
BaseError,
TimeoutError,
RpcRequestError,
FeeCapTooLowError,
decodeErrorResult,
ExecutionRevertedError,
InsufficientFundsError,
Expand Down Expand Up @@ -63,11 +65,7 @@ export function errorSnapshot(header: string, err: any): string {
if (err.name) message.push("Error: " + err.name);
if (err.details) {
message.push("Details: " + err.details);
if (
err.name.includes("unknown reason") ||
err.details.includes("unknown reason") ||
err.shortMessage.includes("unknown reason")
) {
if (message.some((v) => v.includes("unknown reason"))) {
const { raw, decoded } = parseRevertError(err);
if (decoded) {
message.push("Error Name: " + decoded.name);
Expand Down Expand Up @@ -100,19 +98,33 @@ export function errorSnapshot(header: string, err: any): string {
*/
export function containsNodeError(err: BaseError): boolean {
try {
const snapshot = errorSnapshot("", err);
return (
// err instanceof TransactionRejectedRpcError ||
// err instanceof InvalidInputRpcError ||
err instanceof FeeCapTooLowError ||
err instanceof ExecutionRevertedError ||
err instanceof InsufficientFundsError ||
(err instanceof RpcRequestError && err.code === ExecutionRevertedError.code) ||
(snapshot.includes("exceeds allowance") && !snapshot.includes("out of gas")) ||
("cause" in err && containsNodeError(err.cause as any))
);
} catch (error) {
return false;
}
}

/**
* Checks if a viem BaseError is timeout error
*/
export function isTimeout(err: BaseError): boolean {
try {
return err instanceof TimeoutError || ("cause" in err && isTimeout(err.cause as any));
} catch (error) {
return false;
}
}

/**
* Handles a reverted transaction by simulating it and returning the revert error
*/
Expand Down
75 changes: 34 additions & 41 deletions src/modes/interOrderbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,13 @@ export async function dryrun({
try {
blockNumber = Number(await viemClient.getBlockNumber());
spanAttributes["blockNumber"] = blockNumber;
try {
gasPrice = ethers.BigNumber.from(await viemClient.getGasPrice())
.mul(config.gasPriceMultiplier)
.div("100")
.toBigInt();
rawtx.gasPrice = gasPrice;
} catch {
/**/
}
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);
spanAttributes["stage"] = 1;
spanAttributes["isNodeError"] = isNodeError;
spanAttributes["error"] = errMsg;
spanAttributes["rawtx"] = JSON.stringify(
Expand Down Expand Up @@ -180,6 +172,7 @@ export async function dryrun({
} catch (e) {
const isNodeError = containsNodeError(e as BaseError);
const errMsg = errorSnapshot("", e);
spanAttributes["stage"] = 2;
spanAttributes["isNodeError"] = isNodeError;
spanAttributes["error"] = errMsg;
spanAttributes["rawtx"] = JSON.stringify(
Expand Down Expand Up @@ -276,7 +269,7 @@ export async function findOpp({
.filter((v) => v !== undefined) as BundledOrders[];

if (!opposingOrderbookOrders || !opposingOrderbookOrders.length) throw undefined;
let maximumInput = orderPairObject.takeOrders.reduce(
const maximumInput = orderPairObject.takeOrders.reduce(
(a, b) => a.add(b.quote!.maxOutput),
ethers.constants.Zero,
);
Expand Down Expand Up @@ -311,37 +304,37 @@ export async function findOpp({
for (const err of (e as AggregateError).errors) {
allNoneNodeErrors.push(err?.value?.noneNodeError);
}
maximumInput = maximumInput.div(2);
try {
// try to find the first resolving binary search
return await Promise.any(
opposingOrderbookOrders.map((v) => {
// filter out the same owner orders
const opposingOrders = {
...v,
takeOrders: v.takeOrders.filter(
(e) =>
e.takeOrder.order.owner.toLowerCase() !==
orderPairObject.takeOrders[0].takeOrder.order.owner.toLowerCase(),
),
};
return binarySearch({
orderPairObject,
opposingOrders,
signer,
maximumInput,
gasPrice,
arb,
inputToEthPrice,
outputToEthPrice,
config,
viemClient,
});
}),
);
} catch {
/**/
}
// maximumInput = maximumInput.div(2);
// try {
// // try to find the first resolving binary search
// return await Promise.any(
// opposingOrderbookOrders.map((v) => {
// // filter out the same owner orders
// const opposingOrders = {
// ...v,
// takeOrders: v.takeOrders.filter(
// (e) =>
// e.takeOrder.order.owner.toLowerCase() !==
// orderPairObject.takeOrders[0].takeOrder.order.owner.toLowerCase(),
// ),
// };
// return binarySearch({
// orderPairObject,
// opposingOrders,
// signer,
// maximumInput,
// gasPrice,
// arb,
// inputToEthPrice,
// outputToEthPrice,
// config,
// viemClient,
// });
// }),
// );
// } catch {
// /**/
// }
const allOrderbooksAttributes: any = {};
for (let i = 0; i < e.errors.length; i++) {
allOrderbooksAttributes[opposingOrderbookOrders[i].orderbook] =
Expand Down
11 changes: 2 additions & 9 deletions src/modes/intraOrderbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,14 @@ export async function dryrun({
try {
blockNumber = Number(await viemClient.getBlockNumber());
spanAttributes["blockNumber"] = blockNumber;
try {
gasPrice = ethers.BigNumber.from(await viemClient.getGasPrice())
.mul(config.gasPriceMultiplier)
.div("100")
.toBigInt();
rawtx.gasPrice = gasPrice;
} catch {
/**/
}
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);
const errMsg = errorSnapshot("", e);
spanAttributes["stage"] = 1;
spanAttributes["isNodeError"] = isNodeError;
spanAttributes["error"] = errMsg;
spanAttributes["rawtx"] = JSON.stringify(
Expand Down Expand Up @@ -196,6 +188,7 @@ export async function dryrun({
} catch (e) {
const isNodeError = containsNodeError(e as BaseError);
const errMsg = errorSnapshot("", e);
spanAttributes["stage"] = 2;
spanAttributes["isNodeError"] = isNodeError;
spanAttributes["error"] = errMsg;
spanAttributes["rawtx"] = JSON.stringify(
Expand Down
Loading

0 comments on commit 30b4859

Please sign in to comment.