diff --git a/README.md b/README.md index 4f72aca..d31ed19 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ await foo.x_get(); The plugin will also generate a constructor to initialize your abstract contracts. -For example, with this set of contracts: +For example, in this set of contracts notice that `C` is abstract because it doesn't call `B`'s constructor. ```solidity contract A { @@ -50,12 +50,14 @@ contract C is A, B { } ``` -The plugin generates the following exposed version of `C`. Notice how a parameter for `B` was added. +In the plugin-generated exposed version of `C`, there will be an additional parameter to initialize `B`. ```solidity contract XC is C { - constructor(uint256 c, uint256 b) C(c) B(b) {} + constructor(uint256 b, uint256 c) B(b) C(c) {} } ``` +The order of parameters in this generated constructor will be according to the linearization of the parent contracts, starting with the most base contract and ending with the most derived one. This order can be unintuitive, so in these cases make sure you test the contract was initialized as desired. + Note that if a contract is abstract because it's missing an implementation for a virtual function, the exposed contract will remain abstract too. diff --git a/contracts/Test.sol b/contracts/Test.sol index 6432cd1..7b30a1a 100644 --- a/contracts/Test.sol +++ b/contracts/Test.sol @@ -65,6 +65,13 @@ abstract contract Parent2 { constructor(uint y) {} } +abstract contract Parent3 { + constructor(uint z) {} +} + abstract contract Child1 is Parent1 {} abstract contract Child2 is Parent1, Parent2 {} abstract contract Child3 is Parent1, Parent2, Child2 {} +abstract contract Child4 is Parent1, Parent2, Parent3 { + constructor(uint c) {} +} diff --git a/src/core.ts b/src/core.ts index 68097be..b1942b8 100644 --- a/src/core.ts +++ b/src/core.ts @@ -124,7 +124,7 @@ function areFunctionsFullyImplemented(contract: ContractDefinition, contractMap: } function makeConstructor(contract: ContractDefinition, contractMap: ContractMap): string[] { - const parents = contract.linearizedBaseContracts.map(id => mustGet(contractMap, id)); + const parents = contract.linearizedBaseContracts.map(id => mustGet(contractMap, id)).reverse(); const parentsWithConstructor = parents.filter(c => getConstructor(c)?.parameters.parameters.length); const initializedParentIds = new Set(parents.flatMap(p => [ ...p.baseContracts.filter(c => c.arguments?.length).map(c => c.id),