Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
rouzwelt committed Nov 25, 2024
1 parent 6cf7bac commit bee81c0
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 60 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Other optional arguments are:
- `--owner-profile`, Specifies the owner limit, example: --owner-profile 0x123456=12 . Will override the 'OWNER_PROFILE' in env variables
- `--public-rpc`, Allows to use public RPCs as fallbacks, default is false. Will override the 'PUBLIC_RPC' 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
- `--gas-limit-multiplier`, Option to multiply the gas limit estimation from the rpc as percentage, default is 108, ie +8%. 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 @@ -262,7 +262,7 @@ 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%
# Option to multiply the gas limit estimation from the rpc as percentage, default is 108, ie +8%
GAS_LIMIT_MULTIPLIER=

# Option to set a static gas limit for all submitting txs
Expand Down
2 changes: 1 addition & 1 deletion example.env
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ 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%
# Option to multiply the gas limit estimation from the rpc as percentage, default is 108, ie +8%
GAS_LIMIT_MULTIPLIER=

# Option to set a static gas limit for all submitting txs
Expand Down
27 changes: 21 additions & 6 deletions src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,11 @@ export async function sweepToMainWallet(
balance,
]) as `0x${string}`,
};
txs.push({ tx, bounty, balance: ethers.utils.formatUnits(balance, bounty.decimals) });
const gas = await fromWallet.estimateGas(tx);
txs.push({ tx, bounty, balance: ethers.utils.formatUnits(balance, bounty.decimals) });
cumulativeGasLimit = cumulativeGasLimit.add(gas);
} catch {
failedBounties.push(bounty);
addWatchedToken(bounty, failedBounties);
}
}

Expand Down Expand Up @@ -612,7 +612,7 @@ export async function sweepToMainWallet(
code: SpanStatusCode.ERROR,
message: "Failed to sweep back to main wallet: tx reverted",
});
failedBounties.push(txs[i].bounty);
addWatchedToken(txs[i].bounty, failedBounties);
}
fromWallet.BALANCE = fromWallet.BALANCE.sub(txCost);
} catch (error) {
Expand All @@ -621,14 +621,14 @@ export async function sweepToMainWallet(
code: SpanStatusCode.ERROR,
message: "Failed to sweep back to main wallet: " + errorSnapshot("", error),
});
failedBounties.push(txs[i].bounty);
addWatchedToken(txs[i].bounty, failedBounties);
}
span?.end();
}

// empty gas if all tokens are swept
if (!failedBounties.length) {
const span = tracer?.startSpan("sweep-gas-to-main-wallet", undefined, mainCtx);
const span = tracer?.startSpan("sweep-remaining-gas-to-main-wallet", undefined, mainCtx);
span?.setAttribute("details.wallet", fromWallet.account.address);
try {
const gasLimit = ethers.BigNumber.from(
Expand Down Expand Up @@ -889,7 +889,22 @@ export async function sweepToEth(config: BotConfig, tracer?: Tracer, ctx?: Conte
}

export async function setWatchedTokens(account: ViemClient, watchedTokens: TokenDetails[]) {
account.BOUNTY = watchedTokens;
account.BOUNTY = [...watchedTokens];
}

export function addWatchedToken(
token: TokenDetails,
watchedTokens: TokenDetails[],
account?: ViemClient,
) {
if (!watchedTokens.find((v) => v.address.toLowerCase() === token.address.toLowerCase())) {
watchedTokens.push(token);
}
if (account) {
if (!account.BOUNTY.find((v) => v.address.toLowerCase() === token.address.toLowerCase())) {
account.BOUNTY.push(token);
}
}
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ const getOptions = async (argv: any, version?: string) => {
)
.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 to multiply the gas limit estimation from the rpc as percentage, default is 108, ie +8%. Will override the 'GAS_LIMIT_MULTIPLIER' in env variables",
)
.option(
"--tx-gas <integer>",
Expand Down Expand Up @@ -446,7 +446,7 @@ export async function startup(argv: any, version?: string, tracer?: Tracer, ctx?
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;
options.gasLimitMultiplier = 108;
}
if (options.txGas) {
if (typeof options.txGas === "number") {
Expand Down Expand Up @@ -478,7 +478,7 @@ export async function startup(argv: any, version?: string, tracer?: Tracer, ctx?
}
const lastReadOrdersTimestamp = Math.floor(Date.now() / 1000);
const tokens = getOrdersTokens(ordersDetails);
options.tokens = [...tokens];
options.tokens = tokens;

// get config
const config = await getConfig(
Expand Down
3 changes: 3 additions & 0 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ export function errorSnapshot(header: string, err: any): string {
export function containsNodeError(err: BaseError): boolean {
try {
const snapshot = errorSnapshot("", err);
const parsed = parseRevertError(err);
return (
// err instanceof TransactionRejectedRpcError ||
// err instanceof InvalidInputRpcError ||
!!parsed.decoded ||
!!parsed.raw.data ||
err instanceof FeeCapTooLowError ||
err instanceof ExecutionRevertedError ||
err instanceof InsufficientFundsError ||
Expand Down
57 changes: 31 additions & 26 deletions src/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { OrderV3 } from "./abis";
import { SgOrder } from "./query";
import { Span } from "@opentelemetry/api";
import { hexlify } from "ethers/lib/utils";
import { addWatchedToken } from "./account";
import { getTokenSymbol, shuffleArray } from "./utils";
import { decodeAbiParameters, parseAbiParameters } from "viem";
import {
Expand Down Expand Up @@ -67,13 +68,14 @@ export async function getOrderPairs(
_outputSymbol = symbol;
}
} else {
if (!tokens.find((v) => v.address.toLowerCase() === _output.token.toLowerCase())) {
tokens.push({
addWatchedToken(
{
address: _output.token.toLowerCase(),
symbol: _outputSymbol,
decimals: _output.decimals,
});
}
},
tokens,
);
}

for (let k = 0; k < orderStruct.validInputs.length; k++) {
Expand All @@ -91,13 +93,14 @@ export async function getOrderPairs(
_inputSymbol = symbol;
}
} else {
if (!tokens.find((v) => v.address.toLowerCase() === _input.token.toLowerCase())) {
tokens.push({
addWatchedToken(
{
address: _input.token.toLowerCase(),
symbol: _inputSymbol,
decimals: _input.decimals,
});
}
},
tokens,
);
}

if (_input.token.toLowerCase() !== _output.token.toLowerCase())
Expand Down Expand Up @@ -278,29 +281,30 @@ export function prepareOrdersForRound(
for (const [, ownerProfile] of ownersProfileMap) {
let remainingLimit = ownerProfile.limit;
const activeOrdersProfiles = Array.from(ownerProfile.orders).filter((v) => v[1].active);
const remainingOrdersPairs = activeOrdersProfiles.filter(
let remainingOrdersPairs = activeOrdersProfiles.filter(
(v) => v[1].takeOrders.length > 0,
);
// reset if all orders are already consumed
if (remainingOrdersPairs.length === 0) {
for (const [orderHash, orderProfile] of activeOrdersProfiles) {
for (const [, orderProfile] of activeOrdersProfiles) {
orderProfile.takeOrders.push(...orderProfile.consumedTakeOrders.splice(0));
if (remainingLimit > 0) {
const consumingOrderPairs = orderProfile.takeOrders.splice(
0,
remainingLimit,
);
remainingLimit -= consumingOrderPairs.length;
orderProfile.consumedTakeOrders.push(...consumingOrderPairs);
gatherPairs(
orderbook,
orderHash,
consumingOrderPairs,
orderbookBundledOrders,
);
}
}
} else {
for (const [orderHash, orderProfile] of remainingOrdersPairs) {
remainingOrdersPairs = activeOrdersProfiles;
}
// consume orders limits
for (const [orderHash, orderProfile] of remainingOrdersPairs) {
if (remainingLimit > 0) {
const consumingOrderPairs = orderProfile.takeOrders.splice(0, remainingLimit);
remainingLimit -= consumingOrderPairs.length;
orderProfile.consumedTakeOrders.push(...consumingOrderPairs);
gatherPairs(orderbook, orderHash, consumingOrderPairs, orderbookBundledOrders);
}
}
// if all orders are consumed and still there is limit remaining,
// reset and start consuming again from top until limit is reached
if (remainingLimit > 0) {
for (const [orderHash, orderProfile] of activeOrdersProfiles) {
orderProfile.takeOrders.push(...orderProfile.consumedTakeOrders.splice(0));
if (remainingLimit > 0) {
const consumingOrderPairs = orderProfile.takeOrders.splice(
0,
Expand Down Expand Up @@ -351,6 +355,7 @@ function gatherPairs(
v.sellToken.toLowerCase() === pair.sellToken.toLowerCase(),
);
if (bundleOrder) {
// make sure to not duplicate
if (
!bundleOrder.takeOrders.find((v) => v.id.toLowerCase() === orderHash.toLowerCase())
) {
Expand Down
24 changes: 9 additions & 15 deletions src/processOrders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { privateKeyToAccount } from "viem/accounts";
import { BigNumber, Contract, ethers } from "ethers";
import { Tracer } from "@opentelemetry/sdk-trace-base";
import { Context, SpanStatusCode } from "@opentelemetry/api";
import { fundOwnedOrders, getNonce, rotateAccounts } from "./account";
import { addWatchedToken, fundOwnedOrders, getNonce, rotateAccounts } from "./account";
import { containsNodeError, ErrorSeverity, errorSnapshot, handleRevert, isTimeout } from "./error";
import {
Report,
Expand Down Expand Up @@ -762,27 +762,21 @@ export async function processPair(args: {

// keep track of gas consumption of the account and bounty token
result.gasCost = actualGasCost;
if (
inputTokenIncome &&
inputTokenIncome.gt(0) &&
!signer.BOUNTY.find((v) => v.address === orderPairObject.buyToken)
) {
signer.BOUNTY.push({
if (inputTokenIncome && inputTokenIncome.gt(0)) {
const tkn = {
address: orderPairObject.buyToken.toLowerCase(),
decimals: orderPairObject.buyTokenDecimals,
symbol: orderPairObject.buyTokenSymbol,
});
};
addWatchedToken(tkn, config.watchedTokens ?? [], signer);
}
if (
outputTokenIncome &&
outputTokenIncome.gt(0) &&
!signer.BOUNTY.find((v) => v.address === orderPairObject.sellToken)
) {
signer.BOUNTY.push({
if (outputTokenIncome && outputTokenIncome.gt(0)) {
const tkn = {
address: orderPairObject.sellToken.toLowerCase(),
decimals: orderPairObject.sellTokenDecimals,
symbol: orderPairObject.sellTokenSymbol,
});
};
addWatchedToken(tkn, config.watchedTokens ?? [], signer);
}
return result;
} else {
Expand Down
63 changes: 56 additions & 7 deletions test/orders.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ describe("Test order details", async function () {
[order1, order2, order3, order4, order5, order6, order7, order8],
undefined,
[],
{ [owner1]: 3, [owner2]: 1 }, // set owner1 limit as 3, owner2 to 1
{ [owner1]: 4, [owner2]: 1 }, // set owner1 limit as 4, owner2 to 1
);

// prepare orders for first round
Expand All @@ -768,8 +768,8 @@ describe("Test order details", async function () {
sellTokenSymbol: token2.symbol,
sellTokenDecimals: token2.decimals,
orderbook,
// first 3 owner1 orders for round1, owner1 limit is 3
takeOrders: owner1Orders.slice(0, 3).map((v) => ({
// first 4 owner1 orders for round1, owner1 limit is 4
takeOrders: owner1Orders.slice(0, 4).map((v) => ({
id: v.id,
takeOrder: {
order: v.struct,
Expand Down Expand Up @@ -814,8 +814,11 @@ describe("Test order details", async function () {
sellTokenSymbol: token2.symbol,
sellTokenDecimals: token2.decimals,
orderbook,
// second 3 owner1 orders for round2, owner1 limit is 3
takeOrders: owner1Orders.slice(3, owner1Orders.length).map((v) => ({
// first2 and last 2 owner1 orders for round2, owner1 limit is 4
takeOrders: [
...owner1Orders.slice(4, owner1Orders.length),
...owner1Orders.slice(0, 2),
].map((v) => ({
id: v.id,
takeOrder: {
order: v.struct,
Expand Down Expand Up @@ -861,8 +864,8 @@ describe("Test order details", async function () {
sellTokenSymbol: token2.symbol,
sellTokenDecimals: token2.decimals,
orderbook,
// first 3 owner1 orders again for round3, owner1 limit is 3
takeOrders: owner1Orders.slice(0, 3).map((v) => ({
// last 4 owner1 orders again for round3, owner1 limit is 4
takeOrders: owner1Orders.slice(2).map((v) => ({
id: v.id,
takeOrder: {
order: v.struct,
Expand Down Expand Up @@ -894,6 +897,52 @@ describe("Test order details", async function () {
],
];
assert.deepEqual(result3, expected3);

// prepare orders for 4th round
const result4 = prepareOrdersForRound(allOrders, false);
const expected4 = [
[
{
buyToken: token1.address,
buyTokenSymbol: token1.symbol,
buyTokenDecimals: token1.decimals,
sellToken: token2.address,
sellTokenSymbol: token2.symbol,
sellTokenDecimals: token2.decimals,
orderbook,
// back to first 4 owner1 orders for round4, owner1 limit is 4
takeOrders: owner1Orders.slice(0, 4).map((v) => ({
id: v.id,
takeOrder: {
order: v.struct,
inputIOIndex: 0,
outputIOIndex: 0,
signedContext: [],
},
})),
},
{
buyToken: token2.address,
buyTokenSymbol: token2.symbol,
buyTokenDecimals: token2.decimals,
sellToken: token1.address,
sellTokenSymbol: token1.symbol,
sellTokenDecimals: token1.decimals,
orderbook,
// second 1 owner2 orders for round4, owner2 limit is 1
takeOrders: owner2Orders.slice(1).map((v) => ({
id: v.id,
takeOrder: {
order: v.struct,
inputIOIndex: 0,
outputIOIndex: 0,
signedContext: [],
},
})),
},
],
];
assert.deepEqual(result4, expected4);
});
});

Expand Down

0 comments on commit bee81c0

Please sign in to comment.