From 50f9ca3d43020ad5025bc1fed13e2c00a94286e0 Mon Sep 17 00:00:00 2001 From: rouzwelt Date: Wed, 29 Jan 2025 16:53:09 +0000 Subject: [PATCH] update --- src/config.ts | 77 +++++++++++++++++++++++++++++++++++++ src/modes/interOrderbook.ts | 44 ++++++++------------- src/modes/intraOrderbook.ts | 74 +++++++++++++++-------------------- src/modes/routeProcessor.ts | 44 ++++++++------------- 4 files changed, 140 insertions(+), 99 deletions(-) diff --git a/src/config.ts b/src/config.ts index c5ab5a2..63f383e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -220,6 +220,83 @@ 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`; +} + /** * List of L2 chains that require SEPARATE L1 gas actions. * other L2 chains that dont require separate L1 gas actions diff --git a/src/modes/interOrderbook.ts b/src/modes/interOrderbook.ts index d4812a4..189bacc 100644 --- a/src/modes/interOrderbook.ts +++ b/src/modes/interOrderbook.ts @@ -3,7 +3,7 @@ import { estimateGasCost } from "../gas"; import { BaseError, PublicClient } from "viem"; import { BigNumber, Contract, ethers } from "ethers"; import { containsNodeError, errorSnapshot } from "../error"; -import { getBountyEnsureRainlang, parseRainlang } from "../config"; +import { getBountyEnsureBytecode } from "../config"; import { BotConfig, BundledOrders, ViemClient, DryrunResult, SpanAttrs } from "../types"; import { ONE18, @@ -93,15 +93,11 @@ export async function dryrun({ bytecode: config.gasCoveragePercentage === "0" ? "0x" - : await parseRainlang( - await getBountyEnsureRainlang( - ethers.utils.parseUnits(inputToEthPrice), - ethers.utils.parseUnits(outputToEthPrice), - ethers.constants.Zero, - signer.account.address, - ), - config.viemClient, - config.dispair, + : getBountyEnsureBytecode( + ethers.utils.parseUnits(inputToEthPrice), + ethers.utils.parseUnits(outputToEthPrice), + ethers.constants.Zero, + signer.account.address, ), }, signedContext: [], @@ -153,15 +149,11 @@ 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 = await parseRainlang( - await getBountyEnsureRainlang( - ethers.utils.parseUnits(inputToEthPrice), - ethers.utils.parseUnits(outputToEthPrice), - gasCost.mul(headroom).div("100"), - signer.account.address, - ), - config.viemClient, - config.dispair, + task.evaluable.bytecode = getBountyEnsureBytecode( + ethers.utils.parseUnits(inputToEthPrice), + ethers.utils.parseUnits(outputToEthPrice), + gasCost.mul(headroom).div("100"), + signer.account.address, ); rawtx.data = arb.interface.encodeFunctionData("arb3", [ orderPairObject.orderbook, @@ -177,15 +169,11 @@ export async function dryrun({ .div(100); rawtx.gas = gasLimit.toBigInt(); gasCost = gasLimit.mul(gasPrice).add(estimation.l1Cost); - 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, + task.evaluable.bytecode = getBountyEnsureBytecode( + ethers.utils.parseUnits(inputToEthPrice), + ethers.utils.parseUnits(outputToEthPrice), + gasCost.mul(config.gasCoveragePercentage).div("100"), + signer.account.address, ); rawtx.data = arb.interface.encodeFunctionData("arb3", [ orderPairObject.orderbook, diff --git a/src/modes/intraOrderbook.ts b/src/modes/intraOrderbook.ts index 62c4bea..6602e55 100644 --- a/src/modes/intraOrderbook.ts +++ b/src/modes/intraOrderbook.ts @@ -3,7 +3,7 @@ import { estimateGasCost } from "../gas"; import { BigNumber, ethers } from "ethers"; import { BaseError, erc20Abi, PublicClient } from "viem"; import { containsNodeError, errorSnapshot } from "../error"; -import { getWithdrawEnsureRainlang, parseRainlang } from "../config"; +import { getWithdrawEnsureBytecode } from "../config"; import { estimateProfit, scale18, withBigintSerializer } from "../utils"; import { SpanAttrs, @@ -56,20 +56,16 @@ export async function dryrun({ evaluable: { interpreter: config.dispair.interpreter, store: config.dispair.store, - bytecode: await parseRainlang( - await getWithdrawEnsureRainlang( - signer.account.address, - orderPairObject.buyToken, - orderPairObject.sellToken, - inputBalance, - outputBalance, - ethers.utils.parseUnits(inputToEthPrice), - ethers.utils.parseUnits(outputToEthPrice), - ethers.constants.Zero, - signer.account.address, - ), - config.viemClient, - config.dispair, + bytecode: getWithdrawEnsureBytecode( + signer.account.address, + orderPairObject.buyToken, + orderPairObject.sellToken, + inputBalance, + outputBalance, + ethers.utils.parseUnits(inputToEthPrice), + ethers.utils.parseUnits(outputToEthPrice), + ethers.constants.Zero, + signer.account.address, ), }, signedContext: [], @@ -146,20 +142,16 @@ 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 = await parseRainlang( - await getWithdrawEnsureRainlang( - signer.account.address, - orderPairObject.buyToken, - orderPairObject.sellToken, - inputBalance, - outputBalance, - ethers.utils.parseUnits(inputToEthPrice), - ethers.utils.parseUnits(outputToEthPrice), - gasCost.mul(headroom).div("100"), - signer.account.address, - ), - config.viemClient, - config.dispair, + task.evaluable.bytecode = getWithdrawEnsureBytecode( + signer.account.address, + orderPairObject.buyToken, + orderPairObject.sellToken, + inputBalance, + outputBalance, + ethers.utils.parseUnits(inputToEthPrice), + ethers.utils.parseUnits(outputToEthPrice), + gasCost.mul(headroom).div("100"), + signer.account.address, ); withdrawOutputCalldata = obInterface.encodeFunctionData("withdraw2", [ orderPairObject.sellToken, @@ -179,20 +171,16 @@ export async function dryrun({ .div(100); rawtx.gas = gasLimit.toBigInt(); gasCost = gasLimit.mul(gasPrice).add(estimation.l1Cost); - task.evaluable.bytecode = await parseRainlang( - await getWithdrawEnsureRainlang( - signer.account.address, - orderPairObject.buyToken, - orderPairObject.sellToken, - inputBalance, - outputBalance, - ethers.utils.parseUnits(inputToEthPrice), - ethers.utils.parseUnits(outputToEthPrice), - gasCost.mul(config.gasCoveragePercentage).div("100"), - signer.account.address, - ), - config.viemClient, - config.dispair, + task.evaluable.bytecode = getWithdrawEnsureBytecode( + signer.account.address, + orderPairObject.buyToken, + orderPairObject.sellToken, + inputBalance, + outputBalance, + ethers.utils.parseUnits(inputToEthPrice), + ethers.utils.parseUnits(outputToEthPrice), + gasCost.mul(config.gasCoveragePercentage).div("100"), + signer.account.address, ); withdrawOutputCalldata = obInterface.encodeFunctionData("withdraw2", [ orderPairObject.sellToken, diff --git a/src/modes/routeProcessor.ts b/src/modes/routeProcessor.ts index 515d075..1da0227 100644 --- a/src/modes/routeProcessor.ts +++ b/src/modes/routeProcessor.ts @@ -4,7 +4,7 @@ import { BaseError, PublicClient } from "viem"; import { ChainId, DataFetcher, Router } from "sushi"; import { BigNumber, Contract, ethers } from "ethers"; import { containsNodeError, errorSnapshot } from "../error"; -import { getBountyEnsureRainlang, parseRainlang } from "../config"; +import { getBountyEnsureBytecode } from "../config"; import { SpanAttrs, BotConfig, ViemClient, DryrunResult, BundledOrders } from "../types"; import { ONE18, @@ -155,15 +155,11 @@ export async function dryrun({ bytecode: config.gasCoveragePercentage === "0" ? "0x" - : await parseRainlang( - await getBountyEnsureRainlang( - ethers.utils.parseUnits(ethPrice), - ethers.constants.Zero, - ethers.constants.Zero, - signer.account.address, - ), - config.viemClient, - config.dispair, + : getBountyEnsureBytecode( + ethers.utils.parseUnits(ethPrice), + ethers.constants.Zero, + ethers.constants.Zero, + signer.account.address, ), }, signedContext: [], @@ -219,15 +215,11 @@ 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 = await parseRainlang( - await getBountyEnsureRainlang( - ethers.utils.parseUnits(ethPrice), - ethers.constants.Zero, - gasCost.mul(headroom).div("100"), - signer.account.address, - ), - config.viemClient, - config.dispair, + task.evaluable.bytecode = getBountyEnsureBytecode( + ethers.utils.parseUnits(ethPrice), + ethers.constants.Zero, + gasCost.mul(headroom).div("100"), + signer.account.address, ); rawtx.data = arb.interface.encodeFunctionData("arb3", [ orderPairObject.orderbook, @@ -243,15 +235,11 @@ export async function dryrun({ .div(100); rawtx.gas = gasLimit.toBigInt(); gasCost = gasLimit.mul(gasPrice).add(estimation.l1Cost); - task.evaluable.bytecode = await parseRainlang( - await getBountyEnsureRainlang( - ethers.utils.parseUnits(ethPrice), - ethers.constants.Zero, - gasCost.mul(config.gasCoveragePercentage).div("100"), - signer.account.address, - ), - config.viemClient, - config.dispair, + task.evaluable.bytecode = getBountyEnsureBytecode( + ethers.utils.parseUnits(ethPrice), + ethers.constants.Zero, + gasCost.mul(config.gasCoveragePercentage).div("100"), + signer.account.address, ); rawtx.data = arb.interface.encodeFunctionData("arb3", [ orderPairObject.orderbook,