Skip to content

Commit

Permalink
Merge pull request #647 from bancorprotocol/pool_finder_period
Browse files Browse the repository at this point in the history
Fix the pool-finder-period handling
  • Loading branch information
platonfloria authored May 14, 2024
2 parents 1881f17 + f8d0839 commit 6b906b5
Show file tree
Hide file tree
Showing 17 changed files with 122 additions and 119 deletions.
10 changes: 3 additions & 7 deletions fastlane_bot/data/abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,8 @@
"type": "function",
"name": "getPair",
"stateMutability": "view",
"constant": True,
"inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}],
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
"payable": False,
"outputs": [{"internalType": "address", "name": "", "type": "address"}]
}
]

Expand Down Expand Up @@ -207,9 +205,9 @@
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}]
},
{
"type": "function",
"name": "getPool",
"stateMutability": "view",
"type": "function",
"inputs": [{"internalType": "address", "name": "tokenA", "type": "address"}, {"internalType": "address", "name": "tokenB", "type": "address"}, {"internalType": "bool", "name": "stable", "type": "bool"}],
"outputs": [{"internalType": "address", "name": "", "type": "address"}],
}
Expand Down Expand Up @@ -256,9 +254,7 @@
"type": "function",
"name": "getPair",
"stateMutability": "view",
"inputs": [{"internalType": "address", "name": "", "type": "address"},
{"internalType": "address", "name": "", "type": "address"},
{"internalType": "bool", "name": "", "type": "bool"}],
"inputs": [{"internalType": "address", "name": "", "type": "address"}, {"internalType": "address", "name": "", "type": "address"}, {"internalType": "bool", "name": "", "type": "bool"}],
"outputs": [{"internalType": "address", "name": "", "type": "address"}]
}
]
Expand Down
8 changes: 2 additions & 6 deletions fastlane_bot/events/exchanges/balancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from web3.contract import Contract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import BALANCER_VAULT_ABI, BALANCER_POOL_ABI_V1
from ..exchanges.base import Exchange
from ..pools.base import Pool
Expand Down Expand Up @@ -90,8 +89,5 @@ async def get_tkn_n(self, address: str, contract: Contract, event: Any, index: i
token_balances = pool_balances[1]
return token_balances[index]

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
"""
This function is unused for Carbon.
"""
raise NotImplementedError
def get_pool_func_call(self, addr1, addr2):
raise NotImplementedError
12 changes: 4 additions & 8 deletions fastlane_bot/events/exchanges/bancor_pol.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from web3.contract import Contract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import BANCOR_POL_ABI
from fastlane_bot import Config
from ..exchanges.base import Exchange
Expand Down Expand Up @@ -52,7 +51,7 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]:
def get_subscriptions(self, contract: Contract) -> List[Subscription]:
return [
Subscription(contract.events.TokenTraded),
Subscription(contract.events.TradingEnabled),
Subscription(contract.events.TradingEnabled, "0xae3f48c001771f8e9868e24d47b9e4295b06b1d78072acf96f167074aa3fab64"),
]

async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]:
Expand All @@ -64,12 +63,6 @@ async def get_tkn0(self, address: str, contract: Contract, event: Event) -> str:
async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str:
return self.ETH_ADDRESS if event.args["token"] not in self.ETH_ADDRESS else self.BNT_ADDRESS

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
"""
This function is unused for Carbon.
"""
raise NotImplementedError

def save_strategy(
self,
token: str,
Expand Down Expand Up @@ -112,3 +105,6 @@ def save_strategy(
cid=cid,
block_number=block_number,
)

def get_pool_func_call(self, addr1, addr2):
raise NotImplementedError
11 changes: 3 additions & 8 deletions fastlane_bot/events/exchanges/bancor_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
Licensed under MIT.
"""
from dataclasses import dataclass
from typing import List, Type, Tuple, Any
from typing import List, Type, Tuple

from web3 import AsyncWeb3
from web3.contract import Contract, AsyncContract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import BANCOR_V2_CONVERTER_ABI
from ..exchanges.base import Exchange
from ..pools.base import Pool
Expand Down Expand Up @@ -79,8 +77,5 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str:
async def get_anchor(self, contract: Contract) -> str:
return await contract.caller.anchor()

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
"""
This function is unused for Carbon.
"""
raise NotImplementedError
def get_pool_func_call(self, addr1, addr2):
raise NotImplementedError
18 changes: 9 additions & 9 deletions fastlane_bot/events/exchanges/bancor_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
Licensed under MIT.
"""
from dataclasses import dataclass
from typing import List, Type, Tuple, Any
from typing import List, Type, Tuple

from web3.contract import Contract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import BANCOR_V3_POOL_COLLECTION_ABI
from ..exchanges.base import Exchange
from ..pools.base import Pool
from ..interfaces.event import Event
from ..interfaces.subscription import Subscription


LIQUIDITY_UPDATED_TOPIC = "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620"
TRADING_LIQUIDITY_UPDATED_TOPIC = "0x6e96dc5343d067ec486a9920e0304c3610ed05c65e45cc029d9b9fe7ecfa7620"
TOTAL_LIQUIDITY_UPDATED_TOPIC = "0x85a03952f50b8c00b32a521c32094023b64ef0b6d4511f423d44c480a62cb145"


@dataclass
Expand All @@ -51,7 +51,10 @@ def get_events(self, contract: Contract) -> List[Type[Contract]]:
return [contract.events.TradingLiquidityUpdated]

def get_subscriptions(self, contract: Contract) -> List[Subscription]:
return [Subscription(contract.events.TradingLiquidityUpdated, LIQUIDITY_UPDATED_TOPIC)]
return [
Subscription(contract.events.TradingLiquidityUpdated, TRADING_LIQUIDITY_UPDATED_TOPIC),
# Subscription(contract.events.TotalLiquidityUpdated, TOTAL_LIQUIDITY_UPDATED_TOPIC), # Unused
]

async def get_fee(self, address: str, contract: Contract) -> Tuple[str, float]:
return "0.000", 0.000
Expand All @@ -66,8 +69,5 @@ async def get_tkn1(self, address: str, contract: Contract, event: Event) -> str:
else event.args["tkn_address"]
)

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
"""
This function is unused for Carbon.
"""
raise NotImplementedError
def get_pool_func_call(self, addr1, addr2):
raise NotImplementedError
6 changes: 1 addition & 5 deletions fastlane_bot/events/exchanges/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from web3.contract import Contract, AsyncContract

from fastlane_bot.config.constants import CARBON_V1_NAME
from fastlane_bot.config.multicaller import MultiCaller
from ..pools.base import Pool
from ..interfaces.subscription import Subscription

Expand Down Expand Up @@ -125,10 +124,7 @@ async def get_fee(address: str, contract: AsyncContract) -> float:
pass

@abstractmethod
def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, *args):
"""
Returns the Factory contract function used to fetch liquidity pools.
"""
def get_pool_func_call(self, addr1, addr2, *args, **kwargs):
...

@staticmethod
Expand Down
8 changes: 2 additions & 6 deletions fastlane_bot/events/exchanges/carbon_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from fastlane_bot import Config
from web3.contract import Contract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import CARBON_CONTROLLER_ABI
from ..exchanges.base import Exchange
from ..pools.base import Pool
Expand Down Expand Up @@ -246,8 +245,5 @@ def save_strategy(
block_number=block_number,
)

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
"""
This function is unused for Carbon.
"""
raise NotImplementedError
def get_pool_func_call(self, addr1, addr2):
raise NotImplementedError
4 changes: 2 additions & 2 deletions fastlane_bot/events/exchanges/solidly_v2/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ..base import Exchange
from .base import SolidlyV2 as SolidlyV2Base
from .velocimeter_v2 import VelocimeterV2
from .equalizer_v2 import EqualizerV2
from .velodrome_v2 import VelodromeV2
Expand All @@ -9,7 +9,7 @@
from .xfai_v0 import XFaiV2


class SolidlyV2(Exchange):
class SolidlyV2(SolidlyV2Base):
def __new__(cls, **kwargs):
return {
"velocimeter_v2": VelocimeterV2,
Expand Down
5 changes: 2 additions & 3 deletions fastlane_bot/events/exchanges/solidly_v2/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

from web3.contract import Contract, AsyncContract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import SOLIDLY_V2_POOL_ABI
from fastlane_bot.events.exchanges.base import Exchange
from ...exchanges.base import Exchange
Expand Down Expand Up @@ -63,8 +62,8 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str:
async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str:
return await contract.caller.token1()

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
mc.add_call(self.factory_contract.functions.getPair, addr1, addr2, True)
def get_pool_func_call(self, addr1, addr2):
return self.factory_contract.functions.getPair(addr1, addr2, False)

@property
@abstractmethod
Expand Down
5 changes: 2 additions & 3 deletions fastlane_bot/events/exchanges/solidly_v2/velodrome_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from web3.contract import AsyncContract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import SOLIDLY_V2_FACTORY_ABI
from .base import SolidlyV2

Expand All @@ -19,5 +18,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo
fee_float = float(fee) / 10 ** 4
return str(fee_float), fee_float

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
mc.add_call(self.factory_contract.functions.getPool, addr1, addr2, True)
def get_pool_func_call(self, addr1, addr2):
return self.factory_contract.functions.getPool(addr1, addr2, False)
5 changes: 2 additions & 3 deletions fastlane_bot/events/exchanges/solidly_v2/xfai_v0.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from web3.contract import Contract, AsyncContract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import XFAI_V0_POOL_ABI, XFAI_V0_FACTORY_ABI
from .base import SolidlyV2

Expand All @@ -30,5 +29,5 @@ async def get_fee(self, address: str, contract: AsyncContract) -> Tuple[str, flo
fee_float = float(fee) / 10 ** 4
return str(fee_float), fee_float

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
mc.add_call(self.factory_contract.functions.getPool, addr1)
def get_pool_func_call(self, addr1, addr2):
return self.factory_contract.functions.getPool(addr1)
5 changes: 2 additions & 3 deletions fastlane_bot/events/exchanges/uniswap_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from web3.contract import Contract, AsyncContract

from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import UNISWAP_V2_POOL_ABI, UNISWAP_V2_FACTORY_ABI
from ..exchanges.base import Exchange
from ..pools.base import Pool
Expand Down Expand Up @@ -64,5 +63,5 @@ async def get_tkn0(address: str, contract: AsyncContract, event: Any) -> str:
async def get_tkn1(address: str, contract: AsyncContract, event: Any) -> str:
return await contract.caller.token1()

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2):
mc.add_call(self.factory_contract.functions.getPair, addr1, addr2)
def get_pool_func_call(self, addr1, addr2):
return self.factory_contract.functions.getPair(addr1, addr2)
7 changes: 3 additions & 4 deletions fastlane_bot/events/exchanges/uniswap_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
from dataclasses import dataclass
from typing import List, Type, Tuple, Any

from web3.contract import Contract, AsyncContract
from web3.contract import Contract

from fastlane_bot.config.constants import AGNI_V3_NAME, PANCAKESWAP_V3_NAME, FUSIONX_V3_NAME, ECHODEX_V3_NAME, SECTA_V3_NAME
from fastlane_bot.config.multicaller import MultiCaller
from fastlane_bot.data.abi import UNISWAP_V3_POOL_ABI, UNISWAP_V3_FACTORY_ABI, PANCAKESWAP_V3_POOL_ABI
from ..exchanges.base import Exchange
from ..pools.base import Pool
Expand Down Expand Up @@ -61,5 +60,5 @@ async def get_tkn0(self, address: str, contract: Contract, event: Any) -> str:
async def get_tkn1(self, address: str, contract: Contract, event: Any) -> str:
return await contract.caller.token1()

def get_pool_with_multicall(self, mc: MultiCaller, addr1, addr2, fee):
mc.add_call(self.factory_contract.functions.getPool, addr1, addr2, fee)
def get_pool_func_call(self, addr1, addr2, fee):
return self.factory_contract.functions.getPool(addr1, addr2, fee)
46 changes: 11 additions & 35 deletions fastlane_bot/pool_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode:
_find_unsupported_pairs, and _find_unsupported_triangles methods.
Returns:
Dict: Returns a dictionary with pools sorted into different exchange types (Uni V2 forks, Uni V3 forks,
Dict: Returns a list of dictionaries with pools sorted into different exchange types (Uni V2 forks, Uni V3 forks,
and Solidly V2 forks), each associated with their specific supporting pools based on the unsupported
configurations identified.
"""
Expand All @@ -73,30 +73,7 @@ def get_pools_for_unsupported_pairs(self, pools: List[Dict[str, Any]], arb_mode:
unsupported_pairs = PoolFinder._find_unsupported_triangles(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs)
else:
unsupported_pairs = PoolFinder._find_unsupported_pairs(self._flashloan_tokens, carbon_pairs=carbon_pairs, external_pairs=other_pairs)
missing_pools = self._find_pools(unsupported_pairs)
return missing_pools[UNISWAP_V2_NAME], missing_pools[UNISWAP_V3_NAME], missing_pools[SOLIDLY_V2_NAME]


def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]:
"""
Collects pool addresses for each exchange, based on a set of unsupported token pairs
and flashloan tokens. The function constructs pairs of tokens from unsupported_pairs with each
flashloan token and retrieves pool data via multicall. It filters out invalid addresses.
Args:
unsupported_pairs (List[Tuple]): A list of tuples, where each tuple contains two token addresses.
flashloan_tokens (List[str]): A list of token addresses available for flashloans.
Returns:
Dict[str, List[str]]: A list of dictionaries, where each dictionary maps an exchange's name
to a list of valid pool addresses (i.e., non-zero addresses) obtained
from the multicall across all generated pairs.
Raises:
Exception: An exception could be raised from the multicall operation depending on the
implementation specifics of the multicall context manager or the exchange's
get_pool_with_multicall method if it encounters a problem.
"""
pairs = [(tkn, token) for pair in unsupported_pairs for tkn in pair for token in self._flashloan_tokens]
chunk_size = 400
# Create the list of chunks
Expand All @@ -105,21 +82,20 @@ def _find_pools(self, unsupported_pairs: List[Tuple]) -> Dict[str, List[str]]:

for exchange in self._exchanges:
for pair_chunk in chunked_pairs:
mc = MultiCaller(contract=exchange.factory_contract, web3=self._web3, multicall_address=self._multicall_address)
mc = MultiCaller(self._web3, self._multicall_address)
for pair in pair_chunk:
if exchange.base_exchange_name in [UNISWAP_V2_NAME, SOLIDLY_V2_NAME]:
exchange.get_pool_with_multicall(mc, pair[0], pair[1])
mc.add_call(exchange.get_pool_func_call(pair[0], pair[1]))
elif exchange.base_exchange_name == UNISWAP_V3_NAME:
for fee in self._uni_v3_fee_tiers[exchange.exchange_name]:
exchange.get_pool_with_multicall(mc, pair[0], pair[1], fee)
response = mc.multicall()
result[exchange.base_exchange_name] = {
mc.web3.to_checksum_address(addr): exchange.exchange_name
for addr
in response
if addr != ZERO_ADDRESS
}
return result
mc.add_call(exchange.get_pool_func_call(pair[0], pair[1], fee))
addresses = mc.run_calls()
result[exchange.base_exchange_name].update({
self._web3.to_checksum_address(address): exchange.exchange_name
for address in addresses if address not in [None, ZERO_ADDRESS]
})

return result[UNISWAP_V2_NAME], result[UNISWAP_V3_NAME], result[SOLIDLY_V2_NAME]


def _extract_pairs(self, pools: List[Dict[str, Any]]) -> Tuple[List, set]:
Expand Down
8 changes: 8 additions & 0 deletions fastlane_bot/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import pytest

from fastlane_bot import Config


@pytest.fixture
def config():
return Config.new(config=Config.CONFIG_MAINNET)
Loading

0 comments on commit 6b906b5

Please sign in to comment.