In the following code the "MainContract" contract is constructed by passing the address of a "MyInterface" Object. I'm able to construct a "MainContract" contract by by passing the address of a "ContractInherits" contract. How is this possible when "ContractInherits" doesn't implement the "randomFunction()" function? Is ContractInherits actually inheriting from MyInterface?
pragma solidity 0.8.19;
interface MyInterface{
function changeVariable() external;
function randomFunction() external;
}
contract ContractInherits {
uint256 public a_variable;
function changeVariable() public {
a_variable = a_variable++;
}
}
contract MainContract {
MyInterface public immutable ContractInherits;
constructor(MyInterface _ContractInherits) {
ContractInherits = _ContractInherits;
}
}
I'll demo an example of my comment above, that you'll get a runtime error.
Here is your original code, with a couple of modifications:
ContractInherits
variable name within MainContract
to instanceOfContractInherits
to clarify what it really is, plus avoid variable shadowing.doStuff()
function for the runtime error will be produced.// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.19;
interface MyInterface{
function changeVariable() external;
function randomFunction() external;
}
contract ContractInherits {
uint256 public a_variable;
function changeVariable() public {
a_variable = a_variable++;
}
}
contract MainContract {
MyInterface public immutable instanceOfContractInherits;
constructor(MyInterface _ContractInherits) {
instanceOfContractInherits = _ContractInherits;
}
function doStuff() public {
instanceOfContractInherits.changeVariable();
instanceOfContractInherits.randomFunction();
}
}
Then I've done the following in Remix:
(1) Deploy ContractInherits
(2) Copy its deployed address
(3) Deploy MainContract
, passing in the just copied address into its constructor
(4) Invoke the instanceOfContractInherits
accessor function
At this point, the "Deployed Contracts" section looks like this:
Now for the runtime error as promised:
(5) Invoke the doStuff
transaction function
(6) Observe the transaction status of revert
in the logs
transact to MainContract.doStuff errored: VM error: revert.
revert
(7) Expand the lines in the logs that started with [vm]
to the the reason, which is:
status false Transaction mined but execution failed
So, why does this happen?
The solidity compiler solc
does not (and cannot) know
what the interface is at compile time, because
solc
does not access the network during compilation,solc
cannot infer ABI from bytecode (reverse engineering is not one of the things it does), andsolc
should produce bytecode that is agnostic to which EVM-compatible network it is deployed to (e.g. it could be deployed to another network where the address referenced does indeed have a working implementation for this interface)