Skip to content

Commit

Permalink
Merge pull request #26 from rainprotocol/2023-08-25-orderbook-arb-taker
Browse files Browse the repository at this point in the history
ob v3 and arb order taker support [major]
  • Loading branch information
rouzwelt authored Sep 5, 2023
2 parents c5429d4 + f0ecda5 commit 517caa6
Show file tree
Hide file tree
Showing 41 changed files with 67,725 additions and 4,383 deletions.
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ node arb-bot -k 12ab... -r https://... --orderbook-address 0x1a2b... --arb-addre
```
The app requires these arguments (all arguments can be set in env variables alternatively, more details below):
- `-k` or `--key`, Private key of wallet that performs the transactions. Will override the 'BOT_WALLET_PRIVATEKEY' in env variables
- `-r` or `--rpc`, RPC URL that will be provider for interacting with evm. Will override the 'RPC_URL' in env variables
- `-m` or `--mode`, Running mode of the bot, must be one of: `0x` or `curve` or `router`, Will override the 'MODE' in env variables
- `-r` or `--rpc`, RPC URL(s) that will be provider for interacting with evm, use different providers if more than 1 is specified to prevent banning. Will override the 'RPC_URL' in env variables
- `-m` or `--mode`, Running mode of the bot, must be one of: `0x` or `curve` or `router` or `srouter`, Will override the 'MODE' in env variables
- `--orderbook-address`, Address of the deployed orderbook contract, Will override the 'ORDERBOOK_ADDRESS' in env variables
- `--arb-address`, Address of the deployed arb contract, Will override the 'ARB_ADDRESS' in env variables
- `--arb-contract-type`, Type of the Arb contract, can be either of `flash-loan-v2` or `flash-loan-v3` or `order-taker`, not availabe for `srouter` mode since it is a specialized mode, Will override the 'ARB_TYPE' in env variables

as well as at least one or both of below arguments:

Expand All @@ -53,7 +54,7 @@ Other optional arguments are:
- `--order-interpreter`, Option to filter the subgraph query results with a specific order's interpreter address, Will override the 'ORDER_INTERPRETER' in env variables
- `--monthly-ratelimit`, 0x monthly rate limit, if not specified will not respect any 0x monthly ratelimit, Will override the 'MONTHLY_RATELIMIT' in env variables
- `--sleep`, Seconds to wait between each arb round, default is 10, Will override the 'SLEPP' in env variables
- `--use-zeroex-arb`, Option to use old version of Arb contract for `0x` mode, i.e dedicated 0x Arb contract, ONLY available for `0x` mode
- `--max-profit`, Option to maximize profit for 'srouter' mode, comes at the cost of more RPC calls, Will override the 'MAX_PROFIT' in env variables
- `-V` or `--version`, output the version number
- `-h` or `--help`, output usage information

Expand Down Expand Up @@ -99,12 +100,13 @@ which will show:

Options:
-k, --key <private-key> Private key of wallet that performs the transactions. Will override the 'BOT_WALLET_PRIVATEKEY' in env variables
-r, --rpc <url> RPC URL that will be provider for interacting with evm. Will override the 'RPC_URL' in env variables
-m, --mode <string> Running mode of the bot, must be one of: `0x` or `curve` or `router`, Will override the 'MODE' in env variables
-r, --rpc <url...> RPC URL(s) that will be provider for interacting with evm, use different providers if more than 1 is specified to prevent banning. Will override the 'RPC_URL' in env variables
-m, --mode <string> Running mode of the bot, must be one of: `0x` or `curve` or `router` or `srouter`, Will override the 'MODE' in env variables
-o, --orders <path> The path to a local json file containing the orders details, can be used in combination with --subgraph, Will override the 'ORDERS' in env variables
-s, --subgraph <url...> Subgraph URL(s) to read orders details from, can be used in combination with --orders, Will override the 'SUBGRAPH' in env variables
--orderbook-address <address> Address of the deployed orderbook contract, Will override the 'ORDERBOOK_ADDRESS' in env variables
--arb-address <address> Address of the deployed arb contract, Will override the 'ARB_ADDRESS' in env variables
--arb-contract-type <string> Type of the Arb contract, can be either of `flash-loan-v2` or `flash-loan-v3` or `order-taker`, not availabe for `srouter` mode since it is a specialized mode, Will override the 'ARB_TYPE' in env variables
-l, --lps <string> List of liquidity providers (dex) to use by the router as one quoted string seperated by a comma for each, example: 'SushiSwapV2,UniswapV3', Will override the 'LIQUIDITY_PROVIDERS' in env variables, if unset will use all available liquidty providers
-a, --api-key <key> 0x API key, can be set in env variables, Will override the 'API_KEY' env variable
-g, --gas-coverage <integer> The percentage of gas to cover to be considered profitable for the transaction to be submitted, an integer greater than equal 0, default is 100 meaning full coverage, Will override the 'GAS_COVER' in env variables
Expand All @@ -114,7 +116,7 @@ which will show:
--order-interpreter <address> Option to filter the subgraph query results with a specific order's interpreter address, Will override the 'ORDER_INTERPRETER' in env variables
--monthly-ratelimit <integer> 0x monthly rate limit, if not specified will not respect any 0x monthly ratelimit, Will override the 'MONTHLY_RATELIMIT' in env variables
--sleep <integer> Seconds to wait between each arb round, default is 10, Will override the 'SLEPP' in env variables
--use-zeroex-arb Option to use old version of Arb contract for `0x` mode, i.e dedicated 0x Arb contract, ONLY available for `0x` mode
--max-profit Option to maximize profit for 'srouter' mode, comes at the cost of more RPC calls, Will override the 'MAX_PROFIT' in env variables
-V, --version output the version number
-h, --help display help for command
<br>
Expand All @@ -124,10 +126,11 @@ Alternatively all variables can be specified in env variables with below keys:
# private key of the matchmaker bot's wallet
BOT_WALLET_PRIVATEKEY="123..."

# RPC URL of the desired network, personal RPC API endpoints are preferened
RPC_URL="https://polygon-mainnet.g.alchemy.com/v2/{API_KEY}"
# RPC URL(s) that will be provider for interacting with evm, use different providers if more than 1 is specified to prevent banning.
# for specifying more than 1 RPC in the env, separate them by a comma and a space
RPC_URL="https://polygon-mainnet.g.alchemy.com/v2/{API_KEY}, https://rpc.ankr.com/polygon/{API_KEY}"

# bot running mode, one of "router", "0x", "curve"
# bot running mode, one of "router", "0x", "curve", "srouter"
MODE="router"

# arb contract address
Expand Down Expand Up @@ -156,9 +159,6 @@ GAS_COVER="100"
# 0x monthly rate limit number, if not specified will not respect 0x monthly rate limit
MONTHLY_RATELIMIT=200000

# option to use old version of arb contract for 0x mode, i.e dedicated 0x arb contract
USE_ZEROEX_ARB="false"

# an integer used for specifiying the number repetitions for the app to run, if not set will run for infinite number of times
REPETITIONS=1

Expand All @@ -171,6 +171,12 @@ ORDER_OWNER=""
# Option to filter the subgraph query results with a specific order interpreter address
ORDER_INTERPRETER=""

# Type of the Arb contract, can be either of 'flash-loan-v2' or 'flash-loan-v3' or 'order-taker', not availabe for 'srouter' mode since it is a specialized mode
ARB_TYPE="flash-loan-v2"

# Option to maximize profit for 'srouter' mode, comes at the cost of more RPC calls
MAX_PROFIT="true"

# Seconds to wait between each arb round, default is 10, Will override the 'SLEPP' in env variables
SLEEP=10
```
Expand All @@ -192,9 +198,9 @@ const RainArbBot = require("@rainprotocol/arb-bot");
// options (all properties are optional)
const configOptions = {
zeroExApiKey : "...", // required for '0x' mode
useZeroexArb : false, // option to use old zeroex arb contract
monthlyRatelimit : 1000000, // 0x monthly rate limit, only used for 0x mode
hideSensitiveData : true, // set to true to hide sensitive data such as wallet private key or rpc url from apearing in logs
maxProfit : true, // option to maximize profit for 'srouter' mode
liquidityProviders : [ // list of liquidity providers for "router" mode to get quotes from (optional)
"sushiswapv2",
"uniswapv2"
Expand All @@ -206,7 +212,7 @@ const clearOptions = {
}

// to get the configuration object
const config = await RainArbBot.getConfig(rpcUrl, walletPrivateKey, orderbookAddress, arbAddress, ...[configOptions]);
const config = await RainArbBot.getConfig(rpcUrl, walletPrivateKey, orderbookAddress, arbAddress, arbType, ...[configOptions]);

// to get the order details, one or both of subgraph and json file can be used simultaneously
const ordersJson = "/home/orders.json" // path to a local json file
Expand All @@ -221,7 +227,7 @@ const sgFilters = { // fil
const orderDetails = await RainArbBot.getOrderDetails(subgraphs, ordersJson, config.signer, sgFilters);

// to run the clearing process and get the report object which holds the report of cleared orders
const mode = "router" // mode can be one of "router", "0x" or "curve"
const mode = "srouter" // mode can be one of "router", "0x" or "curve" or "srouter"
const reports = await RainArbBot.clear(mode, config, orderDetails, ...[clearOptions])
```
<br>
Expand Down
35 changes: 24 additions & 11 deletions arb-bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const { getOrderDetails, clear, getConfig } = require("./src");
*/
const DEFAULT_OPTIONS = {
key : process?.env?.BOT_WALLET_PRIVATEKEY,
rpc : process?.env?.RPC_URL,
mode : process?.env?.MODE,
arbAddress : process?.env?.ARB_ADDRESS,
arbType : process?.env?.ARB_TYPE,
orderbookAddress : process?.env?.ORDERBOOK_ADDRESS,
orders : process?.env?.ORDERS,
apiKey : process?.env?.API_KEY,
Expand All @@ -26,23 +26,25 @@ const DEFAULT_OPTIONS = {
orderInterpreter : process?.env?.ORDER_INTERPRETER,
monthlyRatelimit : process?.env?.MONTHLY_RATELIMIT,
sleep : process?.env?.SLEEP,
maxProfit : process?.env?.MAX_PROFIT?.toLowerCase() === "true" ? true : false,
rpc : process?.env?.RPC_URL
? Array.from(process?.env?.RPC_URL.matchAll(/[^,\s]+/g)).map(v => v[0])
: undefined,
subgraph : process?.env?.SUBGRAPH
? Array.from(process?.env?.SUBGRAPH.matchAll(/[^,\s]+/g)).map(v => v[0])
: undefined,
useZeroexArb : process?.env?.USE_ZEROEX_ARB?.toLowerCase() === "true"
? true
: false
: undefined
};

const getOptions = async argv => {
const cmdOptions = new Command("node arb-bot")
.option("-k, --key <private-key>", "Private key of wallet that performs the transactions. Will override the 'BOT_WALLET_PRIVATEKEY' in env variables")
.option("-r, --rpc <url>", "RPC URL that will be provider for interacting with evm. Will override the 'RPC_URL' in env variables")
.option("-m, --mode <string>", "Running mode of the bot, must be one of: `0x` or `curve` or `router`, Will override the 'MODE' in env variables")
.option("-r, --rpc <url...>", "RPC URL(s) that will be provider for interacting with evm, use different providers if more than 1 is specified to prevent banning. Will override the 'RPC_URL' in env variables")
.option("-m, --mode <string>", "Running mode of the bot, must be one of: `0x` or `curve` or `router` or `srouter`, Will override the 'MODE' in env variables")
.option("-o, --orders <path>", "The path to a local json file containing the orders details, can be used in combination with --subgraph, Will override the 'ORDERS' in env variables")
.option("-s, --subgraph <url...>", "Subgraph URL(s) to read orders details from, can be used in combination with --orders, Will override the 'SUBGRAPH' in env variables")
.option("--orderbook-address <address>", "Address of the deployed orderbook contract, Will override the 'ORDERBOOK_ADDRESS' in env variables")
.option("--arb-address <address>", "Address of the deployed arb contract, Will override the 'ARB_ADDRESS' in env variables")
.option("--arb-contract-type <string>", "Type of the Arb contract, can be either of `flash-loan-v2` or `flash-loan-v3` or `order-taker`, not availabe for `srouter` mode since it is a specialized mode, Will override the 'ARB_TYPE' in env variables")
.option("-l, --lps <string>", "List of liquidity providers (dex) to use by the router as one quoted string seperated by a comma for each, example: 'SushiSwapV2,UniswapV3', Will override the 'LIQUIDITY_PROVIDERS' in env variables, if unset will use all available liquidty providers")
.option("-a, --api-key <key>", "0x API key, can be set in env variables, Will override the 'API_KEY' env variable")
.option("-g, --gas-coverage <integer>", "The percentage of gas to cover to be considered profitable for the transaction to be submitted, an integer greater than equal 0, default is 100 meaning full coverage, Will override the 'GAS_COVER' in env variables")
Expand All @@ -52,7 +54,7 @@ const getOptions = async argv => {
.option("--order-interpreter <address>", "Option to filter the subgraph query results with a specific order's interpreter address, Will override the 'ORDER_INTERPRETER' in env variables")
.option("--monthly-ratelimit <integer>", "0x monthly rate limit, if not specified will not respect any 0x monthly ratelimit, Will override the 'MONTHLY_RATELIMIT' in env variables")
.option("--sleep <integer>", "Seconds to wait between each arb round, default is 10, Will override the 'SLEPP' in env variables")
.option("--use-zeroex-arb", "Option to use old version of Arb contract for `0x` mode, i.e dedicated 0x Arb contract, ONLY available for `0x` mode")
.option("--max-profit", "Option to maximize profit for 'srouter' mode, comes at the cost of more RPC calls, Will override the 'MAX_PROFIT' 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.",
"- Use \"node arb-bot [options]\" command alias for running the app from its repository workspace",
Expand All @@ -67,19 +69,20 @@ const getOptions = async argv => {
cmdOptions.rpc = cmdOptions.rpc || DEFAULT_OPTIONS.rpc;
cmdOptions.mode = cmdOptions.mode || DEFAULT_OPTIONS.mode;
cmdOptions.arbAddress = cmdOptions.arbAddress || DEFAULT_OPTIONS.arbAddress;
cmdOptions.arbType = cmdOptions.arbType || DEFAULT_OPTIONS.arbType;
cmdOptions.orderbookAddress = cmdOptions.orderbookAddress || DEFAULT_OPTIONS.orderbookAddress;
cmdOptions.orders = cmdOptions.orders || DEFAULT_OPTIONS.orders;
cmdOptions.subgraph = cmdOptions.subgraph || DEFAULT_OPTIONS.subgraph;
cmdOptions.apiKey = cmdOptions.apiKey || DEFAULT_OPTIONS.apiKey;
cmdOptions.lps = cmdOptions.lps || DEFAULT_OPTIONS.lps;
cmdOptions.gasCoverage = cmdOptions.gasCoverage || DEFAULT_OPTIONS.gasCoverage;
cmdOptions.repetitions = cmdOptions.repetitions || DEFAULT_OPTIONS.repetitions;
cmdOptions.useZeroexArb = cmdOptions.useZeroexArb || DEFAULT_OPTIONS.useZeroexArb;
cmdOptions.orderHash = cmdOptions.orderHash || DEFAULT_OPTIONS.orderHash;
cmdOptions.orderOwner = cmdOptions.orderOwner || DEFAULT_OPTIONS.orderOwner;
cmdOptions.sleep = cmdOptions.sleep || DEFAULT_OPTIONS.sleep;
cmdOptions.orderInterpreter = cmdOptions.orderInterpreter || DEFAULT_OPTIONS.orderInterpreter;
cmdOptions.monthlyRatelimit = cmdOptions.monthlyRatelimit || DEFAULT_OPTIONS.monthlyRatelimit;
cmdOptions.maxProfit = cmdOptions.maxProfit || DEFAULT_OPTIONS.maxProfit;

return cmdOptions;
};
Expand All @@ -97,10 +100,11 @@ const arbRound = async options => {
options.key,
options.orderbookAddress,
options.arbAddress,
options.arbType,
{
zeroExApiKey : options.apiKey,
useZeroexArb : options.useZeroexArb,
monthlyRatelimit : options.monthlyRatelimit,
maxProfit : options.maxProfit,
hideSensitiveData : false,
shortenLargeLogs : false,
liquidityProviders : options.lps
Expand Down Expand Up @@ -131,7 +135,10 @@ const arbRound = async options => {
const main = async argv => {
let repetitions = -1;
const options = await getOptions(argv);
if (!options.rpc) throw "undefined RPC URL";
const rpcs = [...options.rpc];
let roundGap = 10000;
let rpcTurn = 0;

if (options.repetitions) {
if (/^\d+$/.test(options.repetitions)) repetitions = Number(options.repetitions);
Expand All @@ -144,13 +151,14 @@ const main = async argv => {

appGlobalLogger(
true,
options.rpc,
...rpcs,
options.key,
options.apiKey
);

// eslint-disable-next-line no-constant-condition
if (repetitions === -1) while (true) {
options.rpc = rpcs[rpcTurn];
try {
await arbRound(options);
console.log("\x1b[32m%s\x1b[0m", "Round finished successfully!");
Expand All @@ -160,9 +168,12 @@ const main = async argv => {
console.log("\x1b[31m%s\x1b[0m", "An error occured during the round: ");
console.log(error);
}
if (rpcTurn === rpcs.length - 1) rpcTurn = 0;
else rpcTurn++;
await sleep(roundGap);
}
else for (let i = 1; i <= repetitions; i++) {
options.rpc = rpcs[rpcTurn];
try {
await arbRound(options);
console.log("\x1b[32m%s\x1b[0m", `Round ${i} finished successfully!`);
Expand All @@ -174,6 +185,8 @@ const main = async argv => {
console.log("\x1b[31m%s\x1b[0m", `An error occured during round ${i}:`);
console.log(error);
}
if (rpcTurn === rpcs.length - 1) rpcTurn = 0;
else rpcTurn++;
await sleep(roundGap);
}
};
Expand Down
Loading

0 comments on commit 517caa6

Please sign in to comment.