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

Add sei #606

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export ETH_PRIVATE_KEY_BE_CAREFUL="0x123-USE-YOUR-OWN-PRIVATE-KEY-HERE"
export WEB3_FANTOM="FANTOM-API-KEY-HERE" // "public" can be used in place of a paid API key
export WEB3_MANTLE="MANTLE-API-KEY-HERE"
export WEB3_LINEA="LINEA-API-KEY-HERE" //
export WEB3_SEI="SEI-API-KEY-HERE" //

#******** For Development - not required to run bot ********#
export ETHERSCAN_TOKEN="ONLY_REQUIRED_IN_DEV"
Expand Down
2 changes: 1 addition & 1 deletion fastlane_bot/config/multicaller.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class MultiCaller(ContextManager):

def __init__(self, contract: web3.contract.Contract,
web3: Web3,
block_identifier: Any = 'latest', multicall_address = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696"):
block_identifier: Any = 'latest', multicall_address = "0xcA11bde05977b3631167028862bE2a173976CA11"):
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this address and why was it changed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's replace with MULTICALL_CONTRACT_ADDRESS

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MULTICALL_CONTRACT_ADDRESS constant is currently defined separately per network.
We can move it to global scope, but it will be a drop in the ocean, so no point investing too much effort into this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@barakman please make sure it's the right move to replace the default

Copy link
Collaborator

@barakman barakman May 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified (the only place where this default value is used is in test 899).
Ideally it should be removed, but since there's a default-value argument which appears before this argument, removing the default value of this argument would require removing the default value of the other argument, or replacing the order in which they are passed to the function (which would subsequently require more changes in other files).

self._contract_calls: List[Callable] = []
self.contract = contract
self.block_identifier = block_identifier
Expand Down
45 changes: 42 additions & 3 deletions fastlane_bot/config/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ class ConfigNetwork(ConfigBase):
NETWORK_FANTOM = S.NETWORK_FANTOM
NETWORK_MANTLE = S.NETWORK_MANTLE
NETWORK_LINEA = S.NETWORK_LINEA
NETWORK_SEI = S.NETWORK_SEI

# FLAGS
#######################################################################################
Expand Down Expand Up @@ -317,7 +318,9 @@ def new(cls, network=None):
elif network == cls.NETWORK_MANTLE:
return _ConfigNetworkMantle(_direct=False)
elif network == cls.NETWORK_LINEA:
return _ConfigNetworkLinea(_direct=False)
return _ConfigNetworkLinea(_direct=False)
elif network == cls.NETWORK_SEI:
return _ConfigNetworkSei(_direct=False)
elif network == cls.NETWORK_TENDERLY:
return _ConfigNetworkTenderly(_direct=False)
else:
Expand Down Expand Up @@ -426,7 +429,7 @@ class _ConfigNetworkMainnet(ConfigNetwork):
RPC_ENDPOINT = "https://eth-mainnet.alchemyapi.io/v2/"
WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_ALCHEMY_PROJECT_ID")

MULTICALL_CONTRACT_ADDRESS = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696"
MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"
# NATIVE_GAS_TOKEN_KEY = "ETH-EEeE"
# WRAPPED_GAS_TOKEN_KEY = "WETH-6Cc2"
# STABLECOIN_KEY = "USDC-eB48"
Expand Down Expand Up @@ -777,6 +780,42 @@ class _ConfigNetworkLinea(ConfigNetwork):
# Add any exchanges unique to the chain here
CHAIN_SPECIFIC_EXCHANGES = []

class _ConfigNetworkSei(ConfigNetwork):
"""
Fastlane bot config -- network [Base Mainnet]
"""

NETWORK = S.NETWORK_SEI
NETWORK_ID = "1" # TODO
Copy link
Contributor

@zavelevsky zavelevsky May 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clear TODO

NETWORK_NAME = "sei"
DEFAULT_PROVIDER = S.PROVIDER_ALCHEMY
RPC_ENDPOINT = "https://evm-rpc.arctic-1.seinetwork.io/" # TODO currently Sei devnet
WEB3_ALCHEMY_PROJECT_ID = os.environ.get("WEB3_SEI")

network_df = get_multichain_addresses(network=NETWORK_NAME)
FASTLANE_CONTRACT_ADDRESS = "0xC7Dd38e64822108446872c5C2105308058c5C55C" #TODO - UPDATE WITH Mainnet
MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"

CARBON_CONTROLLER_ADDRESS = "0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA" #TODO - UPDATE WITH Mainnet
CARBON_CONTROLLER_VOUCHER = "0xe4816658ad10bF215053C533cceAe3f59e1f1087" #TODO - UPDATE WITH Mainnet

NATIVE_GAS_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
WRAPPED_GAS_TOKEN_ADDRESS = "0x57eE725BEeB991c70c53f9642f36755EC6eb2139" # TODO confirm for Mainnet
NATIVE_GAS_TOKEN_SYMBOL = "SEI"
WRAPPED_GAS_TOKEN_SYMBOL = "WSEI"
STABLECOIN_ADDRESS = "0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C" #TODO USDC on devnet

IS_INJECT_POA_MIDDLEWARE = False
# Balancer
BALANCER_VAULT_ADDRESS = "0x7ccBebeb88696f9c8b061f1112Bb970158e29cA5" # # TODO Jellyswap on devnet

CHAIN_FLASHLOAN_TOKENS = {
"0x57eE725BEeB991c70c53f9642f36755EC6eb2139": "WSEI", #TODO confirm for Mainnet
"0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C": "USDC", #TODO confirm for Mainnet
}
# Add any exchanges unique to the chain here
CHAIN_SPECIFIC_EXCHANGES = []

class _ConfigNetworkTenderly(ConfigNetwork):
"""
Fastlane bot config -- network [Ethereum Tenderly]
Expand Down Expand Up @@ -810,7 +849,7 @@ class _ConfigNetworkTenderly(ConfigNetwork):
FASTLANE_CONTRACT_ADDRESS = "0x41Eeba3355d7D6FF628B7982F3F9D055c39488cB"
CARBON_CONTROLLER_ADDRESS = "0xC537e898CD774e2dCBa3B14Ea6f34C93d5eA45e1"
CARBON_CONTROLLER_VOUCHER = "0x3660F04B79751e31128f6378eAC70807e38f554E"
MULTICALL_CONTRACT_ADDRESS = "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696"
MULTICALL_CONTRACT_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"

# Uniswap
UNISWAP_V2_ROUTER_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
Expand Down
1 change: 1 addition & 0 deletions fastlane_bot/config/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
NETWORK_CANTO = "canto"
NETWORK_FANTOM = "fantom"
NETWORK_LINEA = "linea"
NETWORK_SEI = "sei"
NETWORK_MANTLE = "mantle"
NETWORK_SCROLL = "scroll"
NETWORK_BSC = "binance_smart_chain"
Expand Down
2 changes: 1 addition & 1 deletion fastlane_bot/data/abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@
"type": "function",
"name": "aggregate",
"stateMutability": "view",
"inputs": [{"components": [{"internalType": "address", "name": "target", "type": "address"}, {"internalType": "bytes", "name": "callData", "type": "bytes"}], "internalType": "struct Multicall2.Call[]", "name": "calls", "type": "tuple[]"}],
"inputs": [{"components": [{"internalType": "address", "name": "target", "type": "address"}, {"internalType": "bytes", "name": "callData", "type": "bytes"}], "internalType": "struct Multicall3.Call[]", "name": "calls", "type": "tuple[]"}],
"outputs": [{"internalType": "uint256", "name": "blockNumber", "type": "uint256"}, {"internalType": "bytes[]", "name": "returnData", "type": "bytes[]"}]
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exchange,address
4 changes: 4 additions & 0 deletions fastlane_bot/data/blockchain_data/sei/static_pool_data.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
cid,strategy_id,last_updated,last_updated_block,descr,pair_name,exchange_name,fee,fee_float,address,anchor,tkn0_address,tkn1_address,tkn0_decimals,tkn1_decimals,exchange_id,tkn0_symbol,tkn1_symbol,timestamp,tkn0_balance,tkn1_balance,liquidity,sqrt_price_q96,tick,tick_spacing,exchange,pool_type,tkn0_weight,tkn1_weight,tkn2_address,tkn2_decimals,tkn2_symbol,tkn2_balance,tkn2_weight,tkn3_address,tkn3_decimals,tkn3_symbol,tkn3_balance,tkn3_weight,tkn4_address,tkn4_decimals,tkn4_symbol,tkn4_balance,tkn4_weight,tkn5_address,tkn5_decimals,tkn5_symbol,tkn5_balance,tkn5_weight,tkn6_address,tkn6_decimals,tkn6_symbol,tkn6_balance,tkn6_weight,tkn7_address,tkn7_decimals,tkn7_symbol,tkn7_balance,tkn7_weight
0x1422169ab760ea6994358267b7d3783e8e7fa55c6a74b365b3fd3d17cbf4c6f1,0,,2354,dragonswap 0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0x7b75109369ACb528d9fa989E227812a6589712b9,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0x7b75109369ACb528d9fa989E227812a6589712b9,dragonswap,0.003,0.003,0x01A34Dfa104F020FEE739268679338169945D5B1,,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,0x7b75109369ACb528d9fa989E227812a6589712b9,18,18,3,WSEI,DSWAP,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
0xbfd9612b2cb8035908dff18c040f64de75999cefd1020b5ce8a2e533c2ecd5dc,0,,2354,dragonswap 0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B/0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,dragonswap,0.003,0.003,0x85CB6BFd781e1f42f4E79Efb6bf1F1fEfE4E9732,,0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,18,6,3,WSEI,USDC,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
0xe3aead757d877a15316e4896d5c5ab7639adbcba1ff76e3434b4e0af90f6225e,0,,2354,dragonswap 0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C/0xF983afa393199D6902a1Dd04f8E93465915ffD8B,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C/0xF983afa393199D6902a1Dd04f8E93465915ffD8B,dragonswap,0.003,0.003,0x72A788B0A83e18ce1757171321E82c03e4351498,,0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,0xF983afa393199D6902a1Dd04f8E93465915ffD8B,6,6,3,USDC,USDT,0,0,0,,,,,dragonswap,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
9 changes: 9 additions & 0 deletions fastlane_bot/data/blockchain_data/sei/tokens.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
address,decimals,symbol
0x26841a0A5D958B128209F4ea9a1DD7E61558c330,18,WSEI
0xace5f7Ea93439Af39b46d2748fA1aC19951c8d7C,6,USDC
0x027D2E627209f1cebA52ADc8A5aFE9318459b44B,18,WSEI
0x7b75109369ACb528d9fa989E227812a6589712b9,18,DSWAP
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE,18,SEI
0x9e7A8e558Ce582511f4104465a886b7bEfBC146b,18,JLY
0x57eE725BEeB991c70c53f9642f36755EC6eb2139,18,WSEI
0xF983afa393199D6902a1Dd04f8E93465915ffD8B,6,USDT
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exchange,address
dragonswap,0x01A34Dfa104F020FEE739268679338169945D5B1
dragonswap,0x85CB6BFd781e1f42f4E79Efb6bf1F1fEfE4E9732
dragonswap,0x38BcEBb9A3fbF05B0Ab7ce9b485c9669578409fE
dragonswap,0x72A788B0A83e18ce1757171321E82c03e4351498
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exchange,address
4 changes: 4 additions & 0 deletions fastlane_bot/data/multichain_addresses.csv
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,7 @@ sushiswap_v3,thundercore,uniswap_v3,0xc35DADB65012eC5796536bD9864eD8773aBc74C4,0
pancakeswap_v3,zkevm,uniswap_v3,0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865,0x1b81D678ffb9C0263b24A97847620C99d213eB14,,,
pancakeswap_v3,zksync,uniswap_v3,0x1BB72E0CbbEA93c08f535fc7856E0338D7F7a8aB,0xD70C70AD87aa8D45b8D59600342FB3AEe76E3c68,,,
xfai_v0,linea,solidly_v2,0xa5136eAd459F0E61C99Cec70fe8F5C24cF3ecA26,0xD538be6e9026C13D130C9e17d509E69C8Bb0eF33,,222864,
carbon_v1,sei,carbon_v1,0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA,0x59f21012B2E9BA67ce6a7605E74F945D0D4C84EA,,17658678,
dragonswap,sei,uniswap_v2,0x5D370a6189F89603FaB67e9C68383e63F7B6A262,0x2346d3A6fb18Ff3ae590Ea31d9e41E6AB8c9f5EB,0.003,1008775,
jellyswap,sei,balancer,BALANCER_VAULT_ADDRESS,0x7ccBebeb88696f9c8b061f1112Bb970158e29cA5,0,222832,
uniswap_v3,sei,uniswap_v3,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,,1,
83 changes: 83 additions & 0 deletions fastlane_bot/helpers/poolandtokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,25 @@ def _carbon_to_cpc(self) -> ConstantProductCurve:
allow to omit yint (in which case it is set to y, but this does not make
a difference for the result)
"""
def calculate_parameters(y: Decimal, pa: Decimal, pb: Decimal, pm: Decimal, n: Decimal):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing tests for this functionality - check_overlap and "cleanup" of overlapping strategies

H = pa.sqrt() ** n
L = pb.sqrt() ** n
M = pm.sqrt() ** n
A = H - L
B = L
z = y * (H - L) / (M - L) if M > L else y
return z

def check_overlap(pa0, pb0, pa1, pb1):
min0, max0 = sorted([pa0, pb0])
min1, max1 = sorted([1 / pa1, 1 / pb1])
prices_overlap = max(min0, min1) < min(max0, max1)
return prices_overlap

# if idx == 0, use the first curve, otherwise use the second curve. change the numerical values to Decimal
lst = []
errors = []
strategy_typed_args = []
for i in [0, 1]:

S = Decimal(self.A_1) if i == 0 else Decimal(self.A_0)
Expand Down Expand Up @@ -450,13 +465,19 @@ def decimal_converter(idx):
decimal_converter = decimal_converter(i)

p_start = Decimal(encoded_order.p_start) * decimal_converter
p_marg = Decimal(encoded_order.p_marg) * decimal_converter
p_end = Decimal(encoded_order.p_end) * decimal_converter
yint = Decimal(yint) / (
Decimal("10") ** [self.tkn1_decimals, self.tkn0_decimals][i]
)
y = Decimal(y) / (
Decimal("10") ** [self.tkn1_decimals, self.tkn0_decimals][i]
)
is_limit_order = p_start==p_end

# if (p_marg!=p_start) and (p_marg!=p_end):
# self.ConfigObj.logger.debug(f"[poolandtokens.py, _carbon_to_cpc] p_start, p_marg, p_end:, {p_start, p_marg, p_end}")
# assert (round(p_start,6)<=round(p_marg,6)<=round(p_end,6)) or (round(p_start,6)>=round(p_marg,6)>=round(p_end,6)), f"WARNING {p_start, p_marg, p_end}"

tkny = 1 if i == 0 else 0
typed_args = {
Expand All @@ -466,7 +487,9 @@ def decimal_converter(idx):
"yint": yint,
"y": y,
"pb": p_end,
"p_marg": p_marg, # deleted later since not supported by from_carbon()
"pa": p_start,
"is_limit_order": is_limit_order, # deleted later since not supported by from_carbon()
"tkny": self.pair_name.split("/")[tkny].replace(
self.ConfigObj.NATIVE_GAS_TOKEN_ADDRESS, self.ConfigObj.WRAPPED_GAS_TOKEN_ADDRESS
),
Expand All @@ -476,6 +499,66 @@ def decimal_converter(idx):
"descr": self.descr,
"params": self._params,
}

strategy_typed_args += [typed_args]

#### MODIFICATION LOGIC HERE >>>>>
# Only overlapping strategies are selected for modification
if len(strategy_typed_args) == 2:

is_overlapping = False
pmarg_threshold = Decimal("0.01") # 1% # WARNING using this condition alone can included stable/stable pairs incidently

# evaluate that the marginal prices are within the pmarg_threshold
pmarg0, pmarg1 = [x['p_marg'] for x in strategy_typed_args]
pmarg0_inv = 1/pmarg0 # one of the orders must be flipped since prices are always dy/dx - but must flip same geomean_pmarg later
percent_component = pmarg_threshold * max(pmarg0_inv, pmarg1)
percent_component_met = abs(pmarg0_inv - pmarg1) <= percent_component

# overlapping strategies by defintion cannot have A=0 i.e. there must be no limit orders
no_limit_orders = (strategy_typed_args[0]['is_limit_order'] == False) and (strategy_typed_args[1]['is_limit_order'] == False)

# evaluate if the price boundaries pa/pb overlap at one end # TODO check logic and remove duplicate logic if necessary
prices_overlap = check_overlap(strategy_typed_args[0]['pa'], strategy_typed_args[0]['pb'], strategy_typed_args[1]['pa'], strategy_typed_args[1]['pb'])
# if (percent_component_met and no_limit_orders) and not prices_overlap:
# print(percent_component_met, no_limit_orders, prices_overlap)
# print(strategy_typed_args)

# if the threshold is met and neither is a limit order and prices overlap then likely to be overlapping
is_overlapping = percent_component_met and no_limit_orders and prices_overlap

if is_overlapping:
# print(strategy_typed_args)
# calculate the geometric mean
geomean_p_marg = Decimal.sqrt(pmarg0_inv * pmarg1)
self.ConfigObj.logger.debug(f"[poolandtokens.py, _carbon_to_cpc] These cids are identified as overlapping: {[x['cid'] for x in strategy_typed_args]}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reconsider the verbosity

self.ConfigObj.logger.debug(f"[poolandtokens.py, _carbon_to_cpc] pmarg0_inv, pmarg1, geomean_p_marg: {pmarg0_inv, pmarg1, geomean_p_marg}")

# modify the y_int based on the new geomean to the limit of y #TODO check that this math is correct
typed_args0 = strategy_typed_args[0]
new_yint0 = calculate_parameters(y=typed_args0['y'], pa=typed_args0['pa'], pb=typed_args0['pb'], pm=(1/geomean_p_marg), n=1)
if new_yint0 < typed_args0['y']:
new_yint0 = typed_args0['y']
self.ConfigObj.logger.debug(f"[poolandtokens.py, _carbon_to_cpc] First order: typed_args0['yint'], new_yint0, typed_args0['y']: {typed_args0['yint'], new_yint0, typed_args0['y']}")
typed_args0['yint'] = new_yint0

typed_args1 = strategy_typed_args[1]
new_yint1 = calculate_parameters(y=typed_args1['y'], pa=typed_args1['pa'], pb=typed_args1['pb'], pm=(geomean_p_marg), n=1)
if new_yint1 < typed_args1['y']:
new_yint1 = typed_args1['y']
self.ConfigObj.logger.debug(f"[poolandtokens.py, _carbon_to_cpc] Second order: typed_args1['yint'], new_yint1, typed_args1['y']: {typed_args1['yint'], new_yint1, typed_args1['y']} \n")
typed_args1['yint'] = new_yint1

# repack the strateg_typed_args
strategy_typed_args = [typed_args0, typed_args1]


#### <<<<< MODIFICATION LOGIC HERE

for typed_args in strategy_typed_args:
# delete new args that arent supported by from_carbon()
del typed_args["p_marg"]
del typed_args["is_limit_order"]
try:
if typed_args["y"] > 0:
lst.append(
Expand Down
3 changes: 3 additions & 0 deletions fastlane_bot/tests/test_039_TestMultiMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def test_test_tax_tokens():
# ------------------------------------------------------------

assert any(token.address in cfg.TAX_TOKENS for token in tokens), f"[TestMultiMode], DB does not include any tax tokens"
assert len(CCm) == 516, f"[NBTest 039 TestMultiMode] Expected 516 curves, found {len(CCm)}"

for curve in CCm:
for token in cfg.TAX_TOKENS:
Expand Down Expand Up @@ -178,6 +179,7 @@ def test_test_combos_and_tokens():
# ------------------------------------------------------------

# +
assert len(CCm) == 516, f"[NBTest 039 TestMultiMode] Expected 516 curves, found {len(CCm)}"
arb_finder = bot._get_arb_finder("multi")
finder = arb_finder(
flashloan_tokens=flashloan_tokens,
Expand Down Expand Up @@ -205,6 +207,7 @@ def test_test_expected_output():
# ------------------------------------------------------------

# +
assert len(CCm) == 516, f"[NBTest 039 TestMultiMode] Expected 516 curves, found {len(CCm)}"
arb_finder = bot._get_arb_finder("multi")
finder = arb_finder(
flashloan_tokens=flashloan_tokens,
Expand Down
Loading
Loading