From 9bce66394433418223bf7115b53e2020051728db Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 11:18:37 -0800 Subject: [PATCH 01/13] Create erc-intent-7702.md --- ERCS/erc-intent-7702.md | 159 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 ERCS/erc-intent-7702.md diff --git a/ERCS/erc-intent-7702.md b/ERCS/erc-intent-7702.md new file mode 100644 index 0000000000..83cfabf382 --- /dev/null +++ b/ERCS/erc-intent-7702.md @@ -0,0 +1,159 @@ +--- +eip: tbd +title: Minimal intent-centric EOA smart account standard +description: Minimal effort intent-centric standard interfaces for EOA accounts with contract code (EIP-7702) to support account abstraction features +author: hellohanchen (@hellohanchen) +discussions-to: https://ethereum-magicians.org/t/erc-intent-7702-minimal-intent-centric-eoa-smart-account-standard/21565 +status: Draft +type: Standards Track +category: ERC +created: 2024-11-02 +requires: EIP-7702 +--- + +## Abstract +This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. + +# Motivation +AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: +* **BatchExecution** +* **GasSponsorship** +* **AccessControl** + +With [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337), engineers built a permissionless AA standard. While unlocking enormous number of useful features, ERC-4337 still has several limitations: + +* **Complexity**: Requiring multiple components: Account, EntryPoint, Paymaster, Bundler, and Plugins ([ERC-6900](https://eips.ethereum.org/EIPS/eip-6900), [ERC-7579](https://eips.ethereum.org/EIPS/eip-7579)). Services like bundler has a high original cost and requires high engineer skills to run and maintain. +* **Compatibility**: Compatibility issue between components forces developers to upgrade multiple smart contracts within one version update +* **Cost**: `UserOperation` processing costs high gas units +* **Trust**: Although this standard is designed to be permissionless, there are still centralized processes. Paymaster is usually a centralized service because it needs to either trust the account owner to payback the sponsored gas or the transaction is beneficial for Paymaster. Bundlers are running on MEV based and accounts need to trust bundler providers. + +[ERC-7521](https://eips.ethereum.org/EIPS/eip-7521) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. + +With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. + +The above EIPs inspired the author to build an intent-centric standard for EIP-7702 smart accounts. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +### UserIntent struct +`UserIntent` is a packed data structure defining the intents of executing a transaction. + +| Field | Type | Description | +|----------------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `sender` | `address` | The wallet making the intent | +| `standard` | `address` | The `IStandard` implementation to validate and parse this `UserIntent` | +| `header` | `bytes` | The metadata of this `UserIntent`, used by `standard`, using `bytes` type to keep flexibility | +| `instructions` | `bytes[]` | The detailed content of this `UserIntent`, used by `standard` to determine the `Operation`s need to be executing, using `bytes` type to keep flexibility | +| `signatures` | `bytes[]` | Validatable signatures, used by `standard` | + +### IStandard interface +The above `standard` means how to parse and validate an `UserIntent`, it implements the following `IStandard` interface: + +```solidity +interface IStandard { + /** + * Validate user's intent + * @dev returning validation result, the type uses bytes4 for extensibility purpose + * @return result: values representing validation outcomes + */ + function validateUserIntent(UserIntent calldata intent) external returns (bytes4 result); + + /** + * Unpack user's intent + * @dev returning validation result, the type uses bytes for extensibility purpose + * @return header: metadata of the unpacked instructions + * @return instructions: unpacked instructions, NOT REQUIRED to match UserIntent.instructions + */ + function unpackUserIntent(UserIntent calldata intent) external returns (bytes header, bytes[] instructions); +} +``` +Notice that `IStandard` fully controls the validation process, so similar as `EntryPoint` in ERC-4337 and ERC-7521, each `standard` MUST be pre-audited and SHOULD NOT be upgradable. + +### IAccount interface +On the `account` side, `IAccount` is the interface to execute `UserIntent`: +```solidity +interface IAccount { + /** + * Execute user's intent + * @dev returning execution result, the type uses bytes4 for extensibility purpose + * @return result: values representing execution outcomes + */ + function executeUserIntent(UserIntent calldata intent) external returns (bytes result); +} +``` +Following EIP-7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. + +It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, here is a very simple example: +```solidity +abstract contract StandardAccount is IAccount { + IStandard _myStandard = IStandard("0xstandard"); + + function executeUserIntent(UserIntent calldata intent) external returns (bytes result) { + require(intent.standard == address(_myStandard), "invalid standard"); + bytes4 validationResult = _myStandard.validateUserIntent(intent); + require(validationResult == MAGIC_VALUE, "validation failed"); + + (bytes header, bytes[] instructions) = _myStandard.unpackUserIntent(intent); + + // continue execution using header and instructions ... + } +} +``` + +`account` MAY be implemented as a stateless smart contract. + +### Usage of Bytes +There are many objects defined with `bytes` type for extensibility, future-compatibility purpose. All those objects are optional and their usages depends on `standard`. For the `UserIntent` struct: + +* `UserIntent.header`: The `UserIntent.header` can carry information about how to validate the intent or how to prevent double-spending. For example, let `UserIntent.header` be an `uint256 nonce` and the `standard` can check if the `nonce` is used already. +* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified ERC20 token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. +* `UserIntent.signatures`: These `signatures` can support different signing methods. It is NOT REQUIRED that all `signatures` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. + +## Rationale + +> The main challenge with a generalized intent standard is being able to adapt to the evolving world of intents. Users need to have a way to express their intents in a seamless way without having to make constant updates to their smart contract wallets. --- ERC-7521 + +The interface designs proposed in this EIP is inspired by ERC-7521, and the author tries to avoid turning EIP into a real implementation. + +### Execution in EOA contract code +EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: +* Aligned with the nature of EOA that the execution is fully controlled by the account owner. EOA owner can easily turn off all smart contract features by un-delegating the contract code. +* `msg.sender` is always EOA address +* Execution code can be stateless, this allows `account` to store no state data. + +In the case that the EOA doesn't need to execute its contract code, or the intent cost is too high. The owner can use the account as EOA. + +### Validation in standard contract +Validation logic commonly relies on contract state, for example, weighted multi-owner signature needs to track the weight of each signer. Keeping the functionality of intent validate purely inside `IStandard` makes it similar to the `EntryPoint` concept in ERC-4337, but a simpler version. Standard only taking responsibility of validation makes it easier for contract engineer to build, audit and maintain. + +Also, the `IStandard` interface can be considered as "modular". There can be a "compound" standard that breaks `UserIntent` into smaller pieces and call other standards to validate each piece and later combine the results together. + +### Gas abstraction defined in standard +This EIP enables standard to use content stored in `UserIntent.header` to define the "reward" of solving this intent. For example, `UserIntent.header` can contain `(erc20TokenAddress, amount)` and the standard can convert this into an instruction to send these tokens to the `tx.origin` and returns this instruction through `unpackInstruction` ABI. + +### Auditability of both validation and execution +It is very important both the standard and account implementation can be publicly audited and shared. The most important reason is security. And this can also help mediate the compatibility issues between standard and account. + +### Solver is relayer, relayer is paymaster, paymaster is bundler +Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. EIP-7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. + +Each solver needs to develop its own strategy to maximize its profit. And this EIP doesn't define anything about how a solver executes the intents, meaning there is no limitation. + +### Intents can be rewarded, repeatable +And another fact, which is easy to be ignored, is that intent has value by itself. For example, if an EOA is always willing to swap 1000 USDC to 1000 USDT and vice versa, this EOA will be considered as a "liquidity provider" in the market. The account can send the signed intent to exchanges and make the exchange reward the account every time the intent is executed. + +## Backwards Compatibility +This EIP shares the same backwards compatibility issue as EIP-7702. This EIP is not compatible with ERC-7521. + +## Reference Implementation +To be added + +## Security Considerations +This is mainly controlled by the standard and account implementation to make sure the account is safe. Solver needs to responsible for its own security when executing intents. + +More discussion needed. + +## Copyright +Copyright and related rights waived via [CC0](../LICENSE.md). From a1dcc764d527f7b68bfb8121e8b1f5326d025793 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 15:30:51 -0800 Subject: [PATCH 02/13] Assigned ERC --- ERCS/{erc-intent-7702.md => erc-7806.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename ERCS/{erc-intent-7702.md => erc-7806.md} (98%) diff --git a/ERCS/erc-intent-7702.md b/ERCS/erc-7806.md similarity index 98% rename from ERCS/erc-intent-7702.md rename to ERCS/erc-7806.md index 83cfabf382..ef8e3a0e5f 100644 --- a/ERCS/erc-intent-7702.md +++ b/ERCS/erc-7806.md @@ -1,9 +1,9 @@ --- eip: tbd -title: Minimal intent-centric EOA smart account standard +title: Minimal intent-centric EOA smart account description: Minimal effort intent-centric standard interfaces for EOA accounts with contract code (EIP-7702) to support account abstraction features author: hellohanchen (@hellohanchen) -discussions-to: https://ethereum-magicians.org/t/erc-intent-7702-minimal-intent-centric-eoa-smart-account-standard/21565 +discussions-to: https://ethereum-magicians.org/t/erc-7806-minimal-intent-centric-eoa-smart-account/21565 status: Draft type: Standards Track category: ERC From 9f6d85eaac02397a6b654c213e51cd1e90fc67bf Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 15:31:45 -0800 Subject: [PATCH 03/13] Update erc-7806.md --- ERCS/erc-7806.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index ef8e3a0e5f..ebb5d9359a 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -1,5 +1,5 @@ --- -eip: tbd +eip: 7806 title: Minimal intent-centric EOA smart account description: Minimal effort intent-centric standard interfaces for EOA accounts with contract code (EIP-7702) to support account abstraction features author: hellohanchen (@hellohanchen) From 535adcedccdc486c67dda39dd3ccd49ceeb5b197 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:02:07 -0800 Subject: [PATCH 04/13] Add examples --- ERCS/erc-7806.md | 204 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 161 insertions(+), 43 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index ebb5d9359a..2beba09b89 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -11,7 +11,7 @@ created: 2024-11-02 requires: EIP-7702 --- -## Abstract +# Abstract This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. # Motivation @@ -33,11 +33,11 @@ With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, The above EIPs inspired the author to build an intent-centric standard for EIP-7702 smart accounts. -## Specification +# Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -### UserIntent struct +## UserIntent struct `UserIntent` is a packed data structure defining the intents of executing a transaction. | Field | Type | Description | @@ -48,7 +48,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S | `instructions` | `bytes[]` | The detailed content of this `UserIntent`, used by `standard` to determine the `Operation`s need to be executing, using `bytes` type to keep flexibility | | `signatures` | `bytes[]` | Validatable signatures, used by `standard` | -### IStandard interface +## IStandard interface The above `standard` means how to parse and validate an `UserIntent`, it implements the following `IStandard` interface: ```solidity @@ -56,68 +56,51 @@ interface IStandard { /** * Validate user's intent * @dev returning validation result, the type uses bytes4 for extensibility purpose - * @return result: values representing validation outcomes + * @return result values representing validation outcomes */ - function validateUserIntent(UserIntent calldata intent) external returns (bytes4 result); + function validateUserIntent(UserIntent calldata intent) external returns (bytes4); /** * Unpack user's intent * @dev returning validation result, the type uses bytes for extensibility purpose - * @return header: metadata of the unpacked instructions - * @return instructions: unpacked instructions, NOT REQUIRED to match UserIntent.instructions + * @return header metadata of the unpacked instructions + * @return instructions unpacked instructions, NOT REQUIRED to match UserIntent.instructions */ - function unpackUserIntent(UserIntent calldata intent) external returns (bytes header, bytes[] instructions); + function unpackOperations(UserIntent calldata intent) external returns (bytes memory, bytes[] memory); } ``` Notice that `IStandard` fully controls the validation process, so similar as `EntryPoint` in ERC-4337 and ERC-7521, each `standard` MUST be pre-audited and SHOULD NOT be upgradable. -### IAccount interface +## IAccount interface On the `account` side, `IAccount` is the interface to execute `UserIntent`: ```solidity interface IAccount { /** * Execute user's intent * @dev returning execution result, the type uses bytes4 for extensibility purpose - * @return result: values representing execution outcomes + * @return result values representing execution outcomes */ - function executeUserIntent(UserIntent calldata intent) external returns (bytes result); + function executeUserIntent(UserIntent calldata intent) external returns (bytes memory); } ``` Following EIP-7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. -It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, here is a very simple example: -```solidity -abstract contract StandardAccount is IAccount { - IStandard _myStandard = IStandard("0xstandard"); - - function executeUserIntent(UserIntent calldata intent) external returns (bytes result) { - require(intent.standard == address(_myStandard), "invalid standard"); - bytes4 validationResult = _myStandard.validateUserIntent(intent); - require(validationResult == MAGIC_VALUE, "validation failed"); - - (bytes header, bytes[] instructions) = _myStandard.unpackUserIntent(intent); - - // continue execution using header and instructions ... - } -} -``` - -`account` MAY be implemented as a stateless smart contract. +It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, check **Reference Implmentation** for examples. `account` MAY be implemented as a stateless smart contract. -### Usage of Bytes +## Usage of Bytes There are many objects defined with `bytes` type for extensibility, future-compatibility purpose. All those objects are optional and their usages depends on `standard`. For the `UserIntent` struct: * `UserIntent.header`: The `UserIntent.header` can carry information about how to validate the intent or how to prevent double-spending. For example, let `UserIntent.header` be an `uint256 nonce` and the `standard` can check if the `nonce` is used already. * `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified ERC20 token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. * `UserIntent.signatures`: These `signatures` can support different signing methods. It is NOT REQUIRED that all `signatures` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. -## Rationale +# Rationale > The main challenge with a generalized intent standard is being able to adapt to the evolving world of intents. Users need to have a way to express their intents in a seamless way without having to make constant updates to their smart contract wallets. --- ERC-7521 The interface designs proposed in this EIP is inspired by ERC-7521, and the author tries to avoid turning EIP into a real implementation. -### Execution in EOA contract code +## Execution in EOA contract code EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: * Aligned with the nature of EOA that the execution is fully controlled by the account owner. EOA owner can easily turn off all smart contract features by un-delegating the contract code. * `msg.sender` is always EOA address @@ -125,35 +108,170 @@ EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings so In the case that the EOA doesn't need to execute its contract code, or the intent cost is too high. The owner can use the account as EOA. -### Validation in standard contract +## Validation in standard contract Validation logic commonly relies on contract state, for example, weighted multi-owner signature needs to track the weight of each signer. Keeping the functionality of intent validate purely inside `IStandard` makes it similar to the `EntryPoint` concept in ERC-4337, but a simpler version. Standard only taking responsibility of validation makes it easier for contract engineer to build, audit and maintain. Also, the `IStandard` interface can be considered as "modular". There can be a "compound" standard that breaks `UserIntent` into smaller pieces and call other standards to validate each piece and later combine the results together. -### Gas abstraction defined in standard +## Gas abstraction defined in standard This EIP enables standard to use content stored in `UserIntent.header` to define the "reward" of solving this intent. For example, `UserIntent.header` can contain `(erc20TokenAddress, amount)` and the standard can convert this into an instruction to send these tokens to the `tx.origin` and returns this instruction through `unpackInstruction` ABI. -### Auditability of both validation and execution +## Auditability of both validation and execution It is very important both the standard and account implementation can be publicly audited and shared. The most important reason is security. And this can also help mediate the compatibility issues between standard and account. -### Solver is relayer, relayer is paymaster, paymaster is bundler +## Solver is relayer, relayer is paymaster, paymaster is bundler Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. EIP-7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. Each solver needs to develop its own strategy to maximize its profit. And this EIP doesn't define anything about how a solver executes the intents, meaning there is no limitation. -### Intents can be rewarded, repeatable +## Intents can be rewarded, repeatable And another fact, which is easy to be ignored, is that intent has value by itself. For example, if an EOA is always willing to swap 1000 USDC to 1000 USDT and vice versa, this EOA will be considered as a "liquidity provider" in the market. The account can send the signed intent to exchanges and make the exchange reward the account every time the intent is executed. -## Backwards Compatibility +# Backwards Compatibility This EIP shares the same backwards compatibility issue as EIP-7702. This EIP is not compatible with ERC-7521. -## Reference Implementation -To be added +# Reference Implementation + +## Standard +A ICS (Intent Centric Standard) that checks nonce and timestamp of an intent, the instructions are just `(address, uint256, bytes)` tuples +representing a call to a contract. The relayer will be rewards with ERC20 token. +```solidity +contract ICS1 is IStandard { + using ECDSA for bytes32; + + string public constant ICS_NUMBER = "ICS1"; + string public constant NAME = "Direct Execution Standard with Expiration, Nonce and ERC20 Reward"; + string public constant VERSION = "0.0.0"; + string public constant AUTHOR = "hellohanchen"; + + bytes4 public constant VALIDATION_APPROVED = 0x00000001; + bytes4 public constant VALIDATION_DENIED = 0x00000000; + uint256 public constant MAX_INSTRUCTIONS = 256; + bytes4 public constant ERC20_TRANSFER_SELECTOR = IERC20.transfer.selector; + + mapping(address => mapping(uint256 => bool)) internal _nonces; + + function validateUserIntent(UserIntent calldata intent) external returns (bytes4) { + if (intent.instructions.length > MAX_INSTRUCTIONS) { + return VALIDATION_DENIED; // too many instructions + } + + (bool validated, uint256 nonce, uint256 timestamp, address tokenAddress, uint256 amount) = this.decodeHeader(intent.header); + if (!validated) { + return VALIDATION_DENIED; // invalid header + } + + if (timestamp < block.timestamp) { + return VALIDATION_DENIED; // expired intent + } + + if (_nonces[intent.sender][nonce]) { + return VALIDATION_DENIED; // used nonce + } + + if (intent.signatures.length != 1) { + return VALIDATION_DENIED; // invalid signature + } + + try IERC20(tokenAddress).totalSupply() { + // TODO: validate sender balance + } catch { + return VALIDATION_DENIED; + } + + bytes32 intentHash = keccak256(abi.encode(intent.header, intent.standard, intent.instructions, block.chainid)); + bytes32 messageHash = intentHash.toEthSignedMessageHash(); + + if (intent.sender != messageHash.recover(intent.signatures[0])) { + return VALIDATION_DENIED; // invalid signature + } + + return VALIDATION_APPROVED; + } + + function unpackOperations(UserIntent calldata intent) external returns (bytes memory, bytes[] memory) { + (bool validated, uint256 nonce, , address tokenAddress, uint256 amount) = this.decodeHeader(intent.header); + if (!validated) { + return (abi.encodePacked(VALIDATION_DENIED), new bytes[](0)); // invalid header + } + + bytes[] memory unpackedInstructions = new bytes[](intent.instructions.length + 2); + + for (uint256 i = 0; i < intent.instructions.length; i++) { + unpackedInstructions[i] = intent.instructions[i]; + } + + address relayer = tx.origin; + bytes memory transferCallData = abi.encodeWithSelector(ERC20_TRANSFER_SELECTOR, relayer, amount); + bytes memory transferInstruction = abi.encode(tokenAddress, uint256(0), transferCallData); + unpackedInstructions[intent.instructions.length] = transferInstruction; + + bytes memory nonceCallData = abi.encodeWithSelector(this.markNonce.selector, nonce); + bytes memory nonceInstruction = abi.encode(address(this), 0, nonceCallData); + unpackedInstructions[intent.instructions.length + 1] = nonceInstruction; + + return (abi.encodePacked(VALIDATION_APPROVED), unpackedInstructions); + } + + function decodeHeader(bytes calldata header) external pure returns (bool, uint256, uint256, address, uint256) { + if (header.length != 128) { + return (false, 0, 0, address(0), 0); + } + + (uint256 nonce, uint256 timestamp, address tokenAddress, uint256 amount) = abi.decode(header, (uint256, uint256, address, uint256)); + + return (true, nonce, timestamp, tokenAddress, amount); + } + + function markNonce(uint256 nonce) external { + _nonces[msg.sender][nonce] = true; + } +} +``` + +## Account +An `IAccount` implementation that support batch execution. +```solidity +contract BatchExecuteAccount is IAccount { + bytes4 public constant VALIDATION_APPROVED = 0x00000001; + + function executeUserIntent(UserIntent calldata intent) external returns (bytes memory) { + require(intent.sender == address(this), "intent sender is not this account"); + IStandard standard = IStandard(intent.standard); + + bytes4 validationResult = standard.validateUserIntent(intent); + require(validationResult == VALIDATION_APPROVED, "validation failed"); + + (, bytes[] memory instructions) = standard.unpackOperations(intent); + _executeBatch(instructions); + + return new bytes(0); + } + + function _executeBatch(bytes[] memory instructions) internal { + for (uint256 i = 0; i < instructions.length; i++) { + _execute(instructions[i]); + } + } + + function _execute(bytes memory instruction) internal { + (address dest, uint256 value, bytes memory data) = abi.decode(instruction, (address, uint256, bytes)); + + (bool success, bytes memory result) = dest.call{value: value, gas: gasleft()}(data); + if (!success) { + assembly { + revert(add(result, 32), result) + } + } + } +} + +``` -## Security Considerations +# Security Considerations This is mainly controlled by the standard and account implementation to make sure the account is safe. Solver needs to responsible for its own security when executing intents. More discussion needed. -## Copyright +# Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From f06f03c82afe4da3c7f2e4637711c83f33e6ad02 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:07:51 -0800 Subject: [PATCH 05/13] Fix md --- ERCS/erc-7806.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 2beba09b89..9b975fe767 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -1,14 +1,14 @@ --- eip: 7806 title: Minimal intent-centric EOA smart account -description: Minimal effort intent-centric standard interfaces for EOA accounts with contract code (EIP-7702) to support account abstraction features +description: Minimal effort intent-centric interfaces for EOA accounts with contract code (EIP-7702) to support account abstraction features author: hellohanchen (@hellohanchen) discussions-to: https://ethereum-magicians.org/t/erc-7806-minimal-intent-centric-eoa-smart-account/21565 status: Draft type: Standards Track category: ERC created: 2024-11-02 -requires: EIP-7702 +requires: 7702 --- # Abstract @@ -20,14 +20,14 @@ AA (Account abstraction) is a hot topic in blockchain industry because it gives * **GasSponsorship** * **AccessControl** -With [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337), engineers built a permissionless AA standard. While unlocking enormous number of useful features, ERC-4337 still has several limitations: +With [ERC-4337](./erc-4337.md), engineers built a permissionless AA standard. While unlocking enormous number of useful features, ERC-4337 still has several limitations: -* **Complexity**: Requiring multiple components: Account, EntryPoint, Paymaster, Bundler, and Plugins ([ERC-6900](https://eips.ethereum.org/EIPS/eip-6900), [ERC-7579](https://eips.ethereum.org/EIPS/eip-7579)). Services like bundler has a high original cost and requires high engineer skills to run and maintain. +* **Complexity**: Requiring multiple components: Account, EntryPoint, Paymaster, Bundler, and Plugins ([ERC-6900](./erc-6900.md), [ERC-7579](./erc-7579.md). Services like bundler has a high original cost and requires high engineer skills to run and maintain. * **Compatibility**: Compatibility issue between components forces developers to upgrade multiple smart contracts within one version update * **Cost**: `UserOperation` processing costs high gas units * **Trust**: Although this standard is designed to be permissionless, there are still centralized processes. Paymaster is usually a centralized service because it needs to either trust the account owner to payback the sponsored gas or the transaction is beneficial for Paymaster. Bundlers are running on MEV based and accounts need to trust bundler providers. -[ERC-7521](https://eips.ethereum.org/EIPS/eip-7521) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. +[ERC-7521](./erc-7521.md) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. @@ -91,7 +91,7 @@ It is RECOMMENDED that each `account` leverages `standard` to validate and unpac There are many objects defined with `bytes` type for extensibility, future-compatibility purpose. All those objects are optional and their usages depends on `standard`. For the `UserIntent` struct: * `UserIntent.header`: The `UserIntent.header` can carry information about how to validate the intent or how to prevent double-spending. For example, let `UserIntent.header` be an `uint256 nonce` and the `standard` can check if the `nonce` is used already. -* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified ERC20 token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. +* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified ERC-20 token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. * `UserIntent.signatures`: These `signatures` can support different signing methods. It is NOT REQUIRED that all `signatures` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. # Rationale From 9eb2ef6cb9a6412a91495f6f22e1d96c942d1ae6 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:21:50 -0800 Subject: [PATCH 06/13] fix md --- ERCS/erc-7806.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 9b975fe767..543fe940c4 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -1,7 +1,7 @@ --- eip: 7806 title: Minimal intent-centric EOA smart account -description: Minimal effort intent-centric interfaces for EOA accounts with contract code (EIP-7702) to support account abstraction features +description: Minimal effort intent-centric interfaces for EOA accounts with contract code to support account abstraction features author: hellohanchen (@hellohanchen) discussions-to: https://ethereum-magicians.org/t/erc-7806-minimal-intent-centric-eoa-smart-account/21565 status: Draft @@ -11,10 +11,10 @@ created: 2024-11-02 requires: 7702 --- -# Abstract -This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +## Abstract +This proposal defines interfaces to build intent-centric smart accounts under [7702 Set EOA account code](https://eips.ethereum.org/EIPS/eip-7702), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. -# Motivation +## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: * **BatchExecution** * **GasSponsorship** @@ -33,11 +33,11 @@ With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, The above EIPs inspired the author to build an intent-centric standard for EIP-7702 smart accounts. -# Specification +## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -## UserIntent struct +### UserIntent struct `UserIntent` is a packed data structure defining the intents of executing a transaction. | Field | Type | Description | @@ -48,7 +48,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S | `instructions` | `bytes[]` | The detailed content of this `UserIntent`, used by `standard` to determine the `Operation`s need to be executing, using `bytes` type to keep flexibility | | `signatures` | `bytes[]` | Validatable signatures, used by `standard` | -## IStandard interface +### IStandard interface The above `standard` means how to parse and validate an `UserIntent`, it implements the following `IStandard` interface: ```solidity @@ -71,7 +71,7 @@ interface IStandard { ``` Notice that `IStandard` fully controls the validation process, so similar as `EntryPoint` in ERC-4337 and ERC-7521, each `standard` MUST be pre-audited and SHOULD NOT be upgradable. -## IAccount interface +### IAccount interface On the `account` side, `IAccount` is the interface to execute `UserIntent`: ```solidity interface IAccount { @@ -87,20 +87,20 @@ Following EIP-7702 definition, `account` will be the contract code delegated by It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, check **Reference Implmentation** for examples. `account` MAY be implemented as a stateless smart contract. -## Usage of Bytes +### Usage of Bytes There are many objects defined with `bytes` type for extensibility, future-compatibility purpose. All those objects are optional and their usages depends on `standard`. For the `UserIntent` struct: * `UserIntent.header`: The `UserIntent.header` can carry information about how to validate the intent or how to prevent double-spending. For example, let `UserIntent.header` be an `uint256 nonce` and the `standard` can check if the `nonce` is used already. -* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified ERC-20 token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. +* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified [ERC-20](./erc-20.md) token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. * `UserIntent.signatures`: These `signatures` can support different signing methods. It is NOT REQUIRED that all `signatures` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. -# Rationale +## Rationale > The main challenge with a generalized intent standard is being able to adapt to the evolving world of intents. Users need to have a way to express their intents in a seamless way without having to make constant updates to their smart contract wallets. --- ERC-7521 The interface designs proposed in this EIP is inspired by ERC-7521, and the author tries to avoid turning EIP into a real implementation. -## Execution in EOA contract code +### Execution in EOA contract code EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: * Aligned with the nature of EOA that the execution is fully controlled by the account owner. EOA owner can easily turn off all smart contract features by un-delegating the contract code. * `msg.sender` is always EOA address @@ -108,31 +108,31 @@ EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings so In the case that the EOA doesn't need to execute its contract code, or the intent cost is too high. The owner can use the account as EOA. -## Validation in standard contract +### Validation in standard contract Validation logic commonly relies on contract state, for example, weighted multi-owner signature needs to track the weight of each signer. Keeping the functionality of intent validate purely inside `IStandard` makes it similar to the `EntryPoint` concept in ERC-4337, but a simpler version. Standard only taking responsibility of validation makes it easier for contract engineer to build, audit and maintain. Also, the `IStandard` interface can be considered as "modular". There can be a "compound" standard that breaks `UserIntent` into smaller pieces and call other standards to validate each piece and later combine the results together. -## Gas abstraction defined in standard +### Gas abstraction defined in standard This EIP enables standard to use content stored in `UserIntent.header` to define the "reward" of solving this intent. For example, `UserIntent.header` can contain `(erc20TokenAddress, amount)` and the standard can convert this into an instruction to send these tokens to the `tx.origin` and returns this instruction through `unpackInstruction` ABI. -## Auditability of both validation and execution +### Auditability of both validation and execution It is very important both the standard and account implementation can be publicly audited and shared. The most important reason is security. And this can also help mediate the compatibility issues between standard and account. -## Solver is relayer, relayer is paymaster, paymaster is bundler +### Solver is relayer, relayer is paymaster, paymaster is bundler Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. EIP-7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. Each solver needs to develop its own strategy to maximize its profit. And this EIP doesn't define anything about how a solver executes the intents, meaning there is no limitation. -## Intents can be rewarded, repeatable +### Intents can be rewarded, repeatable And another fact, which is easy to be ignored, is that intent has value by itself. For example, if an EOA is always willing to swap 1000 USDC to 1000 USDT and vice versa, this EOA will be considered as a "liquidity provider" in the market. The account can send the signed intent to exchanges and make the exchange reward the account every time the intent is executed. -# Backwards Compatibility +## Backwards Compatibility This EIP shares the same backwards compatibility issue as EIP-7702. This EIP is not compatible with ERC-7521. -# Reference Implementation +## Reference Implementation -## Standard +### Standard A ICS (Intent Centric Standard) that checks nonce and timestamp of an intent, the instructions are just `(address, uint256, bytes)` tuples representing a call to a contract. The relayer will be rewards with ERC20 token. ```solidity @@ -229,7 +229,7 @@ contract ICS1 is IStandard { } ``` -## Account +### Account An `IAccount` implementation that support batch execution. ```solidity contract BatchExecuteAccount is IAccount { @@ -268,10 +268,10 @@ contract BatchExecuteAccount is IAccount { ``` -# Security Considerations +## Security Considerations This is mainly controlled by the standard and account implementation to make sure the account is safe. Solver needs to responsible for its own security when executing intents. More discussion needed. -# Copyright +## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From 52ba0f506ded8fc62c7ad3049acd37cf290230f3 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:26:00 -0800 Subject: [PATCH 07/13] fix md --- ERCS/erc-7806.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 543fe940c4..6dd2546f06 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -12,7 +12,7 @@ requires: 7702 --- ## Abstract -This proposal defines interfaces to build intent-centric smart accounts under [7702 Set EOA account code](https://eips.ethereum.org/EIPS/eip-7702), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +This proposal defines interfaces to build intent-centric smart accounts under [7702 Set EOA account code](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. ## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: @@ -29,9 +29,9 @@ With [ERC-4337](./erc-4337.md), engineers built a permissionless AA standard. Wh [ERC-7521](./erc-7521.md) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. -With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. +With 7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. -The above EIPs inspired the author to build an intent-centric standard for EIP-7702 smart accounts. +The above EIPs inspired the author to build an intent-centric standard for 7702 smart accounts. ## Specification @@ -83,7 +83,7 @@ interface IAccount { function executeUserIntent(UserIntent calldata intent) external returns (bytes memory); } ``` -Following EIP-7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. +Following 7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, check **Reference Implmentation** for examples. `account` MAY be implemented as a stateless smart contract. @@ -101,7 +101,7 @@ There are many objects defined with `bytes` type for extensibility, future-compa The interface designs proposed in this EIP is inspired by ERC-7521, and the author tries to avoid turning EIP into a real implementation. ### Execution in EOA contract code -EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: +7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: * Aligned with the nature of EOA that the execution is fully controlled by the account owner. EOA owner can easily turn off all smart contract features by un-delegating the contract code. * `msg.sender` is always EOA address * Execution code can be stateless, this allows `account` to store no state data. @@ -120,7 +120,7 @@ This EIP enables standard to use content stored in `UserIntent.header` to define It is very important both the standard and account implementation can be publicly audited and shared. The most important reason is security. And this can also help mediate the compatibility issues between standard and account. ### Solver is relayer, relayer is paymaster, paymaster is bundler -Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. EIP-7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. +Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. 7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. Each solver needs to develop its own strategy to maximize its profit. And this EIP doesn't define anything about how a solver executes the intents, meaning there is no limitation. @@ -128,13 +128,13 @@ Each solver needs to develop its own strategy to maximize its profit. And this E And another fact, which is easy to be ignored, is that intent has value by itself. For example, if an EOA is always willing to swap 1000 USDC to 1000 USDT and vice versa, this EOA will be considered as a "liquidity provider" in the market. The account can send the signed intent to exchanges and make the exchange reward the account every time the intent is executed. ## Backwards Compatibility -This EIP shares the same backwards compatibility issue as EIP-7702. This EIP is not compatible with ERC-7521. +This `IAccount` shares the same backwards compatibility issue as 7702. These interfaces are not compatible with ERC-7521 or ERC-4337. ## Reference Implementation ### Standard A ICS (Intent Centric Standard) that checks nonce and timestamp of an intent, the instructions are just `(address, uint256, bytes)` tuples -representing a call to a contract. The relayer will be rewards with ERC20 token. +representing a call to a contract. The relayer will be rewards with ERC-20 tokens. ```solidity contract ICS1 is IStandard { using ECDSA for bytes32; From a69c308ab7f2257457d9d1e85ac71e2016f03507 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:27:27 -0800 Subject: [PATCH 08/13] fix md --- ERCS/erc-7806.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 6dd2546f06..c42b420a18 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -12,7 +12,7 @@ requires: 7702 --- ## Abstract -This proposal defines interfaces to build intent-centric smart accounts under [7702 Set EOA account code](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md), allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +This proposal defines interfaces to build intent-centric smart accounts under `7702 Set EOA account code` standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. ## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: From 2329032414c1aa9f0e2eab079d710cc82f03f2a0 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:40:07 -0800 Subject: [PATCH 09/13] fix md --- ERCS/erc-7806.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index c42b420a18..2e9ad553c6 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -1,7 +1,7 @@ --- eip: 7806 title: Minimal intent-centric EOA smart account -description: Minimal effort intent-centric interfaces for EOA accounts with contract code to support account abstraction features +description: Minimal effort intent-centric interfaces for EOA accounts with contract code [EIP-7702](./eip-EIP-7702.md) to support account abstraction features author: hellohanchen (@hellohanchen) discussions-to: https://ethereum-magicians.org/t/erc-7806-minimal-intent-centric-eoa-smart-account/21565 status: Draft @@ -12,7 +12,7 @@ requires: 7702 --- ## Abstract -This proposal defines interfaces to build intent-centric smart accounts under `7702 Set EOA account code` standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +This proposal defines interfaces to build intent-centric smart accounts under EIP-7702 standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. ## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: @@ -20,18 +20,18 @@ AA (Account abstraction) is a hot topic in blockchain industry because it gives * **GasSponsorship** * **AccessControl** -With [ERC-4337](./erc-4337.md), engineers built a permissionless AA standard. While unlocking enormous number of useful features, ERC-4337 still has several limitations: +With [ERC-4337](./eip-4337.md), engineers built a permissionless AA standard. While unlocking enormous number of useful features, ERC-4337 still has several limitations: -* **Complexity**: Requiring multiple components: Account, EntryPoint, Paymaster, Bundler, and Plugins ([ERC-6900](./erc-6900.md), [ERC-7579](./erc-7579.md). Services like bundler has a high original cost and requires high engineer skills to run and maintain. +* **Complexity**: Requiring multiple components: Account, EntryPoint, Paymaster, Bundler, and Plugins ([ERC-6900](./eip-6900.md), [ERC-7579](./eip-7579.md). Services like bundler has a high original cost and requires high engineer skills to run and maintain. * **Compatibility**: Compatibility issue between components forces developers to upgrade multiple smart contracts within one version update * **Cost**: `UserOperation` processing costs high gas units * **Trust**: Although this standard is designed to be permissionless, there are still centralized processes. Paymaster is usually a centralized service because it needs to either trust the account owner to payback the sponsored gas or the transaction is beneficial for Paymaster. Bundlers are running on MEV based and accounts need to trust bundler providers. -[ERC-7521](./erc-7521.md) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. +[ERC-7521](./eip-7521.md) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. -With 7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. +With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. -The above EIPs inspired the author to build an intent-centric standard for 7702 smart accounts. +The above EIPs inspired the author to build an intent-centric standard for EIP-7702 smart accounts. ## Specification @@ -83,7 +83,7 @@ interface IAccount { function executeUserIntent(UserIntent calldata intent) external returns (bytes memory); } ``` -Following 7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. +Following EIP-7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, check **Reference Implmentation** for examples. `account` MAY be implemented as a stateless smart contract. @@ -91,7 +91,7 @@ It is RECOMMENDED that each `account` leverages `standard` to validate and unpac There are many objects defined with `bytes` type for extensibility, future-compatibility purpose. All those objects are optional and their usages depends on `standard`. For the `UserIntent` struct: * `UserIntent.header`: The `UserIntent.header` can carry information about how to validate the intent or how to prevent double-spending. For example, let `UserIntent.header` be an `uint256 nonce` and the `standard` can check if the `nonce` is used already. -* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified [ERC-20](./erc-20.md) token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. +* `UserIntent.instructions`: These `instructions` can just be concatenated `(address,value,calldata)` or can be standard-defined values, for example `(erc20TokenAddress,1000)` means the `instructions` can use up to 1000 of the specified [ERC-20](./eip-20.md) token. It is NOT REQUIRED that all `instructions` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. * `UserIntent.signatures`: These `signatures` can support different signing methods. It is NOT REQUIRED that all `signatures` MUST be provided by the EOA owner, some of them MAY be provided by relayer or third party. ## Rationale @@ -101,7 +101,7 @@ There are many objects defined with `bytes` type for extensibility, future-compa The interface designs proposed in this EIP is inspired by ERC-7521, and the author tries to avoid turning EIP into a real implementation. ### Execution in EOA contract code -7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: +EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: * Aligned with the nature of EOA that the execution is fully controlled by the account owner. EOA owner can easily turn off all smart contract features by un-delegating the contract code. * `msg.sender` is always EOA address * Execution code can be stateless, this allows `account` to store no state data. @@ -120,7 +120,7 @@ This EIP enables standard to use content stored in `UserIntent.header` to define It is very important both the standard and account implementation can be publicly audited and shared. The most important reason is security. And this can also help mediate the compatibility issues between standard and account. ### Solver is relayer, relayer is paymaster, paymaster is bundler -Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. 7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. +Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. EIP-7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. Each solver needs to develop its own strategy to maximize its profit. And this EIP doesn't define anything about how a solver executes the intents, meaning there is no limitation. @@ -128,7 +128,7 @@ Each solver needs to develop its own strategy to maximize its profit. And this E And another fact, which is easy to be ignored, is that intent has value by itself. For example, if an EOA is always willing to swap 1000 USDC to 1000 USDT and vice versa, this EOA will be considered as a "liquidity provider" in the market. The account can send the signed intent to exchanges and make the exchange reward the account every time the intent is executed. ## Backwards Compatibility -This `IAccount` shares the same backwards compatibility issue as 7702. These interfaces are not compatible with ERC-7521 or ERC-4337. +This `IAccount` shares the same backwards compatibility issue as EIP-7702. These interfaces are not compatible with ERC-7521 or ERC-4337. ## Reference Implementation From 4d357a57fb0174941f4a1377b5f06c9a29240482 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:41:59 -0800 Subject: [PATCH 10/13] fix md --- ERCS/erc-7806.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 2e9ad553c6..75640b3e28 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -1,7 +1,7 @@ --- eip: 7806 title: Minimal intent-centric EOA smart account -description: Minimal effort intent-centric interfaces for EOA accounts with contract code [EIP-7702](./eip-EIP-7702.md) to support account abstraction features +description: Minimal effort intent-centric interfaces for EOA account abstraction author: hellohanchen (@hellohanchen) discussions-to: https://ethereum-magicians.org/t/erc-7806-minimal-intent-centric-eoa-smart-account/21565 status: Draft @@ -12,7 +12,7 @@ requires: 7702 --- ## Abstract -This proposal defines interfaces to build intent-centric smart accounts under EIP-7702 standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](./eip-EIP-7702.md) standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. ## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: From b3b4181fe19b0f7a62456650ef07dc80b891f447 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Sun, 3 Nov 2024 23:52:57 -0800 Subject: [PATCH 11/13] fix 7702 link --- ERCS/erc-7806.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 75640b3e28..e14d942888 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -12,7 +12,7 @@ requires: 7702 --- ## Abstract -This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](./eip-EIP-7702.md) standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](./EIP-7702.md) standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. ## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: From 65042e4bd6c516ff07d4f43ccd58a428a1f5787d Mon Sep 17 00:00:00 2001 From: Han Chen Date: Wed, 6 Nov 2024 09:13:27 -0800 Subject: [PATCH 12/13] temporarily remove 7702 from md --- ERCS/erc-7806.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index e14d942888..0cbe68156b 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -12,7 +12,7 @@ requires: 7702 --- ## Abstract -This proposal defines interfaces to build intent-centric smart accounts under [EIP-7702](./EIP-7702.md) standard, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. +This proposal defines interfaces to build intent-centric smart accounts by setting EOA account code, allowing EOA account owners to define their intents of a transaction and let relayers (solvers) to validate and execute the requests. ## Motivation AA (Account abstraction) is a hot topic in blockchain industry because it gives accounts programmablility features, including but not limited to: @@ -29,9 +29,9 @@ With [ERC-4337](./eip-4337.md), engineers built a permissionless AA standard. Wh [ERC-7521](./eip-7521.md) discusses an SCA solution with intent-centric design. It enables solvers to fulfill account owners' intents by acting "on behalf of" account owners. ERC-7521 allows arbitrary intents and verification logics while trying to keep the whole solution forward-compatible. -With EIP-7702 _Set EOA account code_ allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. +With `SET_CODE_TX_TYPE=0x04` allowing EOA accounts to set contract code, EOA accounts will gain similar programmability as SCA (Smart Contact Account). A new standard, that provides EOA with highly-demanded AA features while potentially resolving some of the above challenges, will help bringing seamless user experience and drive mass adoptions. -The above EIPs inspired the author to build an intent-centric standard for EIP-7702 smart accounts. +The above EIPs inspired the author to build an intent-centric standard for EOA smart accounts. ## Specification @@ -83,7 +83,7 @@ interface IAccount { function executeUserIntent(UserIntent calldata intent) external returns (bytes memory); } ``` -Following EIP-7702 definition, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. +Using `SET_CODE_TX_TYPE=0x04`, `account` will be the contract code delegated by the EOA, which MAY have full control of EOA's assets, so each `account` MUST be pre-audited. Since different EOAs can set their contract code to the same smart contract, an audited `IAccount` implementation is ALWAYS publicly shared. But it has to be the EOA account owners' responsibility to delegate to a safe `account`. It is RECOMMENDED that each `account` leverages `standard` to validate and unpack `UserIntent`, check **Reference Implmentation** for examples. `account` MAY be implemented as a stateless smart contract. @@ -101,7 +101,7 @@ There are many objects defined with `bytes` type for extensibility, future-compa The interface designs proposed in this EIP is inspired by ERC-7521, and the author tries to avoid turning EIP into a real implementation. ### Execution in EOA contract code -EIP-7702 gives EOA the ability to execute code. Executing from the EOA brings some benefits: +`SET_CODE_TX_TYPE=0x04` gives EOA the ability to execute code. Executing from the EOA brings some benefits: * Aligned with the nature of EOA that the execution is fully controlled by the account owner. EOA owner can easily turn off all smart contract features by un-delegating the contract code. * `msg.sender` is always EOA address * Execution code can be stateless, this allows `account` to store no state data. @@ -120,7 +120,7 @@ This EIP enables standard to use content stored in `UserIntent.header` to define It is very important both the standard and account implementation can be publicly audited and shared. The most important reason is security. And this can also help mediate the compatibility issues between standard and account. ### Solver is relayer, relayer is paymaster, paymaster is bundler -Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. EIP-7702 allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. +Within a intent-centric system, solvers are helping account owners to fulfill the intent and solvers are rewarded. This proposal allows any solver to execute the intent, bringing a positive competitive environment. And supported by gas abstraction, solvers will pay the native token as gas fee and take other tokens back from the EOA account. Besides, solvers can further reduce the cost of their side by bundling multiple intent executions into one blockchain transaction. Each solver needs to develop its own strategy to maximize its profit. And this EIP doesn't define anything about how a solver executes the intents, meaning there is no limitation. @@ -128,7 +128,7 @@ Each solver needs to develop its own strategy to maximize its profit. And this E And another fact, which is easy to be ignored, is that intent has value by itself. For example, if an EOA is always willing to swap 1000 USDC to 1000 USDT and vice versa, this EOA will be considered as a "liquidity provider" in the market. The account can send the signed intent to exchanges and make the exchange reward the account every time the intent is executed. ## Backwards Compatibility -This `IAccount` shares the same backwards compatibility issue as EIP-7702. These interfaces are not compatible with ERC-7521 or ERC-4337. +This `IAccount` shares the same backwards compatibility issue as set EOA account code. These interfaces are not compatible with ERC-7521 or ERC-4337. ## Reference Implementation From b6b05db92496f505ab87369cbb23640747463186 Mon Sep 17 00:00:00 2001 From: Han Chen Date: Mon, 11 Nov 2024 21:45:24 -0800 Subject: [PATCH 13/13] working on implementation --- ERCS/erc-7806.md | 137 +---------------------------------------------- 1 file changed, 1 insertion(+), 136 deletions(-) diff --git a/ERCS/erc-7806.md b/ERCS/erc-7806.md index 0cbe68156b..f44414211e 100644 --- a/ERCS/erc-7806.md +++ b/ERCS/erc-7806.md @@ -131,142 +131,7 @@ And another fact, which is easy to be ignored, is that intent has value by itsel This `IAccount` shares the same backwards compatibility issue as set EOA account code. These interfaces are not compatible with ERC-7521 or ERC-4337. ## Reference Implementation - -### Standard -A ICS (Intent Centric Standard) that checks nonce and timestamp of an intent, the instructions are just `(address, uint256, bytes)` tuples -representing a call to a contract. The relayer will be rewards with ERC-20 tokens. -```solidity -contract ICS1 is IStandard { - using ECDSA for bytes32; - - string public constant ICS_NUMBER = "ICS1"; - string public constant NAME = "Direct Execution Standard with Expiration, Nonce and ERC20 Reward"; - string public constant VERSION = "0.0.0"; - string public constant AUTHOR = "hellohanchen"; - - bytes4 public constant VALIDATION_APPROVED = 0x00000001; - bytes4 public constant VALIDATION_DENIED = 0x00000000; - uint256 public constant MAX_INSTRUCTIONS = 256; - bytes4 public constant ERC20_TRANSFER_SELECTOR = IERC20.transfer.selector; - - mapping(address => mapping(uint256 => bool)) internal _nonces; - - function validateUserIntent(UserIntent calldata intent) external returns (bytes4) { - if (intent.instructions.length > MAX_INSTRUCTIONS) { - return VALIDATION_DENIED; // too many instructions - } - - (bool validated, uint256 nonce, uint256 timestamp, address tokenAddress, uint256 amount) = this.decodeHeader(intent.header); - if (!validated) { - return VALIDATION_DENIED; // invalid header - } - - if (timestamp < block.timestamp) { - return VALIDATION_DENIED; // expired intent - } - - if (_nonces[intent.sender][nonce]) { - return VALIDATION_DENIED; // used nonce - } - - if (intent.signatures.length != 1) { - return VALIDATION_DENIED; // invalid signature - } - - try IERC20(tokenAddress).totalSupply() { - // TODO: validate sender balance - } catch { - return VALIDATION_DENIED; - } - - bytes32 intentHash = keccak256(abi.encode(intent.header, intent.standard, intent.instructions, block.chainid)); - bytes32 messageHash = intentHash.toEthSignedMessageHash(); - - if (intent.sender != messageHash.recover(intent.signatures[0])) { - return VALIDATION_DENIED; // invalid signature - } - - return VALIDATION_APPROVED; - } - - function unpackOperations(UserIntent calldata intent) external returns (bytes memory, bytes[] memory) { - (bool validated, uint256 nonce, , address tokenAddress, uint256 amount) = this.decodeHeader(intent.header); - if (!validated) { - return (abi.encodePacked(VALIDATION_DENIED), new bytes[](0)); // invalid header - } - - bytes[] memory unpackedInstructions = new bytes[](intent.instructions.length + 2); - - for (uint256 i = 0; i < intent.instructions.length; i++) { - unpackedInstructions[i] = intent.instructions[i]; - } - - address relayer = tx.origin; - bytes memory transferCallData = abi.encodeWithSelector(ERC20_TRANSFER_SELECTOR, relayer, amount); - bytes memory transferInstruction = abi.encode(tokenAddress, uint256(0), transferCallData); - unpackedInstructions[intent.instructions.length] = transferInstruction; - - bytes memory nonceCallData = abi.encodeWithSelector(this.markNonce.selector, nonce); - bytes memory nonceInstruction = abi.encode(address(this), 0, nonceCallData); - unpackedInstructions[intent.instructions.length + 1] = nonceInstruction; - - return (abi.encodePacked(VALIDATION_APPROVED), unpackedInstructions); - } - - function decodeHeader(bytes calldata header) external pure returns (bool, uint256, uint256, address, uint256) { - if (header.length != 128) { - return (false, 0, 0, address(0), 0); - } - - (uint256 nonce, uint256 timestamp, address tokenAddress, uint256 amount) = abi.decode(header, (uint256, uint256, address, uint256)); - - return (true, nonce, timestamp, tokenAddress, amount); - } - - function markNonce(uint256 nonce) external { - _nonces[msg.sender][nonce] = true; - } -} -``` - -### Account -An `IAccount` implementation that support batch execution. -```solidity -contract BatchExecuteAccount is IAccount { - bytes4 public constant VALIDATION_APPROVED = 0x00000001; - - function executeUserIntent(UserIntent calldata intent) external returns (bytes memory) { - require(intent.sender == address(this), "intent sender is not this account"); - IStandard standard = IStandard(intent.standard); - - bytes4 validationResult = standard.validateUserIntent(intent); - require(validationResult == VALIDATION_APPROVED, "validation failed"); - - (, bytes[] memory instructions) = standard.unpackOperations(intent); - _executeBatch(instructions); - - return new bytes(0); - } - - function _executeBatch(bytes[] memory instructions) internal { - for (uint256 i = 0; i < instructions.length; i++) { - _execute(instructions[i]); - } - } - - function _execute(bytes memory instruction) internal { - (address dest, uint256 value, bytes memory data) = abi.decode(instruction, (address, uint256, bytes)); - - (bool success, bytes memory result) = dest.call{value: value, gas: gasleft()}(data); - if (!success) { - assembly { - revert(add(result, 32), result) - } - } - } -} - -``` +WIP ## Security Considerations This is mainly controlled by the standard and account implementation to make sure the account is safe. Solver needs to responsible for its own security when executing intents.