Skip to content

Commit 01607b4

Browse files
authored
Omit missing initializer calls error for initializers named *_unchained (OpenZeppelin#1161)
1 parent 0d1eea7 commit 01607b4

File tree

4 files changed

+94
-1
lines changed

4 files changed

+94
-1
lines changed

.changeset/strong-guests-push.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openzeppelin/upgrades-core': patch
3+
---
4+
5+
Fix `Missing initializer calls` error when initializer name ends with `_unchained`

packages/core/contracts/test/ValidationsInitializer.sol

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,80 @@ contract Recursive_Ok is Parent {
629629
}
630630
}
631631

632+
// ==== Omitting validations of *_unchained for non-parent contracts ====
633+
634+
contract Parent_With_Unchained is Initializable {
635+
uint64 x;
636+
function __Parent_init() onlyInitializing internal {
637+
__Parent_init_unchained();
638+
}
639+
640+
function __Parent_init_unchained() onlyInitializing internal {
641+
x = 1;
642+
}
643+
}
644+
645+
contract Child_With_Unchained_Ok is Initializable, Parent_With_Unchained {
646+
uint64 y;
647+
function __Child_init() onlyInitializing internal {
648+
__Parent_init_unchained();
649+
__Child_init_unchained();
650+
}
651+
652+
function __Child_init_unchained() onlyInitializing internal {
653+
y = 1;
654+
}
655+
}
656+
657+
contract Child_Missing_Parent_Unchained_Call_Bad is Initializable, Parent_With_Unchained {
658+
uint64 y;
659+
function __Child_init() onlyInitializing internal {
660+
// missing call to __Parent_init_unchained
661+
__Child_init_unchained();
662+
}
663+
664+
function __Child_init_unchained() onlyInitializing internal {
665+
y = 1;
666+
}
667+
}
668+
669+
contract Child_Duplicate_Parent_Unchained_Call_Bad is Initializable, Parent_With_Unchained {
670+
uint64 y;
671+
function __Child_init() onlyInitializing internal {
672+
__Parent_init_unchained();
673+
__Parent_init_unchained();
674+
__Child_init_unchained();
675+
}
676+
677+
function __Child_init_unchained() onlyInitializing internal {
678+
y = 1;
679+
}
680+
}
681+
682+
contract Parent2_With_Unchained is Initializable {
683+
uint64 x2;
684+
function __Parent2_init() onlyInitializing internal {
685+
__Parent2_init_unchained();
686+
}
687+
688+
function __Parent2_init_unchained() onlyInitializing internal {
689+
x2 = 1;
690+
}
691+
}
692+
693+
contract Child_Wrong_Order_Parent_Unchained_Call_Warning is Initializable, Parent_With_Unchained, Parent2_With_Unchained {
694+
uint64 y;
695+
function __Child_init() onlyInitializing internal {
696+
__Child_init_unchained();
697+
__Parent2_init_unchained();
698+
__Parent_init_unchained();
699+
}
700+
701+
function __Child_init_unchained() onlyInitializing internal {
702+
y = 1;
703+
}
704+
}
705+
632706
// ==== Complex ERC20 examples ====
633707

634708
contract ERC20_Ok is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, ERC20PermitUpgradeable, ERC20FlashMintUpgradeable, UUPSUpgradeable {

packages/core/src/validate-initializers.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,17 @@ testRejects('Recursive_Bad', 'transparent', {
237237
});
238238
testAccepts('Recursive_Ok', 'transparent');
239239

240+
testAccepts('Child_With_Unchained_Ok', 'transparent');
241+
testRejects('Child_Missing_Parent_Unchained_Call_Bad', 'transparent', {
242+
contains: ['Missing initializer calls for one or more parent contracts: `Parent_With_Unchained`'],
243+
count: 1,
244+
});
245+
testRejects('Child_Duplicate_Parent_Unchained_Call_Bad', 'transparent', {
246+
contains: ['Duplicate calls found to initializer `__Parent_init_unchained` for contract `Parent_With_Unchained`'],
247+
count: 1,
248+
});
249+
testAccepts('Child_Wrong_Order_Parent_Unchained_Call_Warning', 'transparent'); // warn 'Expected: Parent_With_Unchained, Parent2_With_Unchained'
250+
240251
testAccepts('ERC20_Ok', 'uups');
241252
testRejects('ERC20_Bad', 'uups', {
242253
contains: [

packages/core/src/validate/run/initializer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,11 @@ function* getInitializerCallExceptions(
264264
}
265265
}
266266

267-
// Report any remaining parents that were not directly initialized
267+
// Report any remaining parents that were not directly initialized,
268+
// unless this initializer is named `*_unchained` since by design it doesn't need to call parent initializers
269+
const unchained = contractInitializer.name.endsWith('_unchained');
268270
if (
271+
!unchained &&
269272
remainingDirectCalls.length > 0 &&
270273
!skipCheck('missing-initializer-call', contractDef) &&
271274
!skipCheck('missing-initializer-call', contractInitializer)

0 commit comments

Comments
 (0)