Skip to content

Commit

Permalink
AA-166: Change #1 - document semi-abstracted nonce
Browse files Browse the repository at this point in the history
  • Loading branch information
forshtat committed Jun 22, 2023
1 parent a5f5490 commit ba4ed95
Showing 1 changed file with 55 additions and 2 deletions.
57 changes: 55 additions & 2 deletions EIPS/eip-4337.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 |
Expand Down Expand Up @@ -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<type(uint64).max)
```

2. Ordered administrative events

In some cases, an account may need to have an "administrative" channel of operations running in parallel to normal
operations.

In this case, the account may use specific `key` when calling methods on the account itself:
```solidity
bytes4 sig = bytes4(userOp.callData[0 : 4]);
uint key = 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`.
Expand Down

0 comments on commit ba4ed95

Please sign in to comment.