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

fix unresolved reverts error and load txs across available wallets #278

Merged
merged 15 commits into from
Dec 11, 2024
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@ Other optional arguments are:
- `--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 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
- `--rp-only`, Only clear orders through RP4, excludes intra and inter orderbook clears. Will override the 'RP_ONLY' in env variablesin env variables
- `-V` or `--version`, output the version number
- `-h` or `--help`, output usage information

<br>
<br>

### List of available supported dexes (decentralized exchanges)
- all of the below names are case INSENSITIVE:
Expand Down Expand Up @@ -267,6 +268,9 @@ GAS_LIMIT_MULTIPLIER=

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

# Only clear orders through RP4, excludes intra and inter orderbook clears
RP_ONLY="true"
```
If both env variables and CLI argument are set, the CLI arguments will be prioritized and override the env variables.

Expand Down
3 changes: 3 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ GAS_LIMIT_MULTIPLIER=
# Option to set a static gas limit for all submitting txs
TX_GAS=

# Only clear orders through RP4, excludes intra and inter orderbook clears
RP_ONLY="true"


# test rpcs vars
TEST_POLYGON_RPC=
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"scripts": {
"prepublish": "npm run build",
"test": "npm run unit-test && npm run e2e-test",
"unit-test": "hardhat test ./test/*.test.js",
"unit-test": "hardhat test ./test/*.test.*",
"e2e-test": "hardhat test",
"lint": "eslint ./src ./test ./arb-bot.js",
"lint-fix": "eslint ./src ./test ./arb-bot.js --fix",
Expand Down
5 changes: 5 additions & 0 deletions src/abis.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { parseAbi } from "viem";

/**
* Minimal ABI for ERC20 contract only including Transfer event
*/
Expand Down Expand Up @@ -45,6 +47,7 @@ export const orderbookAbi = [
"function multicall(bytes[] calldata data) external returns (bytes[] memory results)",
`function takeOrders2(${TakeOrdersConfigV3} memory config) external returns (uint256 totalInput, uint256 totalOutput)`,
`function clear2(${OrderV3} memory aliceOrder, ${OrderV3} memory bobOrder, ${ClearConfig} calldata clearConfig, ${SignedContextV1}[] memory aliceSignedContext, ${SignedContextV1}[] memory bobSignedContext) external`,
`event TakeOrderV2(address sender, ${TakeOrderConfigV3} config, uint256 input, uint256 output)`,
] as const;

/**
Expand Down Expand Up @@ -89,3 +92,5 @@ export const DefaultArbEvaluable = {
store: "0x" + "0".repeat(40),
bytecode: "0x",
} as const;

export const TakeOrderV2EventAbi = parseAbi([orderbookAbi[13]]);
52 changes: 10 additions & 42 deletions src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,9 @@ export async function initAccounts(
span?.setAttribute("details.wallet", accounts[i].account.address);
span?.setAttribute("details.amount", ethers.utils.formatUnits(transferAmount));
try {
const hash = await mainAccount.sendTransaction({
const hash = await mainAccount.sendTx({
to: accounts[i].account.address,
value: transferAmount.toBigInt(),
nonce: await getNonce(mainAccount),
});
const receipt = await mainAccount.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -248,10 +247,9 @@ export async function manageAccounts(
continue;
}
try {
const hash = await config.mainAccount.sendTransaction({
const hash = await config.mainAccount.sendTx({
to: acc.account.address,
value: transferAmount.toBigInt(),
nonce: await getNonce(config.mainAccount),
});
const receipt = await config.mainAccount.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -543,10 +541,9 @@ export async function sweepToMainWallet(
.div(100)
.sub(fromWallet.BALANCE);
span?.setAttribute("details.amount", ethers.utils.formatUnits(transferAmount));
const hash = await toWallet.sendTransaction({
const hash = await toWallet.sendTx({
to: fromWallet.account.address,
value: transferAmount.toBigInt(),
nonce: await getNonce(toWallet),
});
const receipt = await toWallet.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -589,9 +586,7 @@ export async function sweepToMainWallet(
span?.setAttribute("details.tokenAddress", txs[i].bounty.address);
span?.setAttribute("details.balance", txs[i].balance);
try {
const nonce = await getNonce(fromWallet);
(txs[i].tx as any).nonce = nonce;
const hash = await fromWallet.sendTransaction(txs[i].tx);
const hash = await fromWallet.sendTx(txs[i].tx);
const receipt = await fromWallet.waitForTransactionReceipt({
hash,
confirmations: 4,
Expand Down Expand Up @@ -643,12 +638,11 @@ export async function sweepToMainWallet(
const transferAmount = remainingGas.sub(gasLimit.mul(gasPrice));
if (transferAmount.gt(0)) {
span?.setAttribute("details.amount", ethers.utils.formatUnits(transferAmount));
const hash = await fromWallet.sendTransaction({
const hash = await fromWallet.sendTx({
gasPrice,
to: toWallet.account.address,
value: transferAmount.toBigInt(),
gas: gasLimit.toBigInt(),
nonce: await getNonce(fromWallet),
});
const receipt = await fromWallet.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -791,13 +785,12 @@ export async function sweepToEth(config: BotConfig, tracer?: Tracer, ctx?: Conte
).data;
if (allowance && balance.gt(allowance)) {
span?.addEvent("Approving spend limit");
const hash = await config.mainAccount.sendTransaction({
const hash = await config.mainAccount.sendTx({
to: bounty.address as `0x${string}`,
data: erc20.encodeFunctionData("approve", [
rp4Address,
balance.mul(100),
]) as `0x${string}`,
nonce: await getNonce(config.mainAccount),
});
await config.mainAccount.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -838,9 +831,7 @@ export async function sweepToEth(config: BotConfig, tracer?: Tracer, ctx?: Conte
span?.end();
continue;
} else {
const nonce = await getNonce(config.mainAccount);
(rawtx as any).nonce = nonce;
const hash = await config.mainAccount.sendTransaction(rawtx);
const hash = await config.mainAccount.sendTx(rawtx);
span?.setAttribute("txHash", hash);
const receipt = await config.mainAccount.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -1012,11 +1003,10 @@ export async function fundOwnedOrders(
finalRpParams!.to,
finalRpParams!.routeCode,
]) as `0x${string}`;
const swapHash = await config.mainAccount.sendTransaction({
const swapHash = await config.mainAccount.sendTx({
to: rp4Address,
value: sellAmount!.toBigInt(),
data,
nonce: await getNonce(config.mainAccount),
});
const swapReceipt = await config.mainAccount.waitForTransactionReceipt({
hash: swapHash,
Expand Down Expand Up @@ -1046,13 +1036,12 @@ export async function fundOwnedOrders(
})
).data;
if (allowance && topupAmount.gt(allowance)) {
const approveHash = await config.mainAccount.sendTransaction({
const approveHash = await config.mainAccount.sendTx({
to: ownedOrder.token as `0x${string}`,
data: erc20.encodeFunctionData("approve", [
ownedOrder.orderbook,
topupAmount.mul(20),
]) as `0x${string}`,
nonce: await getNonce(config.mainAccount),
});
const approveReceipt =
await config.mainAccount.waitForTransactionReceipt({
Expand All @@ -1070,15 +1059,14 @@ export async function fundOwnedOrders(
}
}

const hash = await config.mainAccount.sendTransaction({
const hash = await config.mainAccount.sendTx({
to: ownedOrder.orderbook as `0x${string}`,
data: ob.encodeFunctionData("deposit2", [
ownedOrder.token,
vaultId,
topupAmount,
[],
]) as `0x${string}`,
nonce: await getNonce(config.mainAccount),
});
const receipt = await config.mainAccount.waitForTransactionReceipt({
hash,
Expand Down Expand Up @@ -1138,23 +1126,3 @@ async function getTransactionCount(
);
return hexToNumber(count);
}

/**
* Get an account's nonce
* @param client - The viem client
* @param address - account address
*/
export async function getNonce(client: ViemClient): Promise<number> {
for (let i = 0; i < 3; i++) {
try {
return await client.getTransactionCount({
address: client.account.address,
blockTag: "latest",
});
} catch (error) {
if (i === 2) throw error;
else await sleep((i + 1) * 5000);
}
}
throw "Failed to get account's nonce";
}
6 changes: 6 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const ENV_OPTIONS = {
gasLimitMultiplier: process?.env?.GAS_LIMIT_MULTIPLIER,
txGas: process?.env?.TX_GAS,
route: process?.env?.ROUTE,
rpOnly: process?.env?.RP_ONLY?.toLowerCase() === "true" ? true : false,
ownerProfile: process?.env?.OWNER_PROFILE
? Array.from(process?.env?.OWNER_PROFILE.matchAll(/[^,\s]+/g)).map((v) => v[0])
: undefined,
Expand Down Expand Up @@ -200,6 +201,10 @@ const getOptions = async (argv: any, version?: string) => {
"--tx-gas <integer>",
"Option to set a static gas limit for all submitting txs. Will override the 'TX_GAS' in env variables",
)
.option(
"--rp-only",
"Only clear orders through RP4, excludes intra and inter orderbook clears. Will override the 'RP_ONLY' 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 @@ -246,6 +251,7 @@ const getOptions = async (argv: any, version?: string) => {
cmdOptions.ownerProfile = cmdOptions.ownerProfile || getEnv(ENV_OPTIONS.ownerProfile);
cmdOptions.route = cmdOptions.route || getEnv(ENV_OPTIONS.route);
cmdOptions.publicRpc = cmdOptions.publicRpc || getEnv(ENV_OPTIONS.publicRpc);
cmdOptions.rpOnly = cmdOptions.rpOnly || getEnv(ENV_OPTIONS.rpOnly);
if (cmdOptions.ownerProfile) {
const profiles: Record<string, number> = {};
cmdOptions.ownerProfile.forEach((v: string) => {
Expand Down
15 changes: 12 additions & 3 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
ROUTE_PROCESSOR_3_1_ADDRESS,
ROUTE_PROCESSOR_3_2_ADDRESS,
} from "sushi/config";
import { sendTransaction } from "./tx";

/**
* Get the chain config for a given chain id
Expand Down Expand Up @@ -114,7 +115,7 @@ export async function createViemClient(
? fallback([...topRpcs, ...fallbacks], configuration)
: fallback(topRpcs, configuration);

return testClient
const client = testClient
? ((await testClient({ account }))
.extend(publicActions)
.extend(walletActions) as any as ViemClient)
Expand All @@ -123,6 +124,14 @@ export async function createViemClient(
chain: publicClientConfig[chainId]?.chain,
transport,
}).extend(publicActions) as any as ViemClient);

// set injected properties
client.BUSY = false;
client.sendTx = async (tx) => {
return await sendTransaction(client, tx);
};

return client;
}

/**
Expand Down Expand Up @@ -228,7 +237,7 @@ export function getBountyEnsureBytecode(
const minimum = minimumExcepted.toHexString().substring(2).padStart(64, "0");
const msgSender = sender.substring(2).padStart(64, "0").toLowerCase();
// rainlang bytecode:
// :ensure(sender context<0 0>()),
// :ensure(equal-to(sender context<0 0>()) \"unknown sender\"),
// :ensure(
// greater-than-or-equal-to(
// add(
Expand Down Expand Up @@ -274,7 +283,7 @@ export function getWithdrawEnsureBytecode(
const minimum = minimumExcepted.toHexString().substring(2).padStart(64, "0");
const msgSender = sender.substring(2).padStart(64, "0").toLowerCase();
// rainlang bytecode:
// :ensure(sender context<0 0>()),
// :ensure(equal-to(sender context<0 0>()) \"unknown sender\"),
// :ensure(
// greater-than-or-equal-to(
// add(
Expand Down
Loading
Loading