I did a few test and seems like the order you use to extend the classes it matter. Given this example:
pragma solidity 0.4.21;
contract Ownable {
event OwnableE(uint);
function Ownable() public {
emit OwnableE(1);
}
}
contract TimedCrowdsale {
event TimedCrowdsaleE(uint);
function TimedCrowdsale() public {
emit TimedCrowdsaleE(1);
}
}
contract Crowdsale {
event CrowdsaleE(uint);
function Crowdsale() public {
emit CrowdsaleE(1);
}
}
contract FinalizableCrowdsale is Ownable, TimedCrowdsale {
event FinalizableCrowdsaleE(uint);
function FinalizableCrowdsale() public {
emit FinalizableCrowdsaleE(1);
}
}
contract CappedCrowdsale is Crowdsale {
event CappedCrowdsaleE(uint);
function CappedCrowdsale() public {
emit CappedCrowdsaleE(1);
}
}
contract RefundableCrowdsale is FinalizableCrowdsale {
event RefundableCrowdsaleE(uint);
function RefundableCrowdsale() public {
emit RefundableCrowdsaleE(1);
}
}
contract MintedCrowdsale is Crowdsale {
event MintedCrowdsaleE(uint);
function MintedCrowdsale() public {
emit MintedCrowdsaleE(1);
}
}
contract IndividuallyCappedCrowdsale is Ownable, Crowdsale {
event IndividuallyCappedCrowdsaleE(uint);
function IndividuallyCappedCrowdsale() public {
emit IndividuallyCappedCrowdsaleE(1);
}
}
contract TieredCrowdsale is Ownable, Crowdsale {
event TieredCrowdsaleE(uint);
function TieredCrowdsale() public {
emit TieredCrowdsaleE(1);
}
}
contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsale, IndividuallyCappedCrowdsale, TieredCrowdsale {
event SampleCrowdsaleE(uint);
function SampleCrowdsale() public {
emit SampleCrowdsaleE(1);
}
}
the call chain would be:
[
{
"topic": "bdac561e97cd2f10f81e3ccfa6953563ea5921aacbbed1a01338388b58b7035b",
"event": "OwnableE",
"args": [
"1"
]
},
{
"topic": "0745b765421933707f4bdaebed6f1478ed78c6f1fa656035d672a1eb04a914ce",
"event": "CrowdsaleE",
"args": [
"1"
]
},
{
"topic": "7e78dc6ab4bed05d0901d10704f58ce946a5eb50d3a279d26887df13fe4b19d6",
"event": "CappedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "896ac1cf1e4f0dea962c7533989a352036679bd5222c53e344f88a80eb70febb",
"event": "TimedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "07b3016f470d5b16960d54a55cb7e9bd74c20746a19c7cb0ba634a52e83934ce",
"event": "FinalizableCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "2a1ec31b0b7f73e6938c981b1f806a9d76ec0c1904a53de98197f2b7054301d7",
"event": "RefundableCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "39a8041bef698db3de246b679ad52b01b9f8ba609de0573804701617faac2803",
"event": "MintedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "9dde5892f2ad9eb0f156963773cf38cad6b804f8061d765fbbbc10f9d3d4048f",
"event": "IndividuallyCappedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "3171f924f0e542de51df919c69da5e54fb7c51a9467384a87261ac7f6f945f48",
"event": "TieredCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "615ecfd72872a19eeed214c27309877c89602943fa4b789f87d67fc0cce30a11",
"event": "SampleCrowdsaleE",
"args": [
"1"
]
}
]
from the bottom to the top this would be the order
SampleCrowdsale
TieredCrowdsale
IndividuallyCappedCrowdsale
MintedCrowdsale
RefundableCrowdsale
FinalizableCrowdsale
TimedCrowdsale
CappedCrowdsale
Crowdsale
Ownable
same as the one you found on your empirical approach.
But if I change the order of the class that I'm going to extend in the SampleCrowdsale the output would be different
contract SampleCrowdsale is TieredCrowdsale, IndividuallyCappedCrowdsale, MintedCrowdsale, RefundableCrowdsale, CappedCrowdsale {
event SampleCrowdsaleE(uint);
function SampleCrowdsale() public {
emit SampleCrowdsaleE(1);
}
}
this will give you this output
[
{
"topic": "bdac561e97cd2f10f81e3ccfa6953563ea5921aacbbed1a01338388b58b7035b",
"event": "OwnableE",
"args": [
"1"
]
},
{
"topic": "0745b765421933707f4bdaebed6f1478ed78c6f1fa656035d672a1eb04a914ce",
"event": "CrowdsaleE",
"args": [
"1"
]
},
{
"topic": "3171f924f0e542de51df919c69da5e54fb7c51a9467384a87261ac7f6f945f48",
"event": "TieredCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "9dde5892f2ad9eb0f156963773cf38cad6b804f8061d765fbbbc10f9d3d4048f",
"event": "IndividuallyCappedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "39a8041bef698db3de246b679ad52b01b9f8ba609de0573804701617faac2803",
"event": "MintedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "896ac1cf1e4f0dea962c7533989a352036679bd5222c53e344f88a80eb70febb",
"event": "TimedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "07b3016f470d5b16960d54a55cb7e9bd74c20746a19c7cb0ba634a52e83934ce",
"event": "FinalizableCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "2a1ec31b0b7f73e6938c981b1f806a9d76ec0c1904a53de98197f2b7054301d7",
"event": "RefundableCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "7e78dc6ab4bed05d0901d10704f58ce946a5eb50d3a279d26887df13fe4b19d6",
"event": "CappedCrowdsaleE",
"args": [
"1"
]
},
{
"topic": "615ecfd72872a19eeed214c27309877c89602943fa4b789f87d67fc0cce30a11",
"event": "SampleCrowdsaleE",
"args": [
"1"
]
}
]
and the order is the one you expect (again from the bottom to the top on the logs)
SampleCrowdsale
CappedCrowdsale
RefundableCrowdsale
FinalizableCrowdsale
TimedCrowdsale
MintedCrowdsale
IndividuallyCappedCrowdsale
TieredCrowdsale
Crowdsale
Ownable
The linearization in Solidity is from the right to the left instead of left to right as per wiki (used in Python). As the documentation states:
Solidity is similar to Python in that it uses “C3 Linearization” to
force a specific order in the DAG of base classes.
Especially, the order in which the base classes are given in the is
directive is important: You have to list the direct base contracts in
the order from “most base-like” to “most derived”. Note that this
order is different from the one used in Python. In the following code,
Solidity will give the error “Linearization of inheritance graph
impossible”.
My overall consideration is to make it as simple as possible to avoid that the multiple inheritance will be a pain and you encounter the yo-yo problem.
the linearization in Solidity is from the right to the left instead of left to right as per wiki. How should I updated the answer? I can't see any improvement to my answer in the github link. – qbsp May 04 '18 at 10:04