Simple question but I couldn’t find the answer anywhere.
How to know if the code of my contract is used in a CALLCODE or DELEGATECALL by third party sinceaddress(this)
returns the address of the caller instead of the address of the contract if I’m not wrong ?
1 Answer
Simple way
uint private constant MAGIC = ...; // Your birthday here
uint private magic = MAGIC;
function isDelegated () internal view return (bool) {
return magic != MAGIC;
}
The idea is that MAGIC
is compile-time constant, so it will be embedded into the byte code by Solidity, but magic
is state variable. When contract is called normally, magic == MAGIC
is true, but in case of CALLCODE
or DELEGATECALL
, your code will observe storage of the calling contract, thus magic
will most probably contain something other than MAGIC
. Though this approach may be easily cheated by calling contract, so it protects only from accidental, but not from malicious use.
Reliable approach
You need to save real deployment address of your contract, and then in method you need to compare address(this)
with saved address. The problem is that you cannot save deployment address into storage, because storage will not be available when your contract is called via CALLCODE
or DELEGATECALL
, so you need to save deployment address into your smart contract's byte code. It is possible to modify byte code in constructor of smart contract, though this will require some assembly programming. Simpler way would be to modify byte code before publishing deploy transaction. You will just need to predict contract address, which is actually possible, because contract address is derived from address of whoever deployed the contract and transaction nonce. So, you need to do something like this:
function isDelegated () internal view returns (bool) {
return address (this) != 0x0123456789012345678901234567890123456789;
}
And before deploying your contract you need to:
- Find out address the contract will be deployed at
- Replace
0123456789012345678901234567890123456789
in contract's byte code with this address - Deploy contract as usual but with modified byte code
And after this isDelegated
will return accurate result.
BTW, Solidity protects libraries form being called directly, and I believe that is uses byte code modification in constructor technique, as described above, to achieve this.
-
No this won’t work because calling contract can trick the values. I don’t only want to check but prevent. Commented Apr 11, 2019 at 14:05
-
Usually,
address(this)
returns address of this contract, not calling one. But in case this contract was called viaCALLCODE
orDELEGATECALL
it returns address of calling contract, or, more precisely, it returns whatever it returned for calling contract. Commented Apr 11, 2019 at 14:05 -
-
How to ensure
0x0123456789012345678901234567890123456789
will be encoded in code and not as an ꜱꜱᴛᴏʀᴇ constent ? Commented Apr 11, 2019 at 14:07 -
All literals are always in code. All store variables should be explicitly declared. Solidity never puts anything into store by its own. Commented Apr 11, 2019 at 14:08
address(this)
returns always the same address even in a CALLCODE environment.