How to find out if an Ethereum address is a contract?

后端 未结 6 808
谎友^
谎友^ 2020-12-24 13:31

An address in Solidity can be an account or a contract (or other things, such as a transaction). When I have a variable x, holding an address, how can I test if it is a cont

相关标签:
6条回答
  • 2020-12-24 14:08

    Edit: Solidity has changed since this answer was first written, @manuel-aráoz has the correct answer.

    There is no way in solidity to check if an address is a contract. One of the goals of Ethereum is for humans and smart contracts to both be treated equally. This leads into a future where smart contracts interact seamlessly with humans and other contracts. It might change in the future , but for now an arbitrary address is ambiguous.

    0 讨论(0)
  • 2020-12-24 14:12

    What you can do, granted you have the information at hand. If the transactions sender address was null or unoccupied then you can tell if the address is a contract account or an EOA (externally owned account). i.e. when sending a create contract transaction on the network then the receive address in the transaction is null/not used.

    Reference from github: https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions

    Hope this helps.

    0 讨论(0)
  • 2020-12-24 14:16

    The top-voted answer with the isContract function that uses EXTCODESIZE was discovered to be hackable.

    The function will return false if it is invoked from a contract's constructor (because the contract has not been deployed yet).

    The code should be used very carefully, if at all, to avoid security hacks such as:

    https://www.reddit.com/r/ethereum/comments/916xni/how_to_pwn_fomo3d_a_beginners_guide (archive)

    To repeat:

    Do not use the EXTCODESIZE check to prevent smart contracts from calling a function. This is not foolproof, it can be subverted by a constructor call, due to the fact that while the constructor is running, EXTCODESIZE for that address returns 0.

    See sample code for a contract that tricks EXTCODESIZE to return 0.


    If you want to make sure that an EOA is calling your contract, a simple way is require(msg.sender == tx.origin). However, preventing a contract is an anti-pattern with security and interoperability considerations.

    This will need revisiting when account abstraction is implemented.

    0 讨论(0)
  • 2020-12-24 14:22

    Short answer:

    require(tx.origin == msg.sender);
    

    tx.origin is a reference of the original address who initiates this serial function call, while msg.sender is the address who directly calls the target function. Which means, tx.origin must be a human, msg.sender can be a contract or human. Thus, if someone calls you from a contract, then the msg.sender is a contract address which is different from tx.origin.

    I know most contracts may use @Manuel Aráoz's code, which works in most cases. But if you call a function within the constructor of a contract, extcodesize will return 0 which fails the isContract check.

    NOTE: DON'T use tx.origin under other circumstances if you are not clear about what it represents because .

    0 讨论(0)
  • 2020-12-24 14:25

    Yes you can, by using some EVM assembly code to get the address' code size:

    function isContract(address addr) returns (bool) {
      uint size;
      assembly { size := extcodesize(addr) }
      return size > 0;
    }
    
    0 讨论(0)
  • 2020-12-24 14:28

    This isn't something you can query from within a contract using Solidity, but if you were just wanting to know whether an address holds contract code or not, you can check using your geth console or similar with eg:

      > eth.getCode("0xbfb2e296d9cf3e593e79981235aed29ab9984c0f")
    

    with the hex string (here 0xbfb2e296d9cf3e593e79981235aed29ab9984c0f) as the address you wish to query. This will return the bytecode stored at that address.

    You can also use a blockchain scanner to find the source code of the contract at that address, for example the ecsol library as shown on etherscan.io.

    0 讨论(0)
提交回复
热议问题