Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AA-416: Create JSON-RPC API standard for RIP-7560 Native Account Abstraction #6

Closed
wants to merge 27 commits into from
Closed
Changes from 12 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
20300e8
Initial commit
forshtat Aug 13, 2024
e63c1f9
Initial addition of RIP-7560 specific JSON-RPC API methods
forshtat Aug 13, 2024
fae2ef6
Add some definitions
forshtat Aug 14, 2024
75f5687
Update erc-xxxx.md
forshtat Aug 15, 2024
595eb7a
Update ERCS/erc-xxxx.md
forshtat Aug 15, 2024
be81528
Update ERCS/erc-xxxx.md
forshtat Aug 15, 2024
7aee678
Update ERCS/erc-xxxx.md
forshtat Aug 15, 2024
8a469f7
Update erc-xxxx.md
forshtat Aug 15, 2024
7907ef9
Remove unnecessary list of existing transaction types
forshtat Aug 15, 2024
aa361b3
Fix reference to a removed method
forshtat Aug 15, 2024
b48ec44
Remove 'eth_signRip7560Transaction'; remove 'eth_traceRip7560Validati…
forshtat Aug 15, 2024
7430b1e
Remove 'validationLogsBloom' field
forshtat Aug 15, 2024
ad1327f
Update ERCS/erc-xxxx.md
forshtat Aug 15, 2024
060e251
Remove title & nesting levels
forshtat Aug 15, 2024
d3b30f2
Address PR comments
forshtat Aug 15, 2024
508a43a
Update ERCS/erc-xxxx.md
forshtat Aug 19, 2024
8c18587
AA-419: Rename parameters
forshtat Aug 19, 2024
e4726c2
Remove unnecessary 'contractAddress' field
forshtat Sep 8, 2024
8cf51dd
Explain fields optionality
forshtat Sep 10, 2024
fff8372
Remove 'status', add 'executionStatus'
forshtat Sep 10, 2024
6d6ff43
Mmove the `eth_getTransactionReceipt` description to core RIP-7560
forshtat Sep 10, 2024
1e71ff2
Remove transaction description table
forshtat Sep 10, 2024
8b0a2a7
update title
drortirosh Sep 10, 2024
23855ad
Grammar
shahafn Sep 10, 2024
4eaf77a
Rename to `eth_executeRip7560Transaction` to `eth_callRip7560Transact…
forshtat Sep 10, 2024
8013ecf
Fix
forshtat Sep 10, 2024
237cd9a
update call return value
drortirosh Sep 10, 2024
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
243 changes: 243 additions & 0 deletions ERCS/erc-xxxx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
---
eip: xxxx
title: JSON-RPC API for RIP-7560 Native Account Abstraction

Choose a reason for hiding this comment

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

Native AA Transaction

Choose a reason for hiding this comment

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

API exposed by NODE

drortirosh marked this conversation as resolved.
Show resolved Hide resolved
description: A set of JSON-RPC API methods that are required for a fully functional Native Account Abstraction protocol
author:
discussions-to:
status: Draft
type: Standards Track
category: ERC
created:
requires: RIP-7560, ERC-7562, EIP-7702
---

## Abstract

forshtat marked this conversation as resolved.
Show resolved Hide resolved
[RIP-7560](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7560.md) defines the new transaction type
and the modifications to the EVM needed for the Native Account Abstraction support.

However, there are a number of modifications to the Ethereum JSON-RPC API that is needed as well.
shahafn marked this conversation as resolved.
Show resolved Hide resolved
This proposal contains the full description of the new or modified APIs, and it would be highly beneficial
for the Native Account Abstraction ecosystem to implement these APIs in a standardised and compatible way.

## Motivation

Native Account Abstraction is expected to supersede [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337)
Copy link

Choose a reason for hiding this comment

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

I try not to use terms like "supersede". Native AA and 4337 are going to live alongside each other for a long time, and possibly forever if L1 doesn't adopt native AA. "supersede" might create the wrong impression that 4337 is going to be deprecated - which is not the case. How about "improve upon"?

by making all the benefits of Account Abstraction a core part of the protocol, bringing down the cost for the users,
enabling easy migration to post-quantum cryptography and eventually deprecation of Externally Owned Accounts altogether.

There are also some actions that are only applicable in the context of Native Account Abstraction,
which requires a creation of new JSON-RPC API methods.
shahafn marked this conversation as resolved.
Show resolved Hide resolved

## Specification

This document defines the API that the RIP-7560 compatible Ethereum nodes provide to either Smart Contract
Wallet applications or advanced dapps.
We define the following changes to the Ethereum JSON-RPC API:

### Definition of the RIP-7560 transaction type:

The following table represents a full list of fields of an RIP-7560 transaction:

Copy link

Choose a reason for hiding this comment

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

Move to 7560 along with tx receipt

| Name | Type | Description |
|-------------------------------|----------------|----------------------------------------------------------------|
| sender | DATA, 20 Bytes | Address of the Smart Contract Account making the transaction |
| deployer | DATA, 20 Bytes | Address of the Deployer - account factory contract |
| deployerData | DATA | Data that is provided to the Deployer contract |
| paymaster | DATA, 20 Bytes | Address of the Paymaster contract |
| paymasterData | DATA | Data that is provided to the Paymaster contract |
| callData | DATA | Data that is provided to the Account contract for execution |
| nonce | QUANTITY | A 256 bit nonce. Use of `nonce > 2^64` is defined in RIP-7712 |
| builderFee | QUANTITY | Value passed from sender or paymaster to the `coinbase` |
| maxPriorityFeePerGas | QUANTITY | The maximum gas price to be included as a tip to the validator |
| maxFeePerGas | QUANTITY | The maximum fee per unit of gas |
| validationGasLimit | QUANTITY | Gas provided for the transaction account validation frame |
| paymasterValidationGasLimit | QUANTITY | Gas provided for the transaction paymaster validation frame |
| paymasterPostOpGasLimit | QUANTITY | Gas provided for the transaction paymaster `postOp` frame |
| callGasLimit | QUANTITY | Gas provided for the transaction execution frame |
| accessList | OBJECT | An EIP-2930 compatible Access List structure |
| EIP-7702 authorizations (WIP) | ARRAY | An EIP-7702 compatible list of contracts injected into EOAs |
| signature | DATA | A signature of any kind used by Account to verify transaction |
Copy link

Choose a reason for hiding this comment

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

If we're renaming this to authData, remember to do it here as well. Ditto for callData above.


### Changes to the JSON-RPC API
forshtat marked this conversation as resolved.
Show resolved Hide resolved

#### Add RIP-7560 support for `eth_getTransactionReceipt`
forshtat marked this conversation as resolved.
Show resolved Hide resolved

For an RIP-7560 transaction included in a block, return also the values specific to this transaction type
Copy link

Choose a reason for hiding this comment

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

Move Receipt back to 7560

in addition to all the existing fields.

Parameters:

1. DATA, 32 Bytes - hash of a transaction

Returns:

1. OBJECT - A transaction receipt object, or `null` when no receipt was found:

Fields specific to an RIP-7560 transaction receipt:

| Name | Type | Description |
|----------------------------|-----------------|--------------------------------------------------------------------------------|
| sender | DATA, 20 Bytes | Address of the sender of this transaction |
| paymaster | DATA, 20 Bytes | Address of the Paymaster if it is paying for the transaction, `null` otherwise |
| deployer | DATA, 20 Bytes | Address of the Deployer if it is included in the transaction, `null` otherwise |
| senderCreationGasUsed | QUANTITY | The amount of gas actually used by the sender deployment frame |
| senderValidationGasUsed | QUANTITY | The amount of gas actually used by the sender validation frame |
| paymasterValidationGasUsed | QUANTITY | The amount of gas actually used by the paymaster validation frame |
| executionGasUsed | QUANTITY | The amount of gas actually used by the execution frame |
| postOpStatus | QUANTITY | 1 (success), 0 (failure), or `null` (did not run) status of the `postOp` frame |
| postOpGasUsed | QUANTITY | The amount of gas actually used by the paymaster `postOp` frame |
| validationLogs | ARRAY | Array of log objects, which this transaction'S VALIDATION FRAME generated. |

Choose a reason for hiding this comment

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

That's interesting.
its a way to report back events but not through a separate "pseudo tx".
still, I think that on-chain, it is a separate tx (e.g the txhash reported in each event)

Copy link
Author

Choose a reason for hiding this comment

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

We have discussed it and did not really reach consensus on how to present the validation phase through an RPC API. However, a separate transaction for a part of a transaction is a very breaking change and should be made very carefully.


Continued, these fields are shared by all transaction types:

| Name | Type | Value |
|-------------------|-----------------|--------------------------------------------------------------------------------------------|
| transactionHash | DATA, 32 Bytes | Hash of the transaction. |
| transactionIndex | QUANTITY | Integer of the transactions index position in the block. |
| blockHash | DATA, 32 Bytes | Hash of the block where this transaction was in. |
| blockNumber | QUANTITY | Block number where this transaction was in. |
| cumulativeGasUsed | QUANTITY | The total amount of gas used when this transaction was executed in the block. |
| effectiveGasPrice | QUANTITY | The sum of the base fee and tip paid per unit of gas. |
| gasUsed | QUANTITY | The amount of gas used by this specific transaction alone. |
| contractAddress | DATA, 20 Bytes | The contract address created, if the transaction was a contract creation, otherwise `null` |
Copy link

Choose a reason for hiding this comment

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

What does contract creation look like in this transaction type? In "normal" transactions this refers to a contract created by calling address(0) directly, so there can be only one. AA doesn't have an equivalent, as it's an operation performed by the account implementation. Are we going to use this for the actual account when deployed? (i.e. if the transaction had initcode, this address will be identical to sender, and if there's no initcode then it's empty)

Copy link
Author

Choose a reason for hiding this comment

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

This part of the table is copied over from a documentation for eth_getTransactionReceipt without modification, so I did not think about it.
About having a newly deployed sender address also in contractAddress, I don't know if it provides any useful information. It is already possible to check if there was a deployment frame by looking at senderCreationGasUsed value.
I have no strong feelings about this one way or the other.

Choose a reason for hiding this comment

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

afaik, we never add "contractAddress", at it is clearly spelled out in the TX itself ("sender" is always present)

| logs | ARRAY | Array of log objects, which this transaction'S EXECUTION FRAME generated. |
| logsBloom | DATA, 256 Bytes | Bloom filter for light clients to quickly retrieve related logs. |
| type | QUANTITY | Integer of the transaction type |
drortirosh marked this conversation as resolved.
Show resolved Hide resolved
| status | QUANTITY | Either 1 (success) or 0 (failure) status of the execution frame |

#### Create a new JSON-RPC API method `eth_executeRip7560Transaction`

Executes the entire RIP-7560 transaction in memory without broadcasting it or including it in a block.
forshtat marked this conversation as resolved.
Show resolved Hide resolved
Does not require the transaction to be properly signed, meaning it continues execution after either an account
or a paymaster contract make a `sigFailAccount` or `sigFailPaymaster` call.
If all frames execute successfully, simply returns the data returned by the top level frame of the execution phase.
If any of the validation or execution frames revers, returns an error object containing the revert message.
forshtat marked this conversation as resolved.
Show resolved Hide resolved
If the transaction validation fails for any reason other than the failed signature check,
returns an error object containing the details of the validation failure.

Parameters:

1. OBJECT - The RIP-7560 transaction object.
The `signature` field is optional.
2. QUANTITY | TAG - integer block number, or the string "latest", "earliest", "pending", "safe" or "finalized"

Returns:

DATA - The return value of the `sender` execution frame.

Choose a reason for hiding this comment

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

just wonder: do we need a way to check also signature?
The call returns with either "sigFailAccount" or "acceptAccount", but that information is not returned to the caller.
that would require a return object, e.g. {data: string, sigFail?:boolean }

drortirosh marked this conversation as resolved.
Show resolved Hide resolved

Error:

DATA - The revert data of the first reverted frame.
CODE - The error code indicating the type of error, which may include the entity that caused the revert on-chain.
MESSAGE - The human-readable error that may include a decoding of the `DATA` field if possible.

#### Add RIP-7560 support for all remaining transaction-level RPC APIs

This includes the following APIs: `eth_sendTransaction`, `eth_sendRawTransaction`, `eth_getTransactionByHash`,
Copy link

Choose a reason for hiding this comment

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

How would eth_sendTransaction work? The node is unaware of the account implementation and cannot generate a valid transaction for it. It exists in clients because historically people ran nodes and kept keys in their keystores, unlocking the account and transacting with it. Nowadays I think it's mostly used between the wallet and the dapp. Will the node implement it in some way?

Copy link
Author

Choose a reason for hiding this comment

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

In this case I thought it would basically mirror the eth_sendRawTransaction but without having to make an RLP encoding first. Meaning, all fields must be filled in, including signature a.k.a. authorizationData.
I would love us to define a dapp-wallet API as well but we would need to dedicate a lot of time to do it. As far as I understand, there isn't a final design for ERC-4337 as well, is that correct?

Choose a reason for hiding this comment

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

We overload the eth_sendTransaction for a different meaning, which is not good (the format - json object - is the same, but the usage is different)
So we need a new method name
e.g:
sendSignedTransaction or sendAATransaction
(or aa_sendTransaction ?)

Copy link
Author

Choose a reason for hiding this comment

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

I don't know if the ability to send an AA transaction as a JSON instead of an RLP-encoded byte array is worth adding a new API.
What do you think? Maybe, I should better remove the changes to eth_sendTransaction completely?

Copy link

Choose a reason for hiding this comment

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

Suggested change
This includes the following APIs: `eth_sendTransaction`, `eth_sendRawTransaction`, `eth_getTransactionByHash`,
This includes the following APIs: `eth_sendTransaction`, `eth_sendRawTransaction`, `eth_getTransactionByHash`, `eth_getTransactionReceipt`

`eth_getTransactionByBlockHashAndIndex`,
`eth_getTransactionByBlockNumberAndIndex`.

These methods have a very similar purpose and should support returning the new transaction type object.

Note that the "transaction index position" is determined by the position of the transaction's **validation frame**.

#### Create a new JSON-RPC API method `eth_estimateRip7560TransactionGas`

Performs a search for gas limit values required to make each of the frames of the RIP-7560 transaction execute
successfully and without running out of gas.
Note that for validation frames, only valid calls to an appropriate `AA_ENTRY_POINT` callback,
drortirosh marked this conversation as resolved.
Show resolved Hide resolved
such as `acceptAccount`, `acceptPaymaster`, `sigFailAccount` and `sigFailPaymaster`, is considered a success.

If it fails to find such a value, returns an error message with the detailed description of the failure reason.

Parameters:

1. OBJECT - The RIP-7560 transaction object.
The `validationGasLimit`, paymasterValidationGasLimit, `paymasterGasLimit` and `callGasLimit` fields are optional.
2. QUANTITY | TAG - integer block number, or the string "latest", "earliest", "pending", "safe" or "finalized"
3. OBJECT - State override set
The State Override Set option allows you to change the state of a contract before executing the call. This means you
can modify the values of variables stored in the contract, such as balances and approvals for that call without
actually modifying the contract on the blockchain.
This behavior is equivalent to the one defined for the `eth_call` RPC method.

Returns:

1. Object

| Name | Type |
|-----------------------------|----------|
| validationGasLimit | QUANTITY |

Choose a reason for hiding this comment

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

returned validation values are not "limits", but actual values.
(because of our validation rules, there's no need to do "bisection" on validation values at all: if they can't access the current "glass ceiling" gaslimit, they can't be affected by it, so we return actual gas, and that's enough gas gaslimit)

Copy link
Author

Choose a reason for hiding this comment

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

Validation rules are not part of RIP-7562, not part of this ERC, and are generally opt-in. We cannot define core features of the protocol recklessly because there are magic rules that protect us from anything going wrong.

| paymasterValidationGasLimit | QUANTITY |
| paymasterPostOpGasLimit | QUANTITY |

Choose a reason for hiding this comment

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

postOpGasLimit is not something we should estimate: estimating would suggest that this estimation should be used - but that's wrong.

  • We can calculate current value, but since it is not bound by opcode access, it can fail on different values.
  • TokenPaymasters (and others) might "batch" calculations (e.g. swap), so estimation might be far less than actual gas - and revert.
  • The entity that estimates is the account (sender), but the entity that pays is the paymaster, so the account has no incentive to do good estimation.
  • Bottom line: I think paymasters should provide a constant value (via off chain service), and validate that in their paymasterValidation, and not rely on estimation at all.

Copy link

Choose a reason for hiding this comment

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

Bottom line: I think paymasters should provide a constant value (via off chain service), and validate that in their paymasterValidation, and not rely on estimation at all.

What about paymasters that have no off-chain service? E.g. a TokenPaymaster that caches lastKnownPrice in postOp, or occasionally calls Uniswap to rebalance its eth? Where will the estimate come from in this case?

Copy link
Author

Choose a reason for hiding this comment

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

  1. Re: since it is not bound by opcode access, it can fail on different values - nothing is bound by opcode access. Opcode access is an opt-in protocol for bundlers, not part of the core protocol. Everything can fail all the time. This is exactly the situation with estimateGas in any other transaction type.
  2. Re: estimation might be far less than actual gas - and revert - well that would not be a legitimate behaviour for the Paymaster. Suddenly requiring a large amount of gas out of the blue should be banned. A Paymaster that might require a huge post op gas can force it by adding require(tx.postOpGasLimit > 1'000'000, "i need more gas") in the postOp. Estimation algorithm should figure that out. This is the way to provide a constant gas limit value, if needed.
  3. Re: The entity that estimates is the account - account is a smart contract and does not estimate anything. The Wallet Application calls the estimation. It is in the wallet's interest not to generate reverting transactions all the time.
  4. Re: not rely on estimation at all - well, I don't think this is a viable solution for a smart contract of any kind.

| callGasLimit | QUANTITY |

Error:

DATA - The revert data of the first reverted frame.
CODE - The error code indicating the type of error, which may include the entity that caused the revert on-chain.
MESSAGE - The human-readable error that may include a decoding of the `DATA` field if possible.

##### Notes on implementation details

As mentioned in the RIP-7560, the `sender` and `paymaster` contracts should not revert on the validation failure
and should make calls to `sigFailAccount` and `sigFailPaymaster` respectively
in order to support `eth_estimateRip7560TransactionGas`.

The recommended way to achieve this behavior for Smart Contract Accounts and Paymasters is to compare the `signature`
parameter to a predetermined "dummy signature" and to call a `sigFail` callback in case the values match.

#### Create a new JSON-RPC API method `eth_traceRip7560Validation`

Only executes the validation phase of the RIP-7560 transaction and returns the tracing results of this execution.
This is done in order to allow other clients to determine
whether all contracts used within the validation phase of this transaction are compliant with the rules
defined in the [ERC-7562](https://eips.ethereum.org/EIPS/eip-7562).

Parameters:

1. OBJECT - The RIP-7560 transaction object.
2. QUANTITY | TAG - a block number, or the string "earliest", "latest", "pending", "safe" or "finalized", as in the
default block parameter.

Returns:

1. OBJECT - the tracing result of executing the entire validation phase of the RIP-7560 transaction.\
The exact shape of the returned object is not strictly defined by this standard and can be decided
by different implementation.

### Error Codes
Copy link

Choose a reason for hiding this comment

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

If we do add this tracing RPC, doesn't it need to also return proper error codes when ERC-7562 rules are violated (so the transaction isn't even fully validated because it won't be accepted due to the 7562 violation)?

Copy link
Author

Choose a reason for hiding this comment

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

Currently, we have a tracer implemented in Go but the parser is still in TypeScript inside bundler, and this API is used by a bundler who gets the stack trace, parses it and finds ERC-7562 violations. So unless we implement parsing in Go we won't be able to return violation errors from the node yet.


* code: -32500 - transaction validation failed by `sender`.
The message field SHOULD be set to the revert message from the `sender`.
forshtat marked this conversation as resolved.
Show resolved Hide resolved

* code: -32501 - transaction validation failed by `paymaster`.
The message field SHOULD be set to the revert message from the `paymaster`.

* code: -32502 - transaction validation failed by `deployer`
The message field SHOULD be set to the revert message from the `deployer`.

* code: -32503 - Transaction out of time range.
The message field SHOULD include the requested time range and the current block timestamp.

## Rationale

### Creating `eth_executeRip7560Transaction` instead of modifying `eth_call`
Copy link

Choose a reason for hiding this comment

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

Suggested change
### Creating `eth_executeRip7560Transaction` instead of modifying `eth_call`
### Creating `eth_callRip7560Transaction` instead of modifying `eth_call`


The semantics of the `eth_call` are currently very simple for all existing transaction types, and would become
significantly more complex with the addition of the RIP-7560 transaction type support.

It seems like the difference between these transaction types warrants a separate standalone RPC API method.
Copy link

Choose a reason for hiding this comment

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

I agree. But where will it be defined if not here?

Copy link
Author

Choose a reason for hiding this comment

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

This comment relates to the eth_executeRip7560Transaction API that is defined in this ERC.


## Security Considerations

The RPC API methods standard described in this document does not have any consequences for the security of the
Native Account Abstraction ecosystem.

The implementations of these APIs, especially the ones related to generating a `signature` for a transaction,
must be extremely careful when handling the Smart Contract Accounts' credentials.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
Loading