From 7544ef4132512c4856a6c996774647278538c143 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 15 Apr 2024 18:06:10 -0400 Subject: [PATCH] chore: refactor (#171) * chore: refactor * chore: fix args and kwargs type hinting for Contract --- dank_mids/brownie_patch/_abi.py | 23 ++++++ dank_mids/brownie_patch/_method.py | 107 ++++++++++++++++++++++++ dank_mids/brownie_patch/contract.py | 43 ++++++++-- dank_mids/brownie_patch/types.py | 122 +--------------------------- tests/test_brownie_patch.py | 2 +- 5 files changed, 169 insertions(+), 128 deletions(-) create mode 100644 dank_mids/brownie_patch/_abi.py create mode 100644 dank_mids/brownie_patch/_method.py diff --git a/dank_mids/brownie_patch/_abi.py b/dank_mids/brownie_patch/_abi.py new file mode 100644 index 00000000..0327f034 --- /dev/null +++ b/dank_mids/brownie_patch/_abi.py @@ -0,0 +1,23 @@ + +import functools +from typing import Any + +from brownie.convert.utils import build_function_selector, build_function_signature +from web3.datastructures import AttributeDict + + +@functools.lru_cache(maxsize=None) +class FunctionABI: + """A singleton to hold function signatures, since we only really need one copy of each func sig in memory.""" + __slots__ = "abi", "input_sig", "signature" + def __init__(self, **abi: Any): + self.abi = abi + self.input_sig = build_function_signature(abi) + self.signature = build_function_selector(abi) + +def _make_hashable(obj: Any) -> Any: + if isinstance(obj, (list, tuple)): + return tuple((_make_hashable(o) for o in obj)) + elif isinstance(obj, dict): + return AttributeDict({k: _make_hashable(v) for k, v in obj.items()}) + return obj \ No newline at end of file diff --git a/dank_mids/brownie_patch/_method.py b/dank_mids/brownie_patch/_method.py new file mode 100644 index 00000000..b904de58 --- /dev/null +++ b/dank_mids/brownie_patch/_method.py @@ -0,0 +1,107 @@ + +import asyncio +import functools +from decimal import Decimal +from typing import Any, Awaitable, Callable, Dict, Generic, Iterable, List, Optional, TypeVar + +from brownie.typing import AccountsType +from brownie.convert.datatypes import EthAddress +from eth_abi.exceptions import InsufficientDataBytes +from web3 import Web3 + +from dank_mids import ENVIRONMENT_VARIABLES as ENVS +from dank_mids.brownie_patch._abi import FunctionABI, _make_hashable + +_EVMType = TypeVar("_EVMType") + +class _DankMethodMixin(Generic[_EVMType]): + _address: EthAddress + _abi: FunctionABI + """A mixin class that gives brownie objects async support and reduces memory usage""" + __slots__ = "_address", "_abi", "_name", "_owner", "natspec", "_encode_input", "_decode_input" + def __await__(self): + """Asynchronously call the contract method without arguments at the latest block and await the result.""" + return self.coroutine().__await__() + async def map( + self, + args: Iterable[Any], + block_identifier: Optional[int] = None, + decimals: Optional[int] = None, + ) -> List[_EVMType]: + return await asyncio.gather(*[self.coroutine(arg, block_identifier=block_identifier, decimals=decimals) for arg in args]) + @property + def abi(self) -> dict: + return self._abi.abi + @property + def signature(self) -> str: + return self._abi.signature + @property + def _input_sig(self) -> str: + return self._abi.input_sig + @functools.cached_property + def _len_inputs(self) -> int: + return len(self.abi['inputs']) + @functools.cached_property + def _skip_decoder_proc_pool(self) -> bool: + from dank_mids.brownie_patch.call import _skip_proc_pool + return self._address in _skip_proc_pool + @functools.cached_property + def _web3(cls) -> Web3: + from dank_mids import web3 + return web3 + @functools.cached_property + def _prep_request_data(self) -> Callable[..., Awaitable[bytes]]: + from dank_mids.brownie_patch import call + if ENVS.OPERATION_MODE.application or self._len_inputs: + return call.encode + else: + return call._request_data_no_args + +class _DankMethod(_DankMethodMixin): + __slots__ = "_address", "_abi", "_name", "_owner", "natspec", "_encode_input", "_decode_output" + def __init__( + self, + address: str, + abi: Dict, + name: str, + owner: Optional[AccountsType], + natspec: Optional[Dict] = None, + ) -> None: + self._address = address + self._abi = FunctionABI(**{key: _make_hashable(abi[key]) for key in sorted(abi)}) + self._name = name + self._owner = owner + self.natspec = natspec or {} + # TODO: refactor this + from dank_mids.brownie_patch import call + self._encode_input = call.encode_input + self._decode_output = call.decode_output + async def coroutine( # type: ignore [empty-body] + self, + *args: Any, + block_identifier: Optional[int] = None, + decimals: Optional[int] = None, + override: Optional[Dict[str, str]] = None, + ) -> _EVMType: + """ + Asynchronously call the contract method via dank mids and await the result. + + Arguments: + - *args: The arguments for the contract method. + - block_identifier (optional): The block at which the chain will be read. If not provided, will read the chain at latest block. + - decimals (optional): if provided, the output will be `result / 10 ** decimals` + + Returns: + - Whatever the node sends back as the output for this contract method. + """ + if override: + raise ValueError("Cannot use state override with `coroutine`.") + async with ENVS.BROWNIE_ENCODER_SEMAPHORE[block_identifier]: + data = await self._encode_input(self, self._len_inputs, self._prep_request_data, *args) + async with ENVS.BROWNIE_CALL_SEMAPHORE[block_identifier]: + output = await self._web3.eth.call({"to": self._address, "data": data}, block_identifier) + try: + decoded = await self._decode_output(self, output) + except InsufficientDataBytes as e: + raise InsufficientDataBytes(str(e), self, self._address, output) from e + return decoded if decimals is None else decoded / 10 ** Decimal(decimals) \ No newline at end of file diff --git a/dank_mids/brownie_patch/contract.py b/dank_mids/brownie_patch/contract.py index d11e5665..27866203 100644 --- a/dank_mids/brownie_patch/contract.py +++ b/dank_mids/brownie_patch/contract.py @@ -1,6 +1,6 @@ import functools -from typing import Dict, List, NewType, Optional, Union, overload +from typing import Dict, List, Literal, NewType, Optional, Union, overload import brownie from brownie.network.contract import (ContractCall, ContractTx, OverloadedMethod, @@ -21,14 +21,38 @@ class Contract(brownie.Contract): """a modified `brownie.Contract` with async and call batching functionalities""" @classmethod - def from_abi(cls, *args, **kwargs) -> "Contract": - return Contract(brownie.Contract.from_abi(*args, **kwargs).address) + def from_abi( + cls, + name: str, + address: str, + abi: List[dict], + owner: Optional[AccountsType] = None, + persist: bool = True, + ) -> "Contract": + persisted = brownie.Contract.from_abi(name, address, abi, owner, _check_persist(persist)) + return Contract(persisted.address) @classmethod - def from_ethpm(cls, *args, **kwargs) -> "Contract": - return Contract(brownie.Contract.from_ethpm(*args, **kwargs).address) + def from_ethpm( + cls, + name: str, + manifest_uri: str, + address: Optional[str] = None, + owner: Optional[AccountsType] = None, + persist: bool = True, + ) -> "Contract": + persisted = brownie.Contract.from_ethpm(name, manifest_uri, address, owner, _check_persist(persist)) + return Contract(persisted.address) @classmethod - def from_explorer(cls, *args, **kwargs) -> "Contract": - return Contract(brownie.Contract.from_explorer(*args, **kwargs).address) + def from_explorer( + cls, + address: str, + as_proxy_for: Optional[str] = None, + owner: Optional[AccountsType] = None, + silent: bool = False, + persist: bool = True, + ) -> "Contract": + persisted = brownie.Contract.from_explorer(address, as_proxy_for, owner, silent, _check_persist(persist)) + return Contract(persisted.address) topics: Dict[str, str] signatures: Dict[Method, Signature] def __init__(self, *args, **kwargs): @@ -96,3 +120,8 @@ def _patch_if_method(method: ContractMethod, w3: Web3) -> None: class _ContractMethodPlaceholder: """A sentinel object that indicates a Contract does have a member by a specific name.""" + +def _check_persist(persist: bool) -> Literal[True]: + if persist is False: + raise NotImplementedError("persist: False") + return persist diff --git a/dank_mids/brownie_patch/types.py b/dank_mids/brownie_patch/types.py index 3fe1d994..4f0cd25f 100644 --- a/dank_mids/brownie_patch/types.py +++ b/dank_mids/brownie_patch/types.py @@ -1,132 +1,14 @@ -import asyncio -import functools -from decimal import Decimal -from typing import Any, Awaitable, Callable, Dict, Generic, Iterable, List, Optional, Tuple, TypeVar, Union +from typing import Any, Dict, Optional, Tuple, Union from brownie.typing import AccountsType -from brownie.convert.datatypes import EthAddress -from brownie.convert.utils import build_function_selector, build_function_signature from brownie.network.contract import ContractCall, ContractTx, OverloadedMethod -from eth_abi.exceptions import InsufficientDataBytes -from web3 import Web3 -from web3.datastructures import AttributeDict -from dank_mids import ENVIRONMENT_VARIABLES as ENVS +from dank_mids.brownie_patch._method import _DankMethod, _DankMethodMixin, _EVMType -_EVMType = TypeVar("_EVMType") ContractMethod = Union[ContractCall, ContractTx, OverloadedMethod] -@functools.lru_cache(maxsize=None) -class FunctionABI: - """A singleton to hold function signatures, since we only really need one copy of each func sig in memory.""" - __slots__ = "abi", "input_sig", "signature" - def __init__(self, **abi: Any): - self.abi = abi - self.input_sig = build_function_signature(abi) - self.signature = build_function_selector(abi) - - -def _make_hashable(obj: Any) -> Any: - if isinstance(obj, (list, tuple)): - return tuple((_make_hashable(o) for o in obj)) - elif isinstance(obj, dict): - return AttributeDict({k: _make_hashable(v) for k, v in obj.items()}) - return obj - -class _DankMethodMixin(Generic[_EVMType]): - _address: EthAddress - _abi: FunctionABI - """A mixin class that gives brownie objects async support and reduces memory usage""" - __slots__ = "_address", "_abi", "_name", "_owner", "natspec", "_encode_input", "_decode_input" - def __await__(self): - """Asynchronously call the contract method without arguments at the latest block and await the result.""" - return self.coroutine().__await__() - async def map( - self, - args: Iterable[Any], - block_identifier: Optional[int] = None, - decimals: Optional[int] = None, - ) -> List[_EVMType]: - return await asyncio.gather(*[self.coroutine(arg, block_identifier=block_identifier, decimals=decimals) for arg in args]) - @property - def abi(self) -> dict: - return self._abi.abi - @property - def signature(self) -> str: - return self._abi.signature - @property - def _input_sig(self) -> str: - return self._abi.input_sig - @functools.cached_property - def _len_inputs(self) -> int: - return len(self.abi['inputs']) - @functools.cached_property - def _skip_decoder_proc_pool(self) -> bool: - from dank_mids.brownie_patch.call import _skip_proc_pool - return self._address in _skip_proc_pool - @functools.cached_property - def _web3(cls) -> Web3: - from dank_mids import web3 - return web3 - @functools.cached_property - def _prep_request_data(self) -> Callable[..., Awaitable[bytes]]: - from dank_mids.brownie_patch import call - if ENVS.OPERATION_MODE.application or self._len_inputs: - return call.encode - else: - return call._request_data_no_args - -class _DankMethod(_DankMethodMixin): - __slots__ = "_address", "_abi", "_name", "_owner", "natspec", "_encode_input", "_decode_output" - def __init__( - self, - address: str, - abi: Dict, - name: str, - owner: Optional[AccountsType], - natspec: Optional[Dict] = None, - ) -> None: - self._address = address - self._abi = FunctionABI(**{key: _make_hashable(abi[key]) for key in sorted(abi)}) - self._name = name - self._owner = owner - self.natspec = natspec or {} - # TODO: refactor this - from dank_mids.brownie_patch import call - self._encode_input = call.encode_input - self._decode_output = call.decode_output - async def coroutine( # type: ignore [empty-body] - self, - *args: Any, - block_identifier: Optional[int] = None, - decimals: Optional[int] = None, - override: Optional[Dict[str, str]] = None, - ) -> _EVMType: - """ - Asynchronously call the contract method via dank mids and await the result. - - Arguments: - - *args: The arguments for the contract method. - - block_identifier (optional): The block at which the chain will be read. If not provided, will read the chain at latest block. - - decimals (optional): if provided, the output will be `result / 10 ** decimals` - - Returns: - - Whatever the node sends back as the output for this contract method. - """ - if override: - raise ValueError("Cannot use state override with `coroutine`.") - async with ENVS.BROWNIE_ENCODER_SEMAPHORE[block_identifier]: - data = await self._encode_input(self, self._len_inputs, self._prep_request_data, *args) - async with ENVS.BROWNIE_CALL_SEMAPHORE[block_identifier]: - output = await self._web3.eth.call({"to": self._address, "data": data}, block_identifier) - try: - decoded = await self._decode_output(self, output) - except InsufficientDataBytes as e: - raise InsufficientDataBytes(str(e), self, self._address, output) from e - return decoded if decimals is None else decoded / 10 ** Decimal(decimals) - class DankContractCall(_DankMethod, ContractCall): """ A `brownie.network.contract.ContractCall` subclass with async support via the `coroutine` method. diff --git a/tests/test_brownie_patch.py b/tests/test_brownie_patch.py index e929ccc1..c581a267 100644 --- a/tests/test_brownie_patch.py +++ b/tests/test_brownie_patch.py @@ -94,4 +94,4 @@ async def test_dank_overloaded_method(): assert isinstance(call, dank_mids.DankContractCall) assert call(pool) == curve_factory.get_lp_token(pool) == await curve_factory.get_lp_token.coroutine(pool) == "0x9432242D9Dc10AD5e2Fe570b8FC053A16597Caf6" -_CURVE_FACTORY_ABI = [{"name":"CommitNewAdmin","inputs":[{"name":"deadline","type":"uint256","indexed":True},{"name":"admin","type":"address","indexed":True}],"anonymous":False,"type":"event"},{"name":"NewAdmin","inputs":[{"name":"admin","type":"address","indexed":True}],"anonymous":False,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_address_provider","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"add_registry_handler","inputs":[{"name":"_registry_handler","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"update_registry_handler","inputs":[{"name":"_index","type":"uint256"},{"name":"_registry_handler","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"get_registry_handlers_from_pool","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address[10]"}]},{"stateMutability":"view","type":"function","name":"get_base_registry","inputs":[{"name":"registry_handler","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"find_pool_for_coins","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"find_pool_for_coins","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"find_pools_for_coins","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"outputs":[{"name":"","type":"address[]"}]},{"stateMutability":"view","type":"function","name":"get_admin_balances","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_admin_balances","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_balances","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_balances","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_base_pool","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_base_pool","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_coin_indices","inputs":[{"name":"_pool","type":"address"},{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"outputs":[{"name":"","type":"int128"},{"name":"","type":"int128"},{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"get_coin_indices","inputs":[{"name":"_pool","type":"address"},{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"int128"},{"name":"","type":"int128"},{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"get_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_decimals","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_decimals","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_fees","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[10]"}]},{"stateMutability":"view","type":"function","name":"get_fees","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[10]"}]},{"stateMutability":"view","type":"function","name":"get_gauge","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_gauge","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_gauge","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_gauge_type","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"get_gauge_type","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"get_gauge_type","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"get_lp_token","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_lp_token","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_n_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_n_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_n_underlying_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_n_underlying_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_pool_asset_type","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_pool_asset_type","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_pool_from_lp_token","inputs":[{"name":"_token","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_pool_from_lp_token","inputs":[{"name":"_token","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_pool_params","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[20]"}]},{"stateMutability":"view","type":"function","name":"get_pool_params","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[20]"}]},{"stateMutability":"view","type":"function","name":"get_pool_name","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"get_pool_name","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"get_underlying_balances","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_balances","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_decimals","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_decimals","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_virtual_price_from_lp_token","inputs":[{"name":"_token","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_virtual_price_from_lp_token","inputs":[{"name":"_token","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"is_meta","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_meta","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_registered","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_registered","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"pool_count","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"pool_list","inputs":[{"name":"_index","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"address_provider","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_registry","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"registry_length","inputs":[],"outputs":[{"name":"","type":"uint256"}]}] \ No newline at end of file +_CURVE_FACTORY_ABI = [{"name":"CommitNewAdmin","inputs":[{"name":"deadline","type":"uint256","indexed":True},{"name":"admin","type":"address","indexed":True}],"anonymous":False,"type":"event"},{"name":"NewAdmin","inputs":[{"name":"admin","type":"address","indexed":True}],"anonymous":False,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"_address_provider","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"add_registry_handler","inputs":[{"name":"_registry_handler","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"update_registry_handler","inputs":[{"name":"_index","type":"uint256"},{"name":"_registry_handler","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"get_registry_handlers_from_pool","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address[10]"}]},{"stateMutability":"view","type":"function","name":"get_base_registry","inputs":[{"name":"registry_handler","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"find_pool_for_coins","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"find_pool_for_coins","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"i","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"find_pools_for_coins","inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"outputs":[{"name":"","type":"address[]"}]},{"stateMutability":"view","type":"function","name":"get_admin_balances","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_admin_balances","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_balances","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_balances","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_base_pool","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_base_pool","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_coin_indices","inputs":[{"name":"_pool","type":"address"},{"name":"_from","type":"address"},{"name":"_to","type":"address"}],"outputs":[{"name":"","type":"int128"},{"name":"","type":"int128"},{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"get_coin_indices","inputs":[{"name":"_pool","type":"address"},{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"int128"},{"name":"","type":"int128"},{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"get_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_decimals","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_decimals","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_fees","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[10]"}]},{"stateMutability":"view","type":"function","name":"get_fees","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[10]"}]},{"stateMutability":"view","type":"function","name":"get_gauge","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_gauge","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_gauge","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_gauge_type","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"get_gauge_type","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"get_gauge_type","inputs":[{"name":"_pool","type":"address"},{"name":"gauge_idx","type":"uint256"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"int128"}]},{"stateMutability":"view","type":"function","name":"get_lp_token","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_lp_token","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_n_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_n_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_n_underlying_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_n_underlying_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_pool_asset_type","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_pool_asset_type","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_pool_from_lp_token","inputs":[{"name":"_token","type":"address"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_pool_from_lp_token","inputs":[{"name":"_token","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_pool_params","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[20]"}]},{"stateMutability":"view","type":"function","name":"get_pool_params","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[20]"}]},{"stateMutability":"view","type":"function","name":"get_pool_name","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"get_pool_name","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"string"}]},{"stateMutability":"view","type":"function","name":"get_underlying_balances","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_balances","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_coins","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_coins","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"address[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_decimals","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_underlying_decimals","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256[8]"}]},{"stateMutability":"view","type":"function","name":"get_virtual_price_from_lp_token","inputs":[{"name":"_token","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"get_virtual_price_from_lp_token","inputs":[{"name":"_token","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"is_meta","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_meta","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_registered","inputs":[{"name":"_pool","type":"address"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"is_registered","inputs":[{"name":"_pool","type":"address"},{"name":"_handler_id","type":"uint256"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"pool_count","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"pool_list","inputs":[{"name":"_index","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"address_provider","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"get_registry","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"registry_length","inputs":[],"outputs":[{"name":"","type":"uint256"}]}]