ApeWorX / ape

The smart contract development tool for Pythonistas, Data Scientists, and Security Professionals
https://apeworx.io
Apache License 2.0
889 stars 131 forks source link

Calling with `sender=ContractInstance` doesn't work #606

Closed fubuloubu closed 2 years ago

fubuloubu commented 2 years ago

Environment information

$ ape --version
0.1.3

$ ape plugins list
Installed Plugins:
  ens          
  hardhat      
  infura       
  vyper        
  etherscan    
  solidity     
  tokens  

What went wrong?

When using a network provider that supports transactions without signatures (such as forked mode networks or local test networks), ape doesn't support calling via a ContractInstance object as sender e.g.:

one_contract.mutableCall(..., sender=another_contract)

How can it be fixed?

The signature check in certain providers checks to see if sender is not of type AddressType before switching to using the signature check, which is missing ContractInstance (this is done because of a circular dependency). Just add the extra support for ContractInstace as well. Could even have it always convert the sender argument to AddressType, if signing is not required on that network.

fubuloubu commented 2 years ago

Debugging this further, seems like there is another issue where src/ape/contract/base.py:ContractTransaction.serialize_transaction will convert AddressType variables to HexBytes (presumably via HexEncoder), which fails to serialize properly for the Provider downstream

Thinking that conversion step needs more context into whatever variable types should be for the conversion, at least for kwargs

fubuloubu commented 2 years ago

quick fix to ContractTransaction:

    def _get_type(self, kwarg_name: str) -> Any:
        return TransactionAPI.__fields__[kwarg_name].type_

    def serialize_transaction(self, *args, **kwargs) -> TransactionAPI:
        kwargs = {
            k: self.conversion_manager.convert(
                v,
                # TODO: Upstream, `TransactionAPI.sender` should be `AddressType` (not `str`)
                AddressType if k == "sender" else self._get_type(k),
            )
            for k, v in kwargs.items()
        }
        ...
fubuloubu commented 2 years ago

Even with above fix, the workaround is to do:

one_contract.mutableCall(..., sender=accounts[another_contract.address])

This will load the contract as an ImpersonatedAccount

sabotagebeats commented 2 years ago

@fubuloubu can you give #619 a shot and see if it resolves the issue?

sabotagebeats commented 2 years ago

https://github.com/ApeWorX/ape-hardhat/issues/38