Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
rouzwelt committed Dec 2, 2024
1 parent 43bc191 commit 53000b1
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 48 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-namespace": "off",
"semi": [ "error", "always" ],
"prettier/prettier": [
"error",
Expand Down
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 108, ie +8%. 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 105, ie +5%. 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 108, ie +8%
# Option to multiply the gas limit estimation from the rpc as percentage, default is 105, ie +5%
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 108, ie +8%
# Option to multiply the gas limit estimation from the rpc as percentage, default is 105, ie +5%
GAS_LIMIT_MULTIPLIER=

# Option to set a static gas limit for all submitting txs
Expand Down
18 changes: 14 additions & 4 deletions package-lock.json

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

7 changes: 4 additions & 3 deletions 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 Expand Up @@ -61,15 +61,16 @@
"@nomicfoundation/hardhat-viem": "^2.0.2",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-waffle": "2.0.3",
"@types/chai": "^4.2.0",
"@types/mocha": "^10.0.0",
"@types/node": "^18.13.0",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"@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
4 changes: 2 additions & 2 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 108, ie +8%. Will override the 'GAS_LIMIT_MULTIPLIER' in env variables",
"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(
"--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 = 108;
options.gasLimitMultiplier = 105;
}
if (options.txGas) {
if (typeof options.txGas === "number") {
Expand Down
17 changes: 17 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export function getChainConfig(chainId: ChainId): ChainConfig {
nativeWrappedToken,
routeProcessors,
stableTokens,
isL2: L2Chains.is(chain.id),
};
}

Expand Down Expand Up @@ -282,6 +283,22 @@ export function getWithdrawEnsureBytecode(
return `0x0000000000000000000000000000000000000000000000000000000000000009${input}${bot}${inputBalance}${inputPrice}${output}${outputBalance}${outputPrice}${minimum}936d696e696d756d53656e6465724f757470757400000000000000000000000000000000000000000000000000000000000000000000000000000000000000530100001307000001100008011000070110000601100005011000010110000411120000471200003d1200000110000301100002011000010110000011120000471200003d1200002b120000211200001d020000`;
}

/**
* List of L2 chains that require SEPARATE L1 gas actions.
* other L2 chains that dont require separate L1 gas actions
* such as Arbitrum and Polygon zkEvm are excluded, these chains'
* gas actions are performed the same as usual L1 chains.
*/
export enum L2Chains {
BASE = ChainId.BASE,
OPTIMISM = ChainId.OPTIMISM,
}
export namespace L2Chains {
export function is(chainId: number): boolean {
return Object.values(L2Chains).includes(chainId as any);
}
}

/**
* Get meta info for a bot to post on otel
*/
Expand Down
80 changes: 80 additions & 0 deletions src/gas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { BotConfig, RawTx, ViemClient } from "./types";
import { publicActionsL2, walletActionsL2 } from "viem/op-stack";

/**
* Estimates gas cost of the given tx, also takes into account L1 gas cost if operating chain is L2.
* Not all L2 chains need to calculate L1 gas separately, some chains like Arbitrum and Polygon zkEvm,
* dont actually need anything extra other than usual gas estimation and they actually contain L1 gas in
* their usual gas estimation opertaion, but some other L2 chains such as Base and Optimism, do need to
* estimate L1 gas separately, so we will use a try/catch block
*/
export async function estimateGasCost(
tx: RawTx,
signer: ViemClient,
config: BotConfig,
l1GasPrice?: bigint,
l1Signer?: any,
) {
const gasPrice = tx.gasPrice ?? (await signer.getGasPrice());
const gas = await signer.estimateGas(tx);
if (config.isL2) {
try {
const l1Signer_ = l1Signer
? l1Signer
: signer.extend(walletActionsL2()).extend(publicActionsL2());
if (typeof l1GasPrice !== "bigint") {
l1GasPrice = (await l1Signer_.getL1BaseFee()) as bigint;
}
const l1Gas = await l1Signer_.estimateL1Gas({
to: tx.to,
data: tx.data,
});
return {
gas,
gasPrice,
l1Gas,
l1GasPrice,
l1Cost: l1Gas * l1GasPrice,
totalGasCost: gasPrice * gas + l1Gas * l1GasPrice,
};
} catch {
return {
gas,
gasPrice,
l1Gas: 0n,
l1GasPrice: 0n,
l1Cost: 0n,
totalGasCost: gasPrice * gas,
};
}
} else {
return {
gas,
gasPrice,
l1Gas: 0n,
l1GasPrice: 0n,
l1Cost: 0n,
totalGasCost: gasPrice * gas,
};
}
}

/**
* Retruns the L1 gas cost of a transaction if operating chain is L2 else returns 0.
* Not all L2 chains need report the L1 gas separately to the usual transaction receipt, chains
* like Arbitrum and Polygon zkEvm report the tx used gas normally like any other L1 chain, but
* some other L2 chains like Base and Optimism report the L1 gas separately to L2 using the properties
* below, so we need to explicitly check for the, if they are not present in the receipt, then simply
* return 0
*/
export function getL1Fee(receipt: any, config: BotConfig): bigint {
if (!config.isL2) return 0n;

if (typeof receipt.l1Fee === "bigint") {
return receipt.l1Fee;
} else if (typeof receipt.l1GasPrice === "bigint" && typeof receipt.l1GasUsed === "bigint") {
return (receipt.l1GasPrice as bigint) * (receipt.l1GasUsed as bigint);
} else {
return 0n;
}
}
25 changes: 24 additions & 1 deletion src/modes/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { BigNumber, Contract } from "ethers";
import { PublicClient } from "viem";
import { DataFetcher } from "sushi";
import { Token } from "sushi/currency";
import { BigNumber, Contract } from "ethers";
import { findOpp as findInterObOpp } from "./interOrderbook";
import { findOpp as findIntraObOpp } from "./intraOrderbook";
import { publicActionsL2, walletActionsL2 } from "viem/op-stack";
import { findOppWithRetries as findRpOpp } from "./routeProcessor";
import { BotConfig, BundledOrders, ViemClient, DryrunResult, SpanAttrs } from "../types";

Expand Down Expand Up @@ -51,6 +52,22 @@ export async function findOpp({
} catch {
/**/
}

// if chain is L2, get L1 gas price before dryruns
let l1Signer;
let l1GasPrice: bigint | undefined;
if (config.isL2) {
try {
// as already known, not all L2 chains support this method such as Arbitrum,
// only certain ones do, such as Base and Optimism, so use try/catch block
// and set to 0 on catch block so it becomes ineffective
l1Signer = signer.extend(walletActionsL2()).extend(publicActionsL2());
l1GasPrice = await l1Signer.getL1BaseFee();
} catch {
l1GasPrice = 0n;
}
}

const promises = [
findRpOpp({
orderPairObject,
Expand All @@ -63,6 +80,8 @@ export async function findOpp({
ethPrice: inputToEthPrice,
config,
viemClient,
l1GasPrice,
l1Signer,
}),
findIntraObOpp({
orderPairObject,
Expand All @@ -73,6 +92,8 @@ export async function findOpp({
config,
viemClient,
orderbooksOrders,
l1GasPrice,
l1Signer,
}),
findInterObOpp({
orderPairObject,
Expand All @@ -84,6 +105,8 @@ export async function findOpp({
config,
viemClient,
orderbooksOrders,
l1GasPrice,
l1Signer,
}),
];
const allResults = await Promise.allSettled(promises);
Expand Down
Loading

0 comments on commit 53000b1

Please sign in to comment.