Use an abstract contract (preferred)
Further clarifications to @Edmund's answer:
contract A { // This doesn't have to match the real contract name. Call it what you like.
function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}
contract YourContract {
function doYourThing(address addressOfA) returns(uint) {
A my_a = A(addressOfA);
return my_a.f1(true, 3);
}
}
This shows using the return value from f1
.
Also, if f1
encounters an exception (imagine its implementation is function f1(bool arg1, uint arg2) returns(uint) { throw; }
), the exception is propagated and my_a.f1
will also throw
and it will revert a transaction that invoked doYourThing
.
In practice, you'll have 3 files.
AbstractA.sol contains:
contract A {
function f1(bool arg1, uint arg2) returns(uint); // No implementation, just the function signature. This is just so Solidity can work out how to call it.
}
YourContract.sol contains:
import "AbstractA.sol"
contract YourContract {
function doYourThing(address addressOfA) returns(uint) {
A my_a = A(addressOfA);
return my_a.f1(true, 3);
}
}
A.sol contains:
contract A {
// implementation of f1
function f1(bool arg1, uint arg2) returns(uint) {
if (arg1) {
throw;
} else {
return arg2;
}
}
}
Limitations of using call
call
is suggested in @Badr's answer but should be used very carefully. Solidity docs state:
All three functions call
, delegatecall
and callcode
are very
low-level functions and should only be used as a last resort as they
break the type-safety of Solidity.
Also, the return value of f1
can't be obtained by using call
like addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)
because call
only returns a bool
(false
if the call encounters an exception).
This means that the exception must be propagated manually like:
if (!addressOfA.call(bytes4(keccak256("f1(bool, uint256)")), true, 3)) {
throw;
}