Bases: ERC20Metadata
 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  
   
      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 {}
  |