-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ shanghai upgrades 5 files changed, 57 insertions(+), 9 deletions(-)
- Loading branch information
Showing
14 changed files
with
787 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .signature import Signature | ||
from .call import Call | ||
from .multicall import Multicall |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
from typing import Any, Callable, Iterable, List, Optional, Tuple, Union | ||
|
||
import eth_retry | ||
from eth_typing import Address, ChecksumAddress, HexAddress | ||
from eth_typing.abi import Decodable | ||
from eth_utils import to_checksum_address | ||
from web3 import Web3 | ||
|
||
from .signature import Signature | ||
from .constants import Network, w3, ASYNC_SEMAPHORE | ||
from .exceptions import StateOverrideNotSupported | ||
from .loggers import setup_logger | ||
from .utils import (chain_id, get_async_w3, run_in_subprocess, | ||
state_override_supported) | ||
|
||
logger = setup_logger(__name__) | ||
|
||
AnyAddress = Union[str, Address, ChecksumAddress, HexAddress] | ||
|
||
|
||
class Call: | ||
def __init__( | ||
self, | ||
target: AnyAddress, | ||
function: Union[str, Iterable[Union[str, Any]]], | ||
# 'funcName(dtype)(dtype)' or ['funcName(dtype)(dtype)', input0, input1, ...] | ||
returns: Optional[Iterable[Tuple[str, Callable]]] = None, | ||
block_id: Optional[int] = None, | ||
gas_limit: Optional[int] = None, | ||
state_override_code: Optional[str] = None, | ||
# This needs to be None in order to use process_pool_executor | ||
_w3: Web3 = None | ||
) -> None: | ||
self.target = to_checksum_address(target) | ||
self.returns = returns | ||
self.block_id = block_id | ||
self.gas_limit = gas_limit | ||
self.state_override_code = state_override_code | ||
self.w3 = _w3 | ||
|
||
self.args: Optional[List[Any]] | ||
if isinstance(function, list): | ||
self.function, *self.args = function | ||
else: | ||
self.function = function | ||
self.args = None | ||
|
||
self.signature = Signature(self.function) | ||
|
||
def __repr__(self) -> str: | ||
return f'<Call {self.function} on {self.target[:8]}>' | ||
|
||
@property | ||
def data(self) -> bytes: | ||
return self.signature.encode_data(self.args) | ||
|
||
def decode_output( | ||
output: Decodable, | ||
signature: Signature, | ||
returns: Optional[Iterable[Tuple[str, Callable]]] = None, | ||
success: Optional[bool] = None | ||
) -> Any: | ||
|
||
if success is None: | ||
apply_handler = lambda handler, value: handler(value) | ||
else: | ||
apply_handler = lambda handler, value: handler(success, value) | ||
|
||
if success is None or success: | ||
try: | ||
decoded = signature.decode_data(output) | ||
except: | ||
success, decoded = False, [None] * (1 if not returns else len(returns)) # type: ignore | ||
else: | ||
decoded = [None] * (1 if not returns else len(returns)) # type: ignore | ||
|
||
logger.debug(f'returns: {returns}') | ||
logger.debug(f'decoded: {decoded}') | ||
|
||
if returns: | ||
return { | ||
name: apply_handler(handler, value) if handler else value | ||
for (name, handler), value | ||
in zip(returns, decoded) | ||
} | ||
else: | ||
return decoded if len(decoded) > 1 else decoded[0] | ||
|
||
@eth_retry.auto_retry | ||
def __call__(self, args: Optional[Any] = None, _w3: Optional[Web3] = None) -> Any: | ||
_w3 = self.w3 or _w3 or w3 | ||
args = prep_args( | ||
self.target, | ||
self.signature, | ||
args or self.args, | ||
self.block_id, | ||
self.gas_limit, | ||
self.state_override_code, | ||
) | ||
return Call.decode_output( | ||
_w3.eth.call(*args), | ||
self.signature, | ||
self.returns, | ||
) | ||
|
||
def __await__(self) -> Any: | ||
return self.coroutine().__await__() | ||
|
||
@eth_retry.auto_retry | ||
async def coroutine(self, args: Optional[Any] = None, _w3: Optional[Web3] = None) -> Any: | ||
_w3 = self.w3 or _w3 or w3 | ||
|
||
if self.state_override_code and not state_override_supported(_w3): | ||
raise StateOverrideNotSupported( | ||
f'State override is not supported on {Network(chain_id(_w3)).__repr__()[1:-1]}.') | ||
|
||
async with ASYNC_SEMAPHORE: | ||
output = await get_async_w3(_w3).eth.call( | ||
*await run_in_subprocess( | ||
prep_args, | ||
self.target, | ||
self.signature, | ||
args or self.args, | ||
self.block_id, | ||
self.gas_limit, | ||
self.state_override_code, | ||
) | ||
) | ||
|
||
return await run_in_subprocess(Call.decode_output, output, self.signature, self.returns) | ||
|
||
|
||
def prep_args( | ||
target: str, | ||
signature: Signature, | ||
args: Optional[Any], | ||
block_id: Optional[int], | ||
gas_limit: int, | ||
state_override_code: str, | ||
) -> List: | ||
calldata = signature.encode_data(args) | ||
|
||
args = [{'to': target, 'data': calldata}, block_id] | ||
|
||
if gas_limit: | ||
args[0]['gas'] = gas_limit | ||
|
||
if state_override_code: | ||
args.append({target: {'code': state_override_code}}) | ||
|
||
return args |
Oops, something went wrong.