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,008
- 1
- 12
- 30
1 Answers
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
0123456789012345678901234567890123456789in 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.
- 7,313
- 1
- 23
- 38
-
No this won’t work because calling contract can trick the values. I don’t only want to check but prevent. – user2284570 Apr 11 '19 at 14:05
-
Usually,
address(this)returns address of this contract, not calling one. But in case this contract was called viaCALLCODEorDELEGATECALLit returns address of calling contract, or, more precisely, it returns whatever it returned for calling contract. – Mikhail Vladimirov Apr 11 '19 at 14:05 -
-
How to ensure
0x0123456789012345678901234567890123456789will be encoded in code and not as an ꜱꜱᴛᴏʀᴇ constent ? – user2284570 Apr 11 '19 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. – Mikhail Vladimirov Apr 11 '19 at 14:08
-
Also, as far I know, it’s not possible to get the address of the future contract if the contract is created by a contract. – user2284570 Apr 12 '19 at 02:31
-
It is indeed possible. The address of created contract is derived from address of creator contract and nonce, where nonce is the number of contracts already created by this creator contract plus one. See "Note" in the following answer: https://ethereum.stackexchange.com/a/761/4955 – Mikhail Vladimirov Apr 12 '19 at 04:49
address(this)returns always the same address even in a CALLCODE environment. – user2284570 Apr 11 '19 at 12:51