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
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.
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.
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.
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 .
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;
}
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.