From ba4ed95234e137bed8de3c134ce5d36c7aee1094 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Thu, 22 Jun 2023 19:40:36 +0300 Subject: [PATCH] AA-166: Change #1 - document semi-abstracted nonce --- EIPS/eip-4337.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-4337.md b/EIPS/eip-4337.md index aed3954178c61..acc0b64cc00b8 100644 --- a/EIPS/eip-4337.md +++ b/EIPS/eip-4337.md @@ -39,7 +39,7 @@ This proposal takes a different approach, avoiding any adjustments to the consen * **UserOperation** - a structure that describes a transaction to be sent on behalf of a user. To avoid confusion, it is not named "transaction". * Like a transaction, it contains "sender", "to", "calldata", "maxFeePerGas", "maxPriorityFee", "signature", "nonce" * unlike a transaction, it contains several other fields, described below - * also, the "nonce" and "signature" fields usage is not defined by the protocol, but by each account implementation + * also, the "signature" field usage is not defined by the protocol, but by each account implementation * **Sender** - the account contract sending a user operation. * **EntryPoint** - a singleton contract to execute bundles of UserOperations. Bundlers/Clients whitelist the supported entrypoint. * **Bundler** - a node (block builder) that bundles multiple UserOperations and create an EntryPoint.handleOps() transaction. Note that not all block-builders on the network are required to be bundlers @@ -51,7 +51,7 @@ To avoid Ethereum consensus changes, we do not attempt to create new transaction | Field | Type | Description | - | - | - | | `sender` | `address` | The account making the operation | -| `nonce` | `uint256` | Anti-replay parameter; also used as the salt for first-time account creation | +| `nonce` | `uint256` | Anti-replay parameter (see "Semi-abstracted Nonce Support" ) | | `initCode` | `bytes` | The initCode of the account (needed if and only if the account is not yet on-chain and needs to be created) | | `callData` | `bytes` | The data to pass to the `sender` during the main execution call | | `callGasLimit` | `uint256` | The amount of gas to allocate the main execution call | @@ -159,6 +159,59 @@ interface IAggregator { * **validateSignatures()** MUST validate the aggregated signature matches for all UserOperations in the array, and revert otherwise. This method is called on-chain by `handleOps()` +#### Semi-abstracted Nonce Support + +In Ethereum protocol, the sequential transaction `nonce` value is used as a replay protection method as well as to +determine the valid order of transaction being included in blocks. + +It also contributes to the transaction hash uniqueness, as a transaction by the same sender with the same +nonce may not be included in the chain twice. + +However, requiring a single sequential `nonce` value is limiting the senders' ability to define their custom logic +with regard to transaction ordering and replay protection. + +We are proposing to implement a nonce mechanism that uses a single `uint256` nonce value in the `UserOperation`, +but treats it as two values: + +* 192-bit "key" +* 64-bit "sequence" + +These values are represented on-chain as a member in the `EntryPoint` contract mapping: + +```solidity +mapping(address => mapping(uint192 => uint256)) public nonces; +``` + +For each `key` the `sequence` is validated and incremented sequentially and monotonically by the `EntryPoint` for +each UserOperation, however a new key can be introduced with an arbitrary value at any point. + +This approach maintains the guarantee of `UserOperation` hash uniqueness on-chain on the protocol level while allowing +wallets to implement any custom logic they may need operating on a 192-bit "key" field, while fitting the 32 byte word. +##### Usage examples + +1. Classic sequential nonce. + + In order to require the wallet to have classic, sequential nonce, the validation function should perform: + ```solidity + require(userOp.nonce> 64; + if (sig == ADMIN_METHODSIG) { + require(key == ADMIN_KEY, "wrong nonce-key for admin operation"); + } else { + require(key == 0, "wrong nonce-key for normal operation"); + } + ``` + #### Using signature aggregators An account signifies it uses signature aggregation returning its address from `validateUserOp`.