Account7702Diamond
Inherits: AccountDiamond
Title: Account7702Diamond
Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
Optional hardened EIP-7702 delegate (#58 item 7). The bare Diamond's ungated initialize is safe
only when onboarding is ATOMIC — the 7702 authorization bundled into the same transaction as the
first UserOp, which is the standard 4337+7702 flow. An EOA that instead applies the delegation in a
separate, earlier transaction and leaves itself uninitialized is exposed to a front-runner who can
initialize it with a hostile blueprint. Delegating to THIS contract closes that window: the
unauthenticated initialize is disabled, and onboarding requires the delegating EOA's signature
over the exact (cuts, init, calldata), bound to this account and chain.
A front-runner cannot forge the EOA's signature, so cannot substitute a hostile blueprint; replaying
the EOA's own signed onboarding only reproduces the intended state (init7702 sets owner = the EOA).
The residual is at most a failed first UserOp + retry, never account hijacking.
LEFTOVER STORAGE (EIP-7702 keeps storage across re-delegation): module state is ERC-7201
namespaced, but the initializer flag and diamond-lib's owner word sit in Solady's default
Initializable (0xff…bf601132) and Ownable (0xff…74873927) slots. An EOA earlier delegated to a
Solady-based account that left either slot non-zero cannot onboard: initializeAuthorized reverts
InvalidInitialization (the constructor-only exemption needs empty code, and a delegated EOA has
the delegation designator) or AlreadyInitialized (from AccountInit's initializeOwner). Clear
both slots first, via a delegate that zeroes them. Lattice's values likewise remain for the next
delegate. Namespacing these slots is deferred to a coordinated 1.0 change (#247).
Constants
_ONBOARD_TAG
Domain tag separating the onboarding digest from any other message the EOA might sign.
bytes32 private constant _ONBOARD_TAG = keccak256("Lattice.EIP7702.Onboard.v1");Functions
initialize
Disabled on this delegate — use initializeAuthorized so onboarding is bound to the EOA's key.
function initialize(FacetCut[] calldata, address, bytes calldata) public payable virtual override;Parameters
| Name | Type | Description |
|---|---|---|
| _ | FacetCut[] | |
| _ | address | |
| _ | bytes |
initializeAuthorized
Initializes the delegated EOA's storage, gated by the EOA's signature over the onboarding.
The initializer guard runs before signature verification — an already-initialized account
reverts InvalidInitialization regardless of signature validity.
function initializeAuthorized(
FacetCut[] calldata _facetCuts,
address _init,
bytes calldata _calldata,
bytes calldata _signature
) external payable virtual initializer;Parameters
| Name | Type | Description |
|---|---|---|
| _facetCuts | FacetCut[] | The facet cuts to apply. |
| _init | address | The initializer delegatecalled by diamondCut (e.g. AccountInit). |
| _calldata | bytes | The initializer calldata (e.g. AccountInit.init7702()). |
| _signature | bytes | The delegating EOA's ECDSA signature over onboardingDigest of the above. |
onboardingDigest
The digest the delegating EOA signs to authorize an onboarding. Bound to this account
(address(this)) and chain, so a signature cannot be replayed onto another account or chain.
function onboardingDigest(FacetCut[] calldata _facetCuts, address _init, bytes calldata _calldata)
public
view
returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| _facetCuts | FacetCut[] | |
| _init | address | |
| _calldata | bytes |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
Errors
UnauthorizedOnboarding
The provided onboarding signature did not recover to this account (the delegating EOA).
error UnauthorizedOnboarding();