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

dotrain tasks #290

Merged
merged 8 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ The app requires these arguments (all arguments can be set in env variables alte
- `--arb-address`, Address of the deployed arb contract, Will override the 'ARB_ADDRESS' in env variables
- `--bot-min-balance` The minimum gas token balance the bot wallet must have. Will override the 'BOT_MIN_BALANCE' in env variables
- `-s` or `--subgraph`, Subgraph URL(s) to read orders details from, can be used in combination with --orders, Will override the 'SUBGRAPH' in env variables
- `--dispair`, Addresses of dispair to use for tasks, in order of interpreter, store, deployer, Will override the 'DISPAIR' in env variables

Other optional arguments are:
- `--generic-arb-address`, Address of the deployed generic arb contract to perform inter-orderbook clears, Will override the 'GENERIC_ARB_ADDRESS' in env variables
Expand Down Expand Up @@ -271,6 +272,9 @@ TX_GAS=

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

# Addresses of dispair to use for tasks, in order of interpreter, store, deployer
DISPAIR="address1,address2,address3"
```
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 @@ -97,6 +97,9 @@ TX_GAS=
# Only clear orders through RP4, excludes intra and inter orderbook clears
RP_ONLY="true"

# Addresses of dispair to use for tasks, in order of interpreter, store, deployer
DISPAIR="address1,address2,address3"


# test rpcs vars
TEST_POLYGON_RPC=
Expand Down
41 changes: 40 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@opentelemetry/resources": "^1.22.0",
"@opentelemetry/sdk-trace-base": "^1.22.0",
"@opentelemetry/semantic-conventions": "^1.22.0",
"@rainlanguage/dotrain": "^6.0.1-alpha.21",
"@rainlanguage/orderbook": "^0.0.1-alpha.1",
"axios": "^1.3.4",
"commander": "^11.0.0",
Expand All @@ -67,9 +68,9 @@
"@typescript-eslint/parser": "^5.42.0",
"chai": "^4.3.6",
"copyfiles": "^2.4.1",
"eslint": "^8.26.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.1",
"eslint": "^8.26.0",
"hardhat": "^2.17.8",
"hardhat-contract-sizer": "^2.1.1",
"hardhat-gas-reporter": "^1.0.4",
Expand All @@ -78,8 +79,8 @@
"jsdoc-to-markdown": "^7.1.1",
"mocha": "^10.1.0",
"mockttp": "^3.12.0",
"rimraf": "^5.0.0",
"prettier": "^3.1.1",
"rimraf": "^5.0.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
}
Expand Down
7 changes: 7 additions & 0 deletions src/abis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ export const routeProcessor3Abi = [
`function processRoute(address tokenIn, uint256 amountIn, address tokenOut, uint256 amountOutMin ,address to, bytes memory route) external payable returns (uint256 amountOut)`,
] as const;

/**
* ExpressionDeployerNPE2 minimal ABI
*/
export const deployerAbi = [
"function parse2(bytes memory data) external view returns (bytes memory bytecode)",
] as const;

/**
* Minimal ABI for Arb contract
*/
Expand Down
26 changes: 26 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { config } from "dotenv";
import { isAddress } from "viem";
import { Command } from "commander";
import { getMetaInfo } from "./config";
import { BigNumber, ethers } from "ethers";
Expand Down Expand Up @@ -85,6 +86,9 @@ const ENV_OPTIONS = {
subgraph: process?.env?.SUBGRAPH
? Array.from(process?.env?.SUBGRAPH.matchAll(/[^,\s]+/g)).map((v) => v[0])
: undefined,
dispair: process?.env?.DISPAIR
? Array.from(process?.env?.DISPAIR.matchAll(/[^,\s]+/g)).map((v) => v[0])
: undefined,
};

const getOptions = async (argv: any, version?: string) => {
Expand Down Expand Up @@ -117,6 +121,10 @@ const getOptions = async (argv: any, version?: string) => {
"--generic-arb-address <address>",
"Address of the deployed generic arb contract to perform inter-orderbook clears, Will override the 'GENERIC_ARB_ADDRESS' in env variables",
)
.option(
"--dispair <address...>",
"Addresses of dispair to use for tasks, in order of interpreter, store, deployer, Will override the 'DISPAIR' 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",
Expand Down Expand Up @@ -252,6 +260,7 @@ const getOptions = async (argv: any, version?: string) => {
cmdOptions.route = cmdOptions.route || getEnv(ENV_OPTIONS.route);
cmdOptions.publicRpc = cmdOptions.publicRpc || getEnv(ENV_OPTIONS.publicRpc);
cmdOptions.rpOnly = cmdOptions.rpOnly || getEnv(ENV_OPTIONS.rpOnly);
cmdOptions.dispair = cmdOptions.dispair || getEnv(ENV_OPTIONS.dispair);
if (cmdOptions.ownerProfile) {
const profiles: Record<string, number> = {};
cmdOptions.ownerProfile.forEach((v: string) => {
Expand Down Expand Up @@ -459,6 +468,23 @@ export async function startup(argv: any, version?: string, tracer?: Tracer, ctx?
throw "invalid txGas value, must be an integer greater than zero optionally with appended percentage sign to apply as percentage to original gas";
}
}
if (options.dispair) {
if (
!Array.isArray(options.dispair) ||
options.dispair.length !== 3 ||
!options.dispair.every((v) => typeof v === "string" && isAddress(v, { strict: false }))
) {
throw "expected 3 addresses for dispair, interpreter, store, deployer";
} else {
options.dispair = {
interpreter: options.dispair[0],
store: options.dispair[1],
deployer: options.dispair[2],
};
}
} else {
throw "undefined dispair addresses";
}
const poolUpdateInterval = _poolUpdateInterval * 60 * 1000;
let ordersDetails: SgOrder[] = [];
if (!process?.env?.CLI_STARTUP_TEST) {
Expand Down
80 changes: 1 addition & 79 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BigNumber } from "ethers";
import { getSgOrderbooks } from "./sg";
import { sendTransaction } from "./tx";
import { WNATIVE } from "sushi/currency";
import { ChainId, ChainKey } from "sushi/chain";
import { DataFetcher, LiquidityProviders } from "sushi/router";
Expand Down Expand Up @@ -30,7 +30,6 @@ 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 @@ -220,83 +219,6 @@ export async function getDataFetcher(
}
}

/**
* Get the bounty check ensure task bytecode
* @param inputToEthPrice - Input token to Eth price
* @param outputToEthPrice - Output token to Eth price
* @param minimumExcepted - Minimum expected amount
*/
export function getBountyEnsureBytecode(
inputToEthPrice: BigNumber,
outputToEthPrice: BigNumber,
minimumExcepted: BigNumber,
sender: string,
): string {
const inputPrice = inputToEthPrice.toHexString().substring(2).padStart(64, "0");
const outputPrice = outputToEthPrice.toHexString().substring(2).padStart(64, "0");
const minimum = minimumExcepted.toHexString().substring(2).padStart(64, "0");
const msgSender = sender.substring(2).padStart(64, "0").toLowerCase();
// rainlang bytecode:
// :ensure(equal-to(sender context<0 0>()) \"unknown sender\"),
// :ensure(
// greater-than-or-equal-to(
// add(
// mul(inputToEthPrice context<1 0>())
// mul(outputToEthPrice context<1 1>())
// )
// minimumExcepted
// )
// \"minimum sender output\"
// );
return `0x0000000000000000000000000000000000000000000000000000000000000006${msgSender}8e756e6b6e6f776e2073656e6465720000000000000000000000000000000000${inputPrice}${outputPrice}${minimum}956d696e696d756d2073656e646572206f7574707574000000000000000000000000000000000000000000000000000000000000000000000000000000000047010000100500000110000103100000011000001e1200001d020000011000050110000403100101011000033d12000003100001011000023d1200002b120000211200001d020000`;
}

/**
* Get the bounty check ensure task bytecode for clear2 withdraw
* @param botAddress - Bot wallet address
* @param inputToken - Input token address
* @param outputToken - Output token address
* @param orgInputBalance - Input token original balance
* @param orgOutputBalance - Output token original balance
* @param inputToEthPrice - Input token to Eth price
* @param outputToEthPrice - Output token to Eth price
* @param minimumExcepted - Minimum expected amount
*/
export function getWithdrawEnsureBytecode(
botAddress: string,
inputToken: string,
outputToken: string,
orgInputBalance: BigNumber,
orgOutputBalance: BigNumber,
inputToEthPrice: BigNumber,
outputToEthPrice: BigNumber,
minimumExcepted: BigNumber,
sender: string,
): string {
const bot = botAddress.substring(2).padStart(64, "0");
const input = inputToken.substring(2).padStart(64, "0");
const output = outputToken.substring(2).padStart(64, "0");
const inputBalance = orgInputBalance.toHexString().substring(2).padStart(64, "0");
const outputBalance = orgOutputBalance.toHexString().substring(2).padStart(64, "0");
const inputPrice = inputToEthPrice.toHexString().substring(2).padStart(64, "0");
const outputPrice = outputToEthPrice.toHexString().substring(2).padStart(64, "0");
const minimum = minimumExcepted.toHexString().substring(2).padStart(64, "0");
const msgSender = sender.substring(2).padStart(64, "0").toLowerCase();
// rainlang bytecode:
// :ensure(equal-to(sender context<0 0>()) \"unknown sender\"),
// :ensure(
// greater-than-or-equal-to(
// add(
// mul(sub(erc20-balance-of(inputToken botAddress) originalInputBalance) inputToEthPrice)
// mul(sub(erc20-balance-of(outputToken botAddress) originalOutputBalance) outputToEthPrice)
// )
// minimumSenderOutput
// )
// \"minimumSenderOutput\"
// );
return `0x000000000000000000000000000000000000000000000000000000000000000b${msgSender}8e756e6b6e6f776e2073656e6465720000000000000000000000000000000000${input}${bot}${inputBalance}${inputPrice}${output}${outputBalance}${outputPrice}${minimum}936d696e696d756d53656e6465724f75747075740000000000000000000000000000000000000000000000000000000000000000000000000000000000000067010000180700000110000103100000011000001e1200001d0200000110000a011000090110000801100007011000030110000611120000471200003d1200000110000501100004011000030110000211120000471200003d1200002b120000211200001d020000`;
}

/**
* Get meta info for a bot to post on otel
*/
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export async function getConfig(
config.gasLimitMultiplier = options.gasLimitMultiplier;
config.txGas = options.txGas;
config.rpOnly = options.rpOnly;
config.dispair = options.dispair;

// init accounts
const { mainAccount, accounts } = await initAccounts(walletKey, config, options, tracer, ctx);
Expand Down
48 changes: 30 additions & 18 deletions src/modes/interOrderbook.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { orderbookAbi } from "../abis";
import { BaseError, PublicClient } from "viem";
import { getBountyEnsureBytecode } from "../config";
import { BigNumber, Contract, ethers } from "ethers";
import { containsNodeError, errorSnapshot } from "../error";
import { getBountyEnsureRainlang, parseRainlang } from "../task";
import { estimateProfit, scale18To, withBigintSerializer } from "../utils";
import { BotConfig, BundledOrders, ViemClient, DryrunResult, SpanAttrs } from "../types";

Expand Down Expand Up @@ -81,16 +81,20 @@ export async function dryrun({

const task = {
evaluable: {
interpreter: orderPairObject.takeOrders[0].takeOrder.order.evaluable.interpreter,
store: orderPairObject.takeOrders[0].takeOrder.order.evaluable.store,
interpreter: config.dispair.interpreter,
store: config.dispair.store,
bytecode:
config.gasCoveragePercentage === "0"
? "0x"
: getBountyEnsureBytecode(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
ethers.constants.Zero,
signer.account.address,
: await parseRainlang(
await getBountyEnsureRainlang(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
ethers.constants.Zero,
signer.account.address,
),
config.viemClient,
config.dispair,
),
},
signedContext: [],
Expand Down Expand Up @@ -142,11 +146,15 @@ export async function dryrun({
// sender output which is already called above
if (config.gasCoveragePercentage !== "0") {
const headroom = (Number(config.gasCoveragePercentage) * 1.03).toFixed();
task.evaluable.bytecode = getBountyEnsureBytecode(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
gasCost.mul(headroom).div("100"),
signer.account.address,
task.evaluable.bytecode = await parseRainlang(
await getBountyEnsureRainlang(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
gasCost.mul(headroom).div("100"),
signer.account.address,
),
config.viemClient,
config.dispair,
);
rawtx.data = arb.interface.encodeFunctionData("arb3", [
orderPairObject.orderbook,
Expand All @@ -162,11 +170,15 @@ export async function dryrun({
.div(100);
rawtx.gas = gasLimit.toBigInt();
gasCost = gasLimit.mul(gasPrice);
task.evaluable.bytecode = getBountyEnsureBytecode(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
gasCost.mul(config.gasCoveragePercentage).div("100"),
signer.account.address,
task.evaluable.bytecode = await parseRainlang(
await getBountyEnsureRainlang(
ethers.utils.parseUnits(inputToEthPrice),
ethers.utils.parseUnits(outputToEthPrice),
gasCost.mul(config.gasCoveragePercentage).div("100"),
signer.account.address,
),
config.viemClient,
config.dispair,
);
rawtx.data = arb.interface.encodeFunctionData("arb3", [
orderPairObject.orderbook,
Expand Down
Loading
Loading