is to derive from another contract. Derived contracts can access all non-private members including internal functions and state variables.ContractName.functionName() or using super.functionName() if you want to call the function one level higher up in the flattened inheritance hierarchysuper.f(..) will use JUMP and not a message call).x, if there is no visible state variable with the same name in any of its bases.virtual means that the function can change its behavior in derived classes ("overriding")B) that inherits from an already deployed contract (A at a specific address like 0x1F70...) at runtime.contract Owned {
address payable owner;
constructor() { owner = payable(msg.sender); }
}
// Use `is` to derive from another contract. Derived
// contracts can access all non-private members including
// internal functions and state variables. These cannot be
// accessed externally via `this`, though.
contract Emittable is Owned {
event Emitted();
// The keyword `virtual` means that the function can change
// its behavior in derived classes ("overriding").
function emitEvent() virtual public {
if (msg.sender == owner)
emit Emitted();
}
}
// These abstract contracts are only provided to make the
// interface known to the compiler. Note the function
// without body. If a contract does not implement all
// functions it can only be used as an interface.
abstract contract Config {
function lookup(uint id) public virtual returns (address adr);
}
abstract contract NameReg {
function register(bytes32 name) public virtual;
function unregister() public virtual;
}
// Multiple inheritance is possible. Note that `Owned` is
// also a base class of `Emittable`, yet there is only a single
// instance of `Owned` (as for virtual inheritance in C++).
contract Named is Owned, Emittable {
constructor(bytes32 name) {
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
NameReg(config.lookup(1)).register(name);
}
// Functions can be overridden by another function with the same name and
// the same number/types of inputs. If the overriding function has different
// types of output parameters, that causes an error.
// Both local and message-based function calls take these overrides
// into account.
// If you want the function to override, you need to use the
// `override` keyword. You need to specify the `virtual` keyword again
// if you want this function to be overridden again.
function emitEvent() public virtual override {
if (msg.sender == owner) {
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
NameReg(config.lookup(1)).unregister();
// It is still possible to call a specific
// overridden function.
Emittable.emitEvent();
}
}
}
// If a constructor takes an argument, it needs to be
// provided in the header or modifier-invocation-style at
// the constructor of the derived contract (see below).
contract PriceFeed is Owned, Emittable, Named("GoldFeed") {
uint info;
function updateInfo(uint newInfo) public {
if (msg.sender == owner) info = newInfo;
}
// Here, we only specify `override` and not `virtual`.
// This means that contracts deriving from `PriceFeed`
// cannot change the behavior of `emitEvent` anymore.
function emitEvent() public override(Emittable, Named) { Named.emitEvent(); }
function get() public view returns(uint r) { return info; }
}
Consider the contract CoinFlip
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CoinFlip {
uint256 public consecutiveWins;
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor() {
consecutiveWins = 0;
}
function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number - 1));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
}
You want to call the function flip from an external contract. You need its ABI
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import './CoinFlip.sol';
interface ICoinFlip {
function flip(bool _guess) external returns (bool);
}
contract CoinFlipHelper {
ICoinFlip public coinFlipInterface;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor(address flipAddress_) {
coinFlipInterface = ICoinFlip(flipAddress_);
}
function winFlipGame() public {
uint256 blockValue = uint256(blockhash(block.number - 1));
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
coinFlipInterface.flip(side);
}
}