Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/metal-ghosts-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@openzeppelin/wizard': patch
---

Add initializers to ERC-7579 non-upgradeable accounts
76 changes: 65 additions & 11 deletions packages/core/solidity/src/account.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,20 @@ Generated by [AVA](https://avajs.dev).
import {AccountERC7579} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579.sol";␊
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";␊
import {ERC7739} from "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol";␊
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";␊
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";␊
contract MyAccount is Account, EIP712, ERC7739, AccountERC7579 {␊
constructor(uint256 moduleTypeId, address module, bytes calldata initData)␊
EIP712("MyAccount", "1")␊
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579 {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
function initialize(uint256 moduleTypeId, address module, bytes calldata initData)␊
public␊
initializer␊
{␊
require(moduleTypeId == MODULE_TYPE_VALIDATOR || moduleTypeId == MODULE_TYPE_EXECUTOR);␊
_installModule(moduleTypeId, module, initData);␊
Expand Down Expand Up @@ -270,10 +279,21 @@ Generated by [AVA](https://avajs.dev).
import {Account} from "@openzeppelin/contracts/account/Account.sol";␊
import {AccountERC7579} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579.sol";␊
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";␊
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";␊
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";␊
contract MyAccount is Account, IERC1271, AccountERC7579 {␊
constructor(uint256 moduleTypeId, address module, bytes calldata initData) {␊
contract MyAccount is Initializable, Account, IERC1271, AccountERC7579 {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
function initialize(uint256 moduleTypeId, address module, bytes calldata initData)␊
public␊
initializer␊
{␊
require(moduleTypeId == MODULE_TYPE_VALIDATOR || moduleTypeId == MODULE_TYPE_EXECUTOR);␊
_installModule(moduleTypeId, module, initData);␊
}␊
Expand Down Expand Up @@ -311,11 +331,20 @@ Generated by [AVA](https://avajs.dev).
import {AccountERC7579} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579.sol";␊
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";␊
import {ERC7739} from "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol";␊
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";␊
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";␊
contract MyAccount is Account, EIP712, ERC7739, AccountERC7579 {␊
constructor(uint256 moduleTypeId, address module, bytes calldata initData)␊
EIP712("MyAccount", "1")␊
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579 {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
function initialize(uint256 moduleTypeId, address module, bytes calldata initData)␊
public␊
initializer␊
{␊
require(moduleTypeId == MODULE_TYPE_VALIDATOR || moduleTypeId == MODULE_TYPE_EXECUTOR);␊
_installModule(moduleTypeId, module, initData);␊
Expand Down Expand Up @@ -358,11 +387,20 @@ Generated by [AVA](https://avajs.dev).
import {AccountERC7579Hooked} from "@openzeppelin/contracts/account/extensions/draft-AccountERC7579Hooked.sol";␊
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";␊
import {ERC7739} from "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol";␊
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";␊
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";␊
contract MyAccount is Account, EIP712, ERC7739, AccountERC7579Hooked {␊
constructor(uint256 moduleTypeId, address module, bytes calldata initData)␊
EIP712("MyAccount", "1")␊
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579Hooked {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
function initialize(uint256 moduleTypeId, address module, bytes calldata initData)␊
public␊
initializer␊
{␊
require(moduleTypeId == MODULE_TYPE_VALIDATOR || moduleTypeId == MODULE_TYPE_EXECUTOR);␊
_installModule(moduleTypeId, module, initData);␊
Expand Down Expand Up @@ -699,6 +737,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579Upgradeable, UUPSUpgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -758,6 +798,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, IERC1271, AccountERC7579Upgradeable, UUPSUpgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -815,6 +857,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579Upgradeable, UUPSUpgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -876,6 +920,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579HookedUpgradeable, UUPSUpgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -1174,6 +1220,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579Upgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -1226,6 +1274,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, IERC1271, AccountERC7579Upgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -1276,6 +1326,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579Upgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down Expand Up @@ -1330,6 +1382,8 @@ Generated by [AVA](https://avajs.dev).
contract MyAccount is Initializable, Account, EIP712, ERC7739, AccountERC7579HookedUpgradeable {␊
/// @custom:oz-upgrades-unsafe-allow-reachable constructor␊
constructor() EIP712("MyAccount", "1") {␊
// Accounts are typically deployed and initialized as clones during their first user op,␊
// therefore, initializers are disabled for the implementation contract␊
_disableInitializers();␊
}␊
Expand Down
Binary file modified packages/core/solidity/src/account.test.ts.snap
Binary file not shown.
33 changes: 16 additions & 17 deletions packages/core/solidity/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,20 +189,15 @@ function addERC7579Modules(c: ContractBuilder, opts: AccountOptions): void {
'require(moduleTypeId == MODULE_TYPE_VALIDATOR || moduleTypeId == MODULE_TYPE_EXECUTOR);',
'_installModule(moduleTypeId, module, initData);',
];
if (opts.upgradeable) {
c.addParent({
name: 'Initializable',
path: '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol',
});
addLockingConstructorAllowReachable(c);
c.addParent({
name: 'Initializable',
path: '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol',
});
addLockingConstructorAllowReachableAccountFactory(c);

const fn = { name: 'initialize', kind: 'public' as const, args };
c.addModifier('initializer', fn);
c.setFunctionBody(body, fn);
} else {
for (const arg of args) c.addConstructorArgument(arg);
for (const line of body) c.addConstructorCode(line);
}
const fn = { name: 'initialize', kind: 'public' as const, args };
c.addModifier('initializer', fn);
c.setFunctionBody(body, fn);
}

// isValidSignature override
Expand Down Expand Up @@ -240,10 +235,7 @@ function addSignerInitializer(c: ContractBuilder, opts: AccountOptions): void {
: '@openzeppelin/contracts/proxy/utils/Initializable.sol',
});

addLockingConstructorAllowReachable(c, [
'// Accounts are typically deployed and initialized as clones during their first user op,',
'// therefore, initializers are disabled for the implementation contract',
]);
addLockingConstructorAllowReachableAccountFactory(c);

const fn = { name: 'initialize', kind: 'public' as const, args: signerArgs[opts.signer] };
c.addModifier('initializer', fn);
Expand Down Expand Up @@ -344,6 +336,13 @@ function overrideRawSignatureValidation(c: ContractBuilder, opts: AccountOptions
}
}

function addLockingConstructorAllowReachableAccountFactory(c: ContractBuilder): void {
addLockingConstructorAllowReachable(c, [
'// Accounts are typically deployed and initialized as clones during their first user op,',
'// therefore, initializers are disabled for the implementation contract',
]);
}

const functions = {
...defineFunctions({
isValidSignature: {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/solidity/src/signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function addLockingConstructorAllowReachable(c: ContractBuilder, bodyComm
if (!c.constructorCode.includes(disableInitializers)) {
c.addConstructorComment('/// @custom:oz-upgrades-unsafe-allow-reachable constructor');
bodyComments?.forEach(comment => c.addConstructorCode(comment));
c.addConstructorCode(disableInitializers);
c.addConstructorCode(`_disableInitializers();`);
}
}

Expand Down
Loading