Bases: ERC20
This is how we make the ProtocolBase inject the ContractFunc via the type signature. After a lot of research, this goes slightly outside of the bounds for type hinting, but I think the improved expressiveness makes it fully worthwhile.
Source code in eth_rpc/contract/base.py
| def __init__(self, **kwargs):
"""
This is how we make the ProtocolBase inject the ContractFunc via the type signature.
After a lot of research, this goes slightly outside of the bounds for type hinting,
but I think the improved expressiveness makes it fully worthwhile.
"""
super().__init__(**kwargs)
for alias, func in self._func_sigs.items():
name = alias
if is_annotation(func):
annotation_args = get_args(func)
args = annotation_args[0]
for annotation in annotation_args:
if isinstance(annotation, Name):
name = annotation.value
else:
args = func
T, U = get_args(args)
setattr(
self,
alias,
ContractFunc[T, U]( # type: ignore
func=FuncSignature[T, U](name=name, alias=alias), # type: ignore
contract=self,
),
)
|
address instance-attribute
code_override class-attribute
instance-attribute
code_override = Field(default=None)
functions class-attribute
instance-attribute
functions = Field(default_factory=list)
model_config class-attribute
instance-attribute
model_config = ConfigDict(extra='allow')
name class-attribute
instance-attribute
symbol class-attribute
instance-attribute
decimals class-attribute
instance-attribute
balance_of class-attribute
instance-attribute
total_supply class-attribute
instance-attribute
transfer class-attribute
instance-attribute
transfer_from class-attribute
instance-attribute
approve class-attribute
instance-attribute
allowance class-attribute
instance-attribute
get_reserves class-attribute
instance-attribute
token0 class-attribute
instance-attribute
token1 class-attribute
instance-attribute
model_post_init
model_post_init(__context)
Source code in eth_rpc/_request.py
| def model_post_init(self, __context):
network = self.__class__._network
object.__setattr__(self, "_network", network)
# overwrite the .rpc() classmethod
object.__setattr__(self, "rpc", self._rpc)
|
rpc classmethod
This uses the default network, unless a network has been provided
Source code in eth_rpc/_request.py
| @classmethod
def rpc(cls) -> "RPC":
"""
This uses the default network, unless a network has been provided
"""
from ._transport import _force_get_global_rpc
if cls._network is None:
return _force_get_global_rpc()
response = _force_get_global_rpc(cls._network)
return response
|
add_func
Source code in eth_rpc/contract/contract.py
| def add_func(self, func: "FuncSignature"):
if func not in self.functions:
self.functions.append(ContractFunc(func=func, contract=self))
|
get_storage_at
get_storage_at(*, slot, block_number='latest', sync=False)
Source code in eth_rpc/contract/contract.py
| def get_storage_at(
self, *, slot: int | HexStr, block_number="latest", sync: bool = False
) -> MaybeAwaitable[HexStr]:
return run(
self._get_storage_at,
slot=slot,
block_number=block_number,
sync=sync,
)
|
get_code
get_code(*, block_number=None, block_hash=None, sync=False)
Source code in eth_rpc/contract/contract.py
| def get_code(
self,
*,
block_number: int | BLOCK_STRINGS | None = None,
block_hash: HexStr | None = None,
sync: bool = False,
) -> MaybeAwaitable[HexStr]:
return run(
self._get_code,
block_number=block_number,
block_hash=block_hash,
sync=sync,
)
|
create2
create2(salt, keccak_init_code)
EIP-104 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md
Source code in eth_rpc/contract/contract.py
| def create2(self, salt: bytes, keccak_init_code: bytes) -> HexAddress:
"""
EIP-104
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md
"""
pre = "0xff"
b_pre = bytes.fromhex(pre[2:])
b_address = bytes.fromhex(self.address[2:])
b_result = keccak_256(b_pre + b_address + salt + keccak_init_code)
result_address = "0x" + b_result[12:].hex()
return HexAddress(HexStr(result_address))
|
get_decimals
Source code in eth_typeshed/erc20/erc20.py
| def get_decimals(self):
if not self._decimals:
self._decimals = self.decimals().get()
return self._decimals
|
get_name
Source code in eth_typeshed/erc20/erc20.py
| def get_name(self):
if not self._name:
self._name = self.name().get()
return self._name
|
get_symbol
Source code in eth_typeshed/erc20/erc20.py
| def get_symbol(self):
if not self._symbol:
self._symbol = self.symbol().get()
return self._symbol
|
load_async async
Source code in eth_typeshed/erc20/erc20.py
| async def load_async(self):
from eth_typeshed.multicall import multicall
if not (self._name and self._symbol and self._decimals):
self._name, self._symbol, self._decimals = await multicall.execute(
self.name(),
self.symbol(),
self.decimals(),
)
|
get_allowance_slot
get_allowance_slot(owner, spender)
Gets the allowance slot given token/owner/spender combination
Source code in eth_typeshed/erc20/erc20.py
| def get_allowance_slot(self, owner: str, spender: str):
"""
Gets the allowance slot given token/owner/spender combination
"""
response = self._get_debug_tracecall(
self.address,
data=f"0xdd62ed3e000000000000000000000000{owner.replace('0x', '')}000000000000000000000000{spender.replace('0x', '')}",
)
if not response:
return None
try:
storage = response[self.address.lower()]["storage"]
except KeyError:
return None
for key in [
OZ_IMPLEMENTATION_SLOT,
ADMIN_SLOT,
EIP1967_IMPLEMENTATION_SLOT,
]:
if hex(key) in storage:
del storage[hex(key)]
if len(storage) != 1:
# TOOD: this isn't really a ValueError, but we need to allow the client to handle this differently
raise ValueError(list(storage.keys()))
return list(storage.keys())[0]
|
get_balance_slot
Attempts to find the balance slot for an address. This will not work on tokens with irregular balance calculation.
Source code in eth_typeshed/erc20/erc20.py
| def get_balance_slot(self, owner: primitives.address) -> Optional[HexStr]:
"""
Attempts to find the balance slot for an address.
This will not work on tokens with irregular balance calculation.
"""
balance = self.balance_of(owner).sync.call().raw
result = self._get_debug_tracecall(
self.address,
data=f"0x70a08231000000000000000000000000{owner.replace('0x', '')}",
)
storage = result[self.address.lower()]["storage"]
for slot in storage:
if balance in storage[slot]:
return slot
# Unknown slot return None
return None
|
balance_state_diff
balance_state_diff(owner, balance)
Source code in eth_typeshed/erc20/erc20.py
| def balance_state_diff(
self, owner: primitives.address, balance: int
) -> Optional[dict]:
slot = self.get_balance_slot(owner)
if slot:
return {
self.address: {
"stateDiff": {
slot: to_bytes32(balance),
},
},
}
return {}
|
allowance_state_diff
allowance_state_diff(owner, spender, amount)
Source code in eth_typeshed/erc20/erc20.py
| def allowance_state_diff(
self, owner: HexAddress, spender: HexAddress, amount: int
) -> Optional[dict]:
slot = self.get_allowance_slot(owner, spender)
if slot:
return {
self.address: {
"stateDiff": {
slot: to_bytes32(amount),
}
},
}
return {}
|
get_price
Source code in eth_typeshed/uniswap_v2/pair.py
| def get_price(self, token0: bool = True):
reserves0, reserves1, _ = self.get_reserves().get()
price0, price1 = (reserves1 / reserves0, reserves0 / reserves1)
return Decimal(price0) if token0 else Decimal(price1)
|