Ethereum blockchain proposed tamper-proof decentralized financial contracts and applications. One of the main objectives of Ethereum is constructing decentralized applications that run without any downtime, fraud, control, or interference from a third party.
Since it does not allow third-party interference, it is literally unthinkable to find a way to check if the address is a smart contract.
But there is a way to get the problem solved. Ethereum virtual machine has the authority to access both smart contracts and externally owned accounts. If we can manipulate the data stored there, we may gather some information regarding the address.
But how can we do that?
We can interact directly with the EVM using the opcodes available in a low-level language called assembly. For this purpose, we will take the benefits of an inline-assembly language that allows us to exploit the bytecode of an address. Let’s jump into a practical use case.
How to Find the Address of a Contract?
There are several methods available to find the address of a contract. I will use an easy one here to get the address of a deployed contract.
pragma solidity ^0.8.0; contract isItContract { function contractAddress() public view returns (address) { address contAddress = address(this); //contract address return contAddress; }
- We have created a function
contractAdress()
inside the “isItContract
” smart contract. - The
contractAddress()
function returns the address of the contract - We put “
this
” keyword as a parameter inside theaddress()
type - To access members of the address type of the current contract instance, we can use the “
this
” keyword. “this
” represents the current contract’s type.
As we deployed our contract on the remix etherium we got the address of the contract as 0xb27A31f1b0AF2946B7F582768f03239b1eC07c2c
.
How to Know That an Address Represents a Smart Contract?
The Ethereum virtual machine is the place where all the smart contracts and Ethereum accounts live.
To extract information regarding smart contracts, we need to manipulate the data residing there. Solidity assembly is a low-level language that allows us to manipulate the data available in an Ethereum virtual machine directly.
It is possible to bypass some of the important safety features and checks in solidity with the help of assembly language. At the same time, It is also a dangerous way to choose as it manipulates the memory directly.
That’s why it is recommended not to use it until the use case is highly required or there is no other way left by using the Solidity language. We will use the assembly language for our purpose today. Let’s jump in.
Method 1: using EXTCODEHASH
function checkContract(address addr) public view returns (bool) { bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; bytes32 codehash; assembly { codehash := extcodehash(addr) } return (codehash != 0x0 && codehash != accountHash); }
- A
checkContract()
function is created, which will take an address as the argument and return the Boolean “true
” if the address is a contract or “false
” if it is not. - We have used
accountHash 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
, as it is thekeccak256
hash of empty data. That means when there is no code available inside the account of an address thisaccountHash
will be returned. codehash
is defined as the hash of the EVM code of an account. When an address receives a message call, this code gets executed. It can not be changed after execution.extcodehash
is introduced as a new opcode that returns thekeccak256
hash of a contract’s bytecode. If we need to perform checks on a contract’s bytecode, we can use extcodehash. According to Ethereum improvement proposals, TheEXTCODEHASH
takes one argument from the stack, zeros the first 96 bits, and pushes thekeccak256
hash of the account code at the address being the remaining 160 bits. If the account does not exist or is empty (as defined by EIP-161) 0 is pushed to the stack.
In case the account does not have code the keccak256
hash of empty data (i.e. c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
) is pushed to the stack.
Reference: https://eips.ethereum.org/EIPS/eip-1052
- codehash “
0x0
” represents a non-existent account. Thus the “return
” function returns boolean “true
”, if the account exists (i.e.codehash != 0x0
) and there is some executable code written inside the smart contract (i.e.codehash != accountHash
).
Let’s deploy the contract and see what happens:
First, we got the deployed contract’s address by clicking the “contractAddress
” button. the address is 0xd9145CCE52D386f254917e481eB44e9943F39138
.
Next, we checked if the address is a contract by placing the contract as an argument inside the “checkContract
” function. The result came out as a Boolean true
.
Now let’s try with a different address.
We tried with a different address, but we got “false
” because the address was not a smart contract.
Method 2: using EXTCODESIZE
Extcodesize is another opcode available which represents the size of the code available inside the EVM. we can use this also to get if the address is a smart contract.
function isContract(address addr) public view returns (bool) { uint size; assembly { size := extcodesize(addr) } return size > 0; }
- The
isContract
function takes an address as an argument and returns a Boolean. - We declared the extcodesize of the address (i.e.,
addr
) as the ‘size
‘. - Each Ethereum address has a code field associated with it. If the address is not a smart contract, this field would be empty. If the
extcodesize
checks the code size of the address is zero, then the address is a regular one. If it finds the code size greater than zero, it is a smart contract. - This assembly code should be written within the contract to access this opcode since the Solidity compiler does not support it directly.
- The function returns
true
if the extcodesize of the address is greater than zero.
Now let’s deploy the contract and check if it works:
We deployed the contract and went for the address first. Then we checked the address with isContract
function. It returns Boolean true
. That means the address is a smart contract.
That’s all for today. You can find the complete code on GitHub.
Reference: