Skip to content
Merged
Show file tree
Hide file tree
Changes from 135 commits
Commits
Show all changes
140 commits
Select commit Hold shift + click to select a range
f5544fd
Add Account framework
ernestognw May 2, 2025
40dfd20
Add missing mocks
ernestognw May 2, 2025
0bcc521
Adding missing hardhat config
ernestognw May 2, 2025
7e75026
up
ernestognw May 2, 2025
5fb074c
Remove unnecessary files for mocks
ernestognw May 2, 2025
e5df541
Remove more unnecessary mock files
ernestognw May 2, 2025
5ad9788
replace hardcoded links
ernestognw May 2, 2025
7090f67
lockfile
ernestognw May 2, 2025
c4af1d7
update ethers
ernestognw May 2, 2025
aa8f29b
add missing interface
ernestognw May 2, 2025
415c00d
Add changesets
ernestognw May 2, 2025
f60aa3a
up
ernestognw May 2, 2025
087a844
up
ernestognw May 2, 2025
79629b7
up
ernestognw May 2, 2025
f47cab7
up
ernestognw May 2, 2025
8f58197
up
ernestognw May 2, 2025
ecede7f
up
ernestognw May 2, 2025
68bd96a
up
ernestognw May 2, 2025
d5cb119
chore: empty commit
ernestognw May 2, 2025
6a0ae8a
change read permissions
ernestognw May 2, 2025
a49a157
Update lucky-donuts-scream.md
ernestognw May 2, 2025
a634278
Update clean-ways-push.md
ernestognw May 2, 2025
8b6501a
Update tame-bears-mix.md
ernestognw May 2, 2025
39a1026
reset package-lock.json
ernestognw May 2, 2025
71a6b25
up
ernestognw May 2, 2025
35d4a12
up
ernestognw May 2, 2025
a95705b
reset dependencies
ernestognw May 2, 2025
90509bd
reset dependencies
ernestognw May 2, 2025
10f40d7
reset dependencies
ernestognw May 2, 2025
36fb044
lint
ernestognw May 2, 2025
f534243
Add ERC7913 signers and utilities
ernestognw May 2, 2025
c0e5e45
Add Account framework docs and guides
ernestognw May 2, 2025
7e10f80
Attempt to fix tests
ernestognw May 2, 2025
c6ed868
up
ernestognw May 2, 2025
b87c8e2
Merge branch 'master' into feature/account-abstraction
ernestognw May 2, 2025
f6d07c2
adjust action.yml
ernestognw May 2, 2025
cfa2392
up
ernestognw May 2, 2025
9a8e63f
Merge branch 'master' into feature/account-abstraction
ernestognw May 2, 2025
3a90091
lint
ernestognw May 2, 2025
bdec803
lint
ernestognw May 2, 2025
73c12c7
Merge branch 'master' into feature/account-abstraction
ernestognw May 2, 2025
1c97739
Test ethers 6.13.6-beta.1
ernestognw May 2, 2025
6b1bbd8
up
ernestognw May 2, 2025
7764515
up
ernestognw May 2, 2025
19fe4c5
up
ernestognw May 2, 2025
11c42c3
checks
ernestognw May 2, 2025
be68753
up
ernestognw May 2, 2025
f0a1155
build in slither
ernestognw May 2, 2025
c42a7fd
Update build command
ernestognw May 2, 2025
6e576ca
compile hardhat too
ernestognw May 2, 2025
593e879
revert slither changes
ernestognw May 2, 2025
c3f39a1
Remove package-lock.json to skip installing dependencies
ernestognw May 2, 2025
db76c3b
up
ernestognw May 2, 2025
8eebff0
Add @custom:stateless tag
ernestognw May 3, 2025
65fa7de
update upgradeable.patch
ernestognw May 3, 2025
abac3bd
fix conflicts
ernestognw May 3, 2025
7d120b9
rollback <package-version>
ernestognw May 3, 2025
02eccc1
update upgradeable.patch
ernestognw May 3, 2025
c39d5f5
Tweak workflows
ernestognw May 3, 2025
54f632a
Use Solidity 0.8.27 as default and set default EVM to prague
ernestognw May 3, 2025
58c794e
Adjust ERC2771Forwarder gas to avoid GasFloorMoreThanGasLimit
ernestognw May 3, 2025
6a60523
Remove console.log
ernestognw May 3, 2025
80edba8
Add EnumerableSetExtended and EnumerableMapExtended
ernestognw May 2, 2025
29c48d9
Fix lint and enable formatting after generation
ernestognw May 3, 2025
fae0a67
Add ERC7913 signers and utilities
ernestognw May 2, 2025
c6b299e
Merge branch 'feature/erc7913' into docs/account
ernestognw May 3, 2025
e412bd9
Add EnumerableSetExtended and EnumerableMapExtended
ernestognw May 2, 2025
f7f64ee
Add changeset and fix linting
ernestognw May 3, 2025
2c33b49
Merge branch 'master' into docs/account
ernestognw May 8, 2025
b0b70eb
Merge branch 'master' into feature/enumerable-extended
ernestognw Jun 2, 2025
b695659
Remove TODOs
ernestognw Jun 2, 2025
5c4fb88
Reset package-lock
ernestognw Jun 2, 2025
8f32638
Revert run.js
ernestognw Jun 2, 2025
b12ca61
Merge Enumerable{Set,Map}Extended into Enumerable{Set,Map}
Amxx Jun 2, 2025
45fa35f
Update scripts/generate/templates/Enumerable.opts.js
Amxx Jun 2, 2025
bec8059
clarification
Amxx Jun 2, 2025
0d7f9d0
speedup generation with selective linter
Amxx Jun 2, 2025
2376a45
update documentation
Amxx Jun 2, 2025
1e35eab
Merge master
ernestognw Jun 2, 2025
c275c03
Remove unnecesary code
ernestognw Jun 2, 2025
5975d79
Remove Bytes32x2
ernestognw Jun 2, 2025
9356599
Update .changeset/pink-dolls-shop.md
ernestognw Jun 2, 2025
86c2cb8
Remove unnecessary _hashes
ernestognw Jun 2, 2025
6898230
Simplify
ernestognw Jun 2, 2025
4e2bc70
Improve changesets
ernestognw Jun 2, 2025
2a1f503
remove unecessary import
Amxx Jun 2, 2025
326c466
Use Arrays.sol
ernestognw Jun 2, 2025
52ac908
Merge branch 'feature/enumerable-extended' into feature/erc7913
ernestognw Jun 3, 2025
6725618
up
ernestognw Jun 3, 2025
0cce4d5
up
ernestognw Jun 3, 2025
5c45ff0
Merge branch 'master' into feature/erc7913
Amxx Jun 3, 2025
80d8bd5
Merge branch 'master' into feature/erc7913
ernestognw Jun 3, 2025
30f3bfa
cleanup
ernestognw Jun 3, 2025
eab64f8
Remove EnumerableSetExtended usage
ernestognw Jun 3, 2025
e3dcc2b
Add tests
ernestognw Jun 3, 2025
3ac675d
Add changesets
ernestognw Jun 3, 2025
b20b017
Merge branch 'master' into feature/erc7913
ernestognw Jun 4, 2025
804ceea
Organize
ernestognw Jun 4, 2025
d0f5961
Review
ernestognw Jun 4, 2025
98108d9
Increase SignatureChecker's pragma
ernestognw Jun 4, 2025
906a805
Merge branch 'master' into docs/account
ernestognw Jun 4, 2025
1bfa65c
Fix
ernestognw Jun 4, 2025
1a9c074
Remove
ernestognw Jun 4, 2025
4135626
Merge branch 'feature/erc7913' into docs/account
ernestognw Jun 4, 2025
e1ffe05
Pragma consistency
ernestognw Jun 4, 2025
7070e39
Merge branch 'feature/erc7913' into docs/account
ernestognw Jun 4, 2025
709493e
Fix compilation
ernestognw Jun 4, 2025
91aeb92
Increase SignatureChecker minimum pragma to 0.8.24
ernestognw Jun 4, 2025
a1ca133
Update mocks
ernestognw Jun 4, 2025
6491896
Merge branch 'master' into docs/account
ernestognw Jun 4, 2025
7cf7b85
Merge branch 'master' into docs/account
ernestognw Jun 5, 2025
ce284c4
Merge branch 'master' into docs/account
ernestognw Jun 9, 2025
1567931
Minimize changes
ernestognw Jun 9, 2025
fd5ac83
up
ernestognw Jun 9, 2025
ca2284d
Merge branch 'master' into docs/account
ernestognw Jun 13, 2025
e636dcd
Merge branch 'master' into docs/account
ernestognw Jun 13, 2025
fd60f74
up
ernestognw Jun 13, 2025
de857b4
up
ernestognw Jun 13, 2025
5729b5a
fix compilation
ernestognw Jun 13, 2025
5099acb
do not transpile contracts/mocks/docs
Amxx Jun 16, 2025
cdd1f24
Merge branch 'master' into docs/account
Amxx Jun 18, 2025
f2f74f7
exclude accounts
ernestognw Jun 13, 2025
dc1927d
draft 7821
ernestognw Jun 18, 2025
14c79f9
Update transpile.sh
Amxx Jun 18, 2025
d4c461a
Move 7913 examples to .adoc file
ernestognw Jun 19, 2025
1180ed0
up
ernestognw Jun 19, 2025
fe88580
Merge branch 'master' into docs/account
Amxx Jun 19, 2025
645102d
Update transpile.sh
Amxx Jun 19, 2025
fa79cb0
up
ernestognw Jun 19, 2025
773d687
up
ernestognw Jun 19, 2025
4f98c5a
Update contracts/mocks/docs/account/MyFactoryAccount.sol
Amxx Jun 19, 2025
26d971a
Review suggestions
ernestognw Jun 20, 2025
e6fda11
Add userOpHash EIP-712 type explanation
ernestognw Jun 20, 2025
07a2ca0
nits
ernestognw Jun 20, 2025
9ce669f
Update factory
ernestognw Jun 20, 2025
613307d
up
ernestognw Jun 20, 2025
5b216ed
up
ernestognw Jun 20, 2025
47a1504
review suggestions
ernestognw Jun 20, 2025
1eeafd9
up
ernestognw Jun 20, 2025
86c2fa9
up
Amxx Jul 9, 2025
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
10 changes: 5 additions & 5 deletions contracts/account/extensions/draft-AccountERC7579.sol
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,11 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
*
* Requirements:
*
* * Module type must be supported. See {supportsModule}. Reverts with {ERC7579UnsupportedModuleType}.
* * Module must be of the given type. Reverts with {ERC7579MismatchedModuleTypeId}.
* * Module must not be already installed. Reverts with {ERC7579AlreadyInstalledModule}.
* * Module type must be supported. See {supportsModule}. Reverts with {ERC7579Utils-ERC7579UnsupportedModuleType}.
* * Module must be of the given type. Reverts with {ERC7579Utils-ERC7579MismatchedModuleTypeId}.
* * Module must not be already installed. Reverts with {ERC7579Utils-ERC7579AlreadyInstalledModule}.
*
* Emits a {ModuleInstalled} event.
* Emits a {IERC7579ModuleConfig-ModuleInstalled} event.
*/
function _installModule(uint256 moduleTypeId, address module, bytes memory initData) internal virtual {
require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId));
Expand Down Expand Up @@ -276,7 +276,7 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
*
* Requirements:
*
* * Module must be already installed. Reverts with {ERC7579UninstalledModule} otherwise.
* * Module must be already installed. Reverts with {ERC7579Utils-ERC7579UninstalledModule} otherwise.
*/
function _uninstallModule(uint256 moduleTypeId, address module, bytes memory deInitData) internal virtual {
require(supportsModule(moduleTypeId), ERC7579Utils.ERC7579UnsupportedModuleType(moduleTypeId));
Expand Down
20 changes: 20 additions & 0 deletions contracts/mocks/docs/account/MyAccountERC7702.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// contracts/MyAccountERC7702.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Account} from "../../../account/Account.sol";
import {ERC721Holder} from "../../../token/ERC721/utils/ERC721Holder.sol";
import {ERC1155Holder} from "../../../token/ERC1155/utils/ERC1155Holder.sol";
import {ERC7821} from "../../../account/extensions/draft-ERC7821.sol";
import {SignerERC7702} from "../../../utils/cryptography/signers/SignerERC7702.sol";

contract MyAccountERC7702 is Account, SignerERC7702, ERC7821, ERC721Holder, ERC1155Holder {
/// @dev Allows the entry point as an authorized executor.
function _erc7821AuthorizedExecutor(
address caller,
bytes32 mode,
bytes calldata executionData
) internal view virtual override returns (bool) {
return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData);
}
}
42 changes: 42 additions & 0 deletions contracts/mocks/docs/account/MyFactoryAccount.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// contracts/MyFactoryAccount.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {Clones} from "../../../proxy/Clones.sol";
import {Address} from "../../../utils/Address.sol";

/**
* @dev A factory contract to create accounts on demand.
*/
contract MyFactoryAccount {
using Clones for address;
using Address for address;

address private immutable _impl;

constructor(address impl_) {
require(impl_.code.length > 0);
_impl = impl_;
}

/// @dev Predict the address of the account
function predictAddress(bytes32 salt, bytes calldata callData) public view returns (address) {
return (_impl.predictDeterministicAddress(_saltedCallData(salt, callData), address(this)));
}

/// @dev Create clone accounts on demand
function cloneAndInitialize(bytes32 salt, bytes calldata callData) public returns (address) {
address predicted = predictAddress(salt, callData);
if (predicted.code.length == 0) {
_impl.cloneDeterministic(_saltedCallData(salt, callData));
predicted.functionCall(callData);
}
return predicted;
}

function _saltedCallData(bytes32 salt, bytes calldata callData) internal pure returns (bytes32) {
// Scope salt to the callData to avoid front-running the salt with a different callData
return keccak256(abi.encodePacked(salt, callData));
}
Copy link
Collaborator

@Amxx Amxx Jun 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is something interresting to notice when we pass arbitrary "initialize" calldata to the factory:
If we add more stuff after the abi encoded call (like a suffix), it won't be processed by the implementation (during initialization) but if will affect the hash. So technically, we can make the salt optional here and do

Suggested change
/// @dev Predict the address of the account
function predictAddress(bytes32 salt, bytes calldata callData) public view returns (address) {
return (_impl.predictDeterministicAddress(_saltedCallData(salt, callData), address(this)));
}
/// @dev Create clone accounts on demand
function cloneAndInitialize(bytes32 salt, bytes calldata callData) public returns (address) {
address predicted = predictAddress(salt, callData);
if (predicted.code.length == 0) {
_impl.cloneDeterministic(_saltedCallData(salt, callData));
predicted.functionCall(callData);
}
return predicted;
}
function _saltedCallData(bytes32 salt, bytes calldata callData) internal pure returns (bytes32) {
// Scope salt to the callData to avoid front-running the salt with a different callData
return keccak256(abi.encodePacked(salt, callData));
}
/// @dev Predict the address of the account
function predictAddress(bytes calldata callData) public view returns (address) {
return _impl.predictDeterministicAddress(keccak256(callData), address(this));
}
/// @dev Create clone accounts on demand
function cloneAndInitialize(bytes calldata callData) public returns (address) {
address predicted = predictAddress(callData);
if (predicted.code.length == 0) {
_impl.cloneDeterministic(keccak256(callData));
predicted.functionCall(callData);
}
return predicted;
}

If someone what to use a salt, they will "just" have to call cloneAndInitialize with
abi.encodePacked(abi.encodeCall(Account.intialize, (<...args...>)), salt);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question is, given that both versions have similar features, do we want:

  • a more simpler version, easy to read, but where some features are "hidden" (and optional)
  • a more complex version, harder to read, but where the extra feature are "in your face"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No strong preference, I think the factory is illustrative and the documentation already suggests some key considerations like "ensure the account address is deterministically tied to the initial owners". So all good with the current suggestion.

Overall I agree that an automated factory generation in Wizard must do the job better than this, and we may want to go for that option instead of a canonical factory in OZ contracts.

}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ abstract contract MultiSignerERC7913 is AbstractSigner {
*
* Requirements:
*
* * The {signers}'s length must be `>=` to the {threshold}. Throws {MultiSignerERC7913UnreachableThreshold} if not.
* * The {getSignerCount}'s length must be `>=` to the {threshold}. Throws {MultiSignerERC7913UnreachableThreshold} if not.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* * The {getSignerCount}'s length must be `>=` to the {threshold}. Throws {MultiSignerERC7913UnreachableThreshold} if not.
* * The {getSignerCount} must be greater or equal than to the {threshold}. Throws {MultiSignerERC7913UnreachableThreshold} if not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes the line too large, and not sure how to keep a single bullet point in 2 rows

*/
function _validateReachableThreshold() internal view virtual {
uint256 signersLength = _signers.length();
Expand Down
4 changes: 4 additions & 0 deletions contracts/utils/cryptography/signers/SignerERC7913.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import {SignatureChecker} from "../SignatureChecker.sol";
* function initialize(bytes memory signer_) public initializer {
* _setSigner(signer_);
* }
*
* function setSigner(bytes memory signer_) public onlyEntryPointOrSelf {
* _setSigner(signer_);
* }
* }
* ```
*
Expand Down
5 changes: 5 additions & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

* xref:access-control.adoc[Access Control]

* xref:account-abstraction.adoc[Account Abstraction]
** xref:accounts.adoc[Accounts]
*** xref:eoa-delegation.adoc[EOA Delegation]
*** xref:multisig.adoc[Multisig]

* xref:tokens.adoc[Tokens]
** xref:erc20.adoc[ERC-20]
*** xref:erc20-supply.adoc[Creating Supply]
Expand Down
100 changes: 100 additions & 0 deletions docs/modules/ROOT/pages/account-abstraction.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
= Account Abstraction

Unlike Externally Owned Accounts (EOAs), smart contracts may contain arbitrary verification logic based on authentication mechanisms different to Ethereum's native xref:api:utils.adoc#ECDSA[ECDSA] and have execution advantages such as batching or gas sponsorship. To leverage these properties of smart contracts, the community has widely adopted https://eips.ethereum.org/EIPS/eip-4337[ERC-4337], a standard to process user operations through an alternative mempool.

The library provides multiple contracts for Account Abstraction following this standard as it enables more flexible and user-friendly interactions with applications. Account Abstraction use cases include wallets in novel contexts (e.g. embedded wallets), more granular configuration of accounts, and recovery mechanisms.

== ERC-4337 Overview

The ERC-4337 is a detailed specification of how to implement the necessary logic to handle operations without making changes to the protocol level (i.e. the rules of the blockchain itself). This specification defines the following components:

=== UserOperation

A `UserOperation` is a higher-layer pseudo-transaction object that represents the intent of the account. This shares some similarities with regular EVM transactions like the concept of `gasFees` or `callData` but includes fields that enable new capabilities.

```solidity
struct PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode; // concatenation of factory address and factoryData (or empty)
bytes callData;
bytes32 accountGasLimits; // concatenation of verificationGas (16 bytes) and callGas (16 bytes)
uint256 preVerificationGas;
bytes32 gasFees; // concatenation of maxPriorityFee (16 bytes) and maxFeePerGas (16 bytes)
bytes paymasterAndData; // concatenation of paymaster fields (or empty)
bytes signature;
}
```

This process of bundling user operations involves several costs that the bundler must cover, including base transaction fees, calldata serialization, entrypoint execution, and paymaster context costs. To compensate for these expenses, bundlers use the `preVerificationGas` and `gasFees` fields to charge users appropriately.

NOTE: Estimating `preVerificationGas` is not standardized as it varies based on network conditions such as gas prices and the size of the operation bundle.

TIP: Use xref:api:account.adoc#ERC4337Utils[`ERC4337Utils`] to manipulate the `UserOperation` struct and other ERC-4337 related values.

=== Entrypoint

Each `UserOperation` is executed through a contract known as the https://etherscan.io/address/0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108#code[`EntryPoint`]. This contract is a singleton deployed across multiple networks at the same address although other custom implementations may be used.

The Entrypoint contracts is considered a trusted entity by the account.

=== Bundlers

The bundler is a piece of _offchain_ infrastructure that is in charge of processing an alternative mempool of user operations. Bundlers themselves call the Entrypoint contract's `handleOps` function with an array of UserOperations that are executed and included in a block.

During the process, the bundler pays for the gas of executing the transaction and gets refunded during the execution phase of the Entrypoint contract.

```solidity
/// @dev Process `userOps` and `beneficiary` receives all
/// the gas fees collected during the bundle execution.
function handleOps(
PackedUserOperation[] calldata ops,
address payable beneficiary
) external { ... }
```

=== Account Contract

The Account Contract is a smart contract that implements the logic required to validate a `UserOperation` in the context of ERC-4337. Any smart contract account should conform with the `IAccount` interface to validate operations.

```solidity
interface IAccount {
function validateUserOp(PackedUserOperation calldata, bytes32, uint256) external returns (uint256 validationData);
}
```

Similarly, an Account should have a way to execute these operations by either handling arbitrary calldata on its `fallback` or implementing the `IAccountExecute` interface:

```solidity
interface IAccountExecute {
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external;
}
```

NOTE: The `IAccountExecute` interface is optional. Developers might want to use xref:api:account.adoc#ERC7821[`ERC-7821`] for a minimal batched execution interface or rely on ERC-7579 or any other execution logic.

To build your own account, see xref:accounts.adoc[accounts].

=== Factory Contract

The smart contract accounts are created by a Factory contract defined by the Account developer. This factory receives arbitrary bytes as `initData` and returns an `address` where the logic of the account is deployed.

To build your own factory, see xref:accounts.adoc#accounts_factory[account factories].

=== Paymaster Contract

A Paymaster is an optional entity that can sponsor gas fees for Accounts, or allow them to pay for those fees in ERC-20 instead of native currency. This abstracts gas away of the user experience in the same way that computational costs of cloud servers are abstracted away from end-users.

To build your own paymaster, see https://docs.openzeppelin.com/community-contracts/0.0.1/paymasters[paymasters].

== Further notes

=== ERC-7562 Validation Rules

To process a bundle of `UserOperations`, bundlers call xref:api:account.adoc#Account-validateUserOp-struct-PackedUserOperation-bytes32-uint256-[`validateUserOp`] on each operation sender to check whether the operation can be executed. However, the bundler has no guarantee that the state of the blockchain will remain the same after the validation phase. To overcome this problem, https://eips.ethereum.org/EIPS/eip-7562[ERC-7562] proposes a set of limitations to EVM code so that bundlers (or node operators) are protected from unexpected state changes.

These rules outline the requirements for operations to be processed by the canonical mempool.

Accounts can access its own storage during the validation phase, they might easily violate ERC-7562 storage access rules in undirect ways. For example, most accounts access their public keys from storage when validating a signature, limiting the ability of having accounts that validate operations for other accounts (e.g. via ERC-1271)

TIP: Although any Account that breaks such rules may still be processed by a private bundler, developers should keep in mind the centralization tradeoffs of relying on private infrastructure instead of _permissionless_ execution.
Loading
Loading