From d1a95a362dc07c1194939ecba57c264b66ec8fc4 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sat, 3 Feb 2024 12:35:16 -0500 Subject: [PATCH 01/15] Create ERC-xxxx --- ERCS/ERC-xxxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 ERCS/ERC-xxxx diff --git a/ERCS/ERC-xxxx b/ERCS/ERC-xxxx new file mode 100644 index 0000000000..0ba65f8008 --- /dev/null +++ b/ERCS/ERC-xxxx @@ -0,0 +1,16 @@ +--- +eip: xxxx +title: Smart Contract Data Push Mechanism +description: An Atomic Mechanism to Allow Publisher Contract Push Data to Subcriber Contracts +author: Elaine Zhang (@lanyinzly) , Jerry , Amandafanny , Shouhao Wong (@wangshouh) , Doris Che (@Cheyukj) +discussions-to: https://ethereum-magicians.org/t/erc-xxxx-smart-contract-data-push-mechanism/18466 +status: Draft +type: Standards Track +category: ERC +created: 2024-02-03 +requires: +--- +## Abstract +This ERC proposes a push-based mechanism for sending data, allowing publisher contract to automatically push certain data to subscriber contracts during a call. The specific implementation relies on two interfaces: one for publisher contract to push data, and another for the subscriber contract to receive data. When the publisher contract is called, it checks if the called function corresponds to subscriber addresses. If it does, the publisher contract push data to the subscriber contracts. + +Copyright and related rights waived via [CC0](../LICENSE.md). From 9cf548f298559b5cb97b1387bf190b7375fc8ef9 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:12:57 -0500 Subject: [PATCH 02/15] Update ERC-xxxx --- ERCS/ERC-xxxx | 160 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-) diff --git a/ERCS/ERC-xxxx b/ERCS/ERC-xxxx index 0ba65f8008..429e3f382f 100644 --- a/ERCS/ERC-xxxx +++ b/ERCS/ERC-xxxx @@ -1,6 +1,6 @@ --- eip: xxxx -title: Smart Contract Data Push Mechanism +title: Atomic Push-based Data Feed Among Contracts description: An Atomic Mechanism to Allow Publisher Contract Push Data to Subcriber Contracts author: Elaine Zhang (@lanyinzly) , Jerry , Amandafanny , Shouhao Wong (@wangshouh) , Doris Che (@Cheyukj) discussions-to: https://ethereum-magicians.org/t/erc-xxxx-smart-contract-data-push-mechanism/18466 @@ -13,4 +13,162 @@ requires: ## Abstract This ERC proposes a push-based mechanism for sending data, allowing publisher contract to automatically push certain data to subscriber contracts during a call. The specific implementation relies on two interfaces: one for publisher contract to push data, and another for the subscriber contract to receive data. When the publisher contract is called, it checks if the called function corresponds to subscriber addresses. If it does, the publisher contract push data to the subscriber contracts. +## Motivation +Currently, there are many keepers rely on off-chain data or seperate data collection process to monitor the events on chain. This proposal aims to establish a system where the publisher contract can atomicly push data to inform subscriber contracts about the updates. The direct on-chain interaction bewteen the publisher and the subscriber allows the system to be more trustless and efficient. + +This proposal will benefit DeFi's boundless and permissionless expansion + + +## Specification + + +``` ++---------+ +-----------+ +-------------+ +| Client | | Publisher | | Subscriber | ++---------+ +-----------+ +-------------+ + | | | + | Call somefunc(...) | | + |------------------------->| | + | | | + | | Query Subscriber | + | |----------------- | + | | | | + | |<---------------- | + | | | + | | Call exec(bytes4 selector, bytes calldata data) | + | |------------------------------------------------------->| + | | | + | | Result | + | |<-------------------------------------------------------| + | | | + | Result | | + |<-------------------------| | + | | | +``` + +### Contract interface + +A publisher contract has the following two configuration schemes, among which the unconditional push configuration requires the push contract to implement the following interface: + +```solidity +interface IPushForce { + function isForceApproved(bytes4 selector, address target) external returns (bool); + function forceApprove(bytes4 selector, address target) external; + function forceCancel(bytes4 selector, address target) external; +} +``` +The conditional push configuration requires the push contract to implement the following interface: + +```solidity +interface IPushFree { + function inbox(bytes4 selector) external returns (bytes memory); + function isApproved(bytes4 selector, address target, bytes calldata data) external returns (bool); + function approve(bytes4 selector, address target, bytes calldata data) external; + function cancel(bytes4 selector, address target, bytes calldata data) external; +} +``` +A subscriber need to implement the following interface: + +```solidity +interface IExec { + function isLocked(bytes4 selector, bytes calldata data) external returns (bool); + function exec(bytes4 selector, bytes calldata data) external; +} +``` + +## Reference Implementation + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IPushFree, IPushForce} from "./interfaces/IPush.sol"; +import {IPull} from "./interfaces/IPull.sol"; + +contract Foo is IPushFree, IPushForce { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes4 selector => mapping(uint256 tokenId => EnumerableSet.AddressSet targets)) private _registry; + mapping(bytes4 selector => EnumerableSet.AddressSet targets) private _registryOfAll; + + modifier notLock(bytes4 selector, address target, bytes memory data) { + require(!IPull(target).isLocked(selector, data), "Foo: lock"); + _; + } + + function inbox(bytes4 selector) public view returns (bytes memory data) { + uint256 loadData; + assembly { + loadData := tload(selector) + } + + data = abi.encode(loadData); + } + + function isApproved(bytes4 selector, address target, bytes calldata data) external view override returns (bool) { + uint256 tokenId = abi.decode(data, (uint256)); + return _registry[selector][tokenId].contains(target); + } + + function isForceApproved(bytes4 selector, address target) external view override returns (bool) { + return _registryOfAll[selector].contains(target); + } + + function approve(bytes4 selector, address target, bytes calldata data) external override { + uint256 tokenId = abi.decode(data, (uint256)); + _registry[selector][tokenId].add(target); + } + + function cancel(bytes4 selector, address target, bytes calldata data) + external + override + notLock(selector, target, data) + { + uint256 tokenId = abi.decode(data, (uint256)); + _registry[selector][tokenId].remove(target); + } + + function forceApprove(bytes4 selector, address target) external override { + _registryOfAll[selector].add(target); + } + + function forceCancel(bytes4 selector, address target) external override notLock(selector, target, "") { + _registryOfAll[selector].remove(target); + } + + function send(uint256 message) external { + _push(this.send.selector, message); + } + + function _push(bytes4 selector, uint256 message) internal { + assembly { + tstore(selector, message) + } + + address[] memory targets = _registry[selector][message].values(); + for (uint256 i = 0; i < targets.length; i++) { + IPull(targets[i]).pull(selector, abi.encode(message)); + } + + targets = _registryOfAll[selector].values(); + for (uint256 i = 0; i < targets.length; i++) { + IPull(targets[i]).pull(selector, abi.encode(message)); + } + } +} + +contract Bar is IPull { + event Log(bytes4 indexed selector, bytes data, bytes inboxData); + + function isLocked(bytes4, bytes calldata) external pure override returns (bool) { + return true; + } + + function pull(bytes4 selector, bytes calldata data) external { + bytes memory inboxData = IPushFree(msg.sender).inbox(selector); + emit Log(selector, data, inboxData); + } +} +``` Copyright and related rights waived via [CC0](../LICENSE.md). From b8016fb858639c484d2261867fb3d9e9d05eed4e Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sat, 17 Feb 2024 10:15:06 -0500 Subject: [PATCH 03/15] Update and rename ERC-xxxx to ERC-7615 --- ERCS/{ERC-xxxx => ERC-7615} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename ERCS/{ERC-xxxx => ERC-7615} (99%) diff --git a/ERCS/ERC-xxxx b/ERCS/ERC-7615 similarity index 99% rename from ERCS/ERC-xxxx rename to ERCS/ERC-7615 index 429e3f382f..7ea52ce4e6 100644 --- a/ERCS/ERC-xxxx +++ b/ERCS/ERC-7615 @@ -1,5 +1,5 @@ --- -eip: xxxx +eip: 7615 title: Atomic Push-based Data Feed Among Contracts description: An Atomic Mechanism to Allow Publisher Contract Push Data to Subcriber Contracts author: Elaine Zhang (@lanyinzly) , Jerry , Amandafanny , Shouhao Wong (@wangshouh) , Doris Che (@Cheyukj) From fac544829414370540f65ec6b223d7ded1df16cb Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sat, 17 Feb 2024 11:41:08 -0500 Subject: [PATCH 04/15] Update ERC-7615 --- ERCS/ERC-7615 | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ERCS/ERC-7615 b/ERCS/ERC-7615 index 7ea52ce4e6..40af9a9dba 100644 --- a/ERCS/ERC-7615 +++ b/ERCS/ERC-7615 @@ -3,7 +3,7 @@ eip: 7615 title: Atomic Push-based Data Feed Among Contracts description: An Atomic Mechanism to Allow Publisher Contract Push Data to Subcriber Contracts author: Elaine Zhang (@lanyinzly) , Jerry , Amandafanny , Shouhao Wong (@wangshouh) , Doris Che (@Cheyukj) -discussions-to: https://ethereum-magicians.org/t/erc-xxxx-smart-contract-data-push-mechanism/18466 +discussions-to: https://ethereum-magicians.org/t/erc-7615-smart-contract-data-push-mechanism/18466 status: Draft type: Standards Track category: ERC @@ -16,8 +16,25 @@ This ERC proposes a push-based mechanism for sending data, allowing publisher co ## Motivation Currently, there are many keepers rely on off-chain data or seperate data collection process to monitor the events on chain. This proposal aims to establish a system where the publisher contract can atomicly push data to inform subscriber contracts about the updates. The direct on-chain interaction bewteen the publisher and the subscriber allows the system to be more trustless and efficient. -This proposal will benefit DeFi's boundless and permissionless expansion +This proposal will offer significant advantages across a range of applications, such as enabling the boundless and permissionless expansion of DeFi, as well as enhancing DAO governance, among others. +### Lending Protocol + +An example of publisher contract could be an oracle, which can automatically push the price update through initiating a call to the subscriber protocol. The lending protocol, as the subscriber, can automatically liquidate the lending positions based on the received price. + +### Automatic Payment + +A service provider can use a smart contract as a publisher contract, so that when a user call this contract, it can push the information to the subsriber contracts, such as, the users' wallets like NFT bound accounts that follows [ERC-6551](./eip-6551.md) or other smart contract wallets. The user's smart contract wallet can thus perform corresponding payment operations automatically. Compared to traditional `approve` needed approach, this solution allows more complex logic in implementation, such as limited payment, etc. + +### PoS Without Transferring Assets + +For some staking scenarios, especially NFT staking, the PoS contract can be set as the subscriber and the NFT contracts can be set as the publisher. Staking can thus achieved through contracts interation, allowing users to earn staking rewards without transferring assets. + +When operations like `transfer` of NFT occur, the NFT contract can push this information to the PoS contract, which can then perform unstaking or other functions. + +### DAO Voting + +The DAO governance contract as a publisher could automatically triggers the push mechanism after the vote is completed, calling relevant subscriber contracts to directly implement the voting results, such as injecting funds into a certain account or pool. ## Specification From 97dc0e6cab49b36f5a61005842dfcf4805c5478e Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sat, 17 Feb 2024 12:25:29 -0500 Subject: [PATCH 05/15] Update ERC-7615 --- ERCS/ERC-7615 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ERCS/ERC-7615 b/ERCS/ERC-7615 index 40af9a9dba..e9af9ae50d 100644 --- a/ERCS/ERC-7615 +++ b/ERCS/ERC-7615 @@ -36,6 +36,24 @@ When operations like `transfer` of NFT occur, the NFT contract can push this inf The DAO governance contract as a publisher could automatically triggers the push mechanism after the vote is completed, calling relevant subscriber contracts to directly implement the voting results, such as injecting funds into a certain account or pool. +The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. + +### Overview + +The push mechanism can be divided into the following four steps: + +1. The publisher contract is called. +2. The publisher contract query the subscriber list from the `selector` of the function called. The subscriber contract can put the selected data into `inbox`. +3. The publisher contract push `selector` and data through calling `exec` function of the subscriber contract. +4. The subscriber contract executes based on pushed `selector` and data, or it may request information from the publisher contract's inbox function as needed. + +In the second step, the relationship between a called function and the corresponding subscriber can be configured in the publisher contract. Two configuration schemes are proposed: + +1. Unconditional push: Any call to the configured selector triggers a push +2. Conditional push: Only certain part of the calls to the configured selector trigger a push based on the configuration. + +It's allowed to configure multiple, different types of subscription contracts for a single function. The sending contract will call the exec function of each subscription contract in turn to push the request. When disassociating the function from the subscription contract, the sending contract must check the subscription contract's isLocked function, and the push relationship between the function and the subscription contract can only be disassociated if isLocked returns a True value. The sending contract can optionally use the inbox mechanism to store data. + ## Specification From 758e81e385bbdd8896ccecfbb3bf8c8ddbd34750 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sun, 18 Feb 2024 10:12:00 -0500 Subject: [PATCH 06/15] Update ERC-7615 --- ERCS/ERC-7615 | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/ERCS/ERC-7615 b/ERCS/ERC-7615 index e9af9ae50d..5ec8e7eef8 100644 --- a/ERCS/ERC-7615 +++ b/ERCS/ERC-7615 @@ -36,6 +36,8 @@ When operations like `transfer` of NFT occur, the NFT contract can push this inf The DAO governance contract as a publisher could automatically triggers the push mechanism after the vote is completed, calling relevant subscriber contracts to directly implement the voting results, such as injecting funds into a certain account or pool. +## Specification + The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. ### Overview @@ -49,12 +51,18 @@ The push mechanism can be divided into the following four steps: In the second step, the relationship between a called function and the corresponding subscriber can be configured in the publisher contract. Two configuration schemes are proposed: -1. Unconditional push: Any call to the configured selector triggers a push -2. Conditional push: Only certain part of the calls to the configured selector trigger a push based on the configuration. +1. Unconditional Push: Any call to the configured `selector` triggers a push +2. Conditional Push: Only the conditioned calls to the configured `selector` trigger a push based on the configuration. -It's allowed to configure multiple, different types of subscription contracts for a single function. The sending contract will call the exec function of each subscription contract in turn to push the request. When disassociating the function from the subscription contract, the sending contract must check the subscription contract's isLocked function, and the push relationship between the function and the subscription contract can only be disassociated if isLocked returns a True value. The sending contract can optionally use the inbox mechanism to store data. +It's allowed to configure multiple, different types of subscriber contracts for a single `selector`. The publisher contract will call the `exec` function of each subscriber contract to push the request. -## Specification +When unsubscribing a contract from a `selector`, publisher contract MUST check whether `isLocked` function of the subscriber contract returns `true`. + +It is OPTIONAL for a publisher contract to use the `inbox` mechanism to store data. + +在第四步中,订阅合约应当在实现的 `exec` 函数内处理所有可能的 `selector` 请求及其数据。注意,在某些情况下,发送合约发送的数据可能只包含 `selector` 而不包含推送数据或仅包含部分推送数据,此时可能需要订阅合约请求发送合约的 `inbox` 函数获取推送数据。 + +In the fourth step, the subscriber contract SHOULD handle all possible `selector` requests and data in the implementation of `exec` function. In some cases, `exec` MAY call `inbox` function of publisher contract to obtain the pushed data in full. ``` @@ -82,8 +90,7 @@ It's allowed to configure multiple, different types of subscription contracts fo ``` ### Contract interface - -A publisher contract has the following two configuration schemes, among which the unconditional push configuration requires the push contract to implement the following interface: +As mentioned above, there are Unconditional Push and Conditional Push two types of implementation. To implement Unconditional Push, the publisher contract SHOULD implement the following interface: ```solidity interface IPushForce { @@ -92,7 +99,11 @@ interface IPushForce { function forceCancel(bytes4 selector, address target) external; } ``` -The conditional push configuration requires the push contract to implement the following interface: + +`isForceApproved` is to query whether `selector` has already unconditionally bound to the subscriber contract with the address `target`. +`forceApprove` is to bind `selector` to the subscriber contract `target`. `forceCancel` is to cancel the binding relationship between `selector` and `target`, where `isLocked` function of `target` returns `true` is REQUIRED. + +To implement Conditional Push, the publisher contract SHOULD implement the following interface: ```solidity interface IPushFree { @@ -102,6 +113,12 @@ interface IPushFree { function cancel(bytes4 selector, address target, bytes calldata data) external; } ``` +`isApproved`, `approve`, and `cancel` have functionalities similar to the corresponding functions in `IPushForce`. However, an additional `data` parameter is introduced here for checking whether a push is needed. +The `inbox` here is used to store data in case of being called from the subscriber contract. + +The publisher contract SHOULD implement `_push(bytes4 selector, bytes calldata data)` function, which acts as a hook. Any function within the publisher contract that needs to implement push mechanism must call this internal function. The function MUST include querying both unconditional and conditional subscription contracts based on `selector` and `data`, and then calling corresponding `exec` function of the subscribers. + + A subscriber need to implement the following interface: ```solidity From ec0a84e37d68f100128f8b759878fbcb6a3558fd Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sun, 18 Feb 2024 10:23:11 -0500 Subject: [PATCH 07/15] Update ERC-7615 --- ERCS/ERC-7615 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ERCS/ERC-7615 b/ERCS/ERC-7615 index 5ec8e7eef8..2015d71ce7 100644 --- a/ERCS/ERC-7615 +++ b/ERCS/ERC-7615 @@ -60,8 +60,6 @@ When unsubscribing a contract from a `selector`, publisher contract MUST check w It is OPTIONAL for a publisher contract to use the `inbox` mechanism to store data. -在第四步中,订阅合约应当在实现的 `exec` 函数内处理所有可能的 `selector` 请求及其数据。注意,在某些情况下,发送合约发送的数据可能只包含 `selector` 而不包含推送数据或仅包含部分推送数据,此时可能需要订阅合约请求发送合约的 `inbox` 函数获取推送数据。 - In the fourth step, the subscriber contract SHOULD handle all possible `selector` requests and data in the implementation of `exec` function. In some cases, `exec` MAY call `inbox` function of publisher contract to obtain the pushed data in full. @@ -90,6 +88,7 @@ In the fourth step, the subscriber contract SHOULD handle all possible `selector ``` ### Contract interface + As mentioned above, there are Unconditional Push and Conditional Push two types of implementation. To implement Unconditional Push, the publisher contract SHOULD implement the following interface: ```solidity @@ -113,12 +112,12 @@ interface IPushFree { function cancel(bytes4 selector, address target, bytes calldata data) external; } ``` + `isApproved`, `approve`, and `cancel` have functionalities similar to the corresponding functions in `IPushForce`. However, an additional `data` parameter is introduced here for checking whether a push is needed. The `inbox` here is used to store data in case of being called from the subscriber contract. The publisher contract SHOULD implement `_push(bytes4 selector, bytes calldata data)` function, which acts as a hook. Any function within the publisher contract that needs to implement push mechanism must call this internal function. The function MUST include querying both unconditional and conditional subscription contracts based on `selector` and `data`, and then calling corresponding `exec` function of the subscribers. - A subscriber need to implement the following interface: ```solidity @@ -128,6 +127,9 @@ interface IExec { } ``` +`exec` is to receive requests from the publisher contracts and further proceed to execute. +`isLocked` is to check the status of whether the subscriber contract can unsubscribe the publisher contract based on `selector` and `data`. It is triggered when a request to unsubscribe is received. + ## Reference Implementation ```solidity From c620a87debbc6e124d47820eaaa82a48a283cf84 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:08:48 -0500 Subject: [PATCH 08/15] Update ERC-7615 --- ERCS/ERC-7615 | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ERCS/ERC-7615 b/ERCS/ERC-7615 index 2015d71ce7..5cec7146b3 100644 --- a/ERCS/ERC-7615 +++ b/ERCS/ERC-7615 @@ -130,6 +130,28 @@ interface IExec { `exec` is to receive requests from the publisher contracts and further proceed to execute. `isLocked` is to check the status of whether the subscriber contract can unsubscribe the publisher contract based on `selector` and `data`. It is triggered when a request to unsubscribe is received. +## Rationale + +### Unconditional and Conditional Configuration + +When the sending contract is called, it is possible to trigger a push, requiring the caller to pay the resulting gas fees. +In some cases, an Unconditional Push is necessary, such as pushing price changes to a lending protocol. While, Conditional Push will reduce the unwanted gas consumption. + +### Check `isLocked` Before Unsubscribing + +Before `forceCancel` or `cancel`, the publisher contract MUST call the `isLocked` function of the subscriber contract to avoid unilateral unsubscribing. The subscriber contract may have a significant logical dependence on the publisher contract, and thus unsubscription could lead to severe issues within the subscriber contract. Therefore, the subscriber contract should implement `isLocked` function with thorough consideration. + +### `inbox` Mechanism + +In certain scenarios, the publisher contract may only push essential data with `selector` to the subscriber contracts, while the full data might be stored within `inbox`. Upon receiving the push from the publisher contract, the subscriber contract is optional to call `inbox`. +`inbox` mechanism simplifies the push information while still ensuring the availability of complete data, thereby reducing gas consumption. + +### Using Function Selectors as Parameters + +Using function selectors to retrieve the addresses of subscriber contracts allows +more detailed configuration. +For the subscriber contract, having the specific function of the request source based on the push information enables more accurate handling of the push information. + ## Reference Implementation ```solidity @@ -225,4 +247,27 @@ contract Bar is IPull { } } ``` + +## Security Considerations + +### `exec` Attacks + +The `exec` function is `public`, therefore, it is vulnerable to malicious calls where arbitrary push information can be inserted. Implementations of `exec` should carefully consider the arbitrariness of calls and should not directly use data passed by the exec function without verification. + +### Reentrancy Attack + +The publisher contract's call to the subscriber contract's `exec` function could lead to reentrancy attacks. Malicious subscription contracts might construct reentrancy attacks to the publisher contract within `exec`. + +### Arbitrary Target Approve + +Implementation of `forceApprove` and `approve` should have reasonable access controls; otherwise, unnecessary gas losses could be imposed on callers. + +Check the gas usage of the `exec` function. + +### isLocked implementation + +Subscriber contracts should implement the `isLocked` function to avoid potential loss brought by unsubscription. This is particularly crucial for lending protocols implementing this proposal. Improper unsubscription can lead to abnormal clearing, causing considerable losses. + +Similarly, when subscribing, the publisher contract should consider whether `isLocked` is properly implemented to prevent irrevocable subscriptions. + Copyright and related rights waived via [CC0](../LICENSE.md). From b1e1b59c513ca58f1318cc82ec61ac7ee6ed4f26 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:15:52 -0500 Subject: [PATCH 09/15] Update and rename ERC-7615 to erc-7615 --- ERCS/{ERC-7615 => erc-7615} | 1 + 1 file changed, 1 insertion(+) rename ERCS/{ERC-7615 => erc-7615} (99%) diff --git a/ERCS/ERC-7615 b/ERCS/erc-7615 similarity index 99% rename from ERCS/ERC-7615 rename to ERCS/erc-7615 index 5cec7146b3..85fe8a97bf 100644 --- a/ERCS/ERC-7615 +++ b/ERCS/erc-7615 @@ -270,4 +270,5 @@ Subscriber contracts should implement the `isLocked` function to avoid potential Similarly, when subscribing, the publisher contract should consider whether `isLocked` is properly implemented to prevent irrevocable subscriptions. +## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From feb3ad13de67c19fc9d95ac96b900dc160a450a9 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:17:07 -0500 Subject: [PATCH 10/15] Update erc-7615 --- ERCS/erc-7615 | 1 - 1 file changed, 1 deletion(-) diff --git a/ERCS/erc-7615 b/ERCS/erc-7615 index 85fe8a97bf..db0166d189 100644 --- a/ERCS/erc-7615 +++ b/ERCS/erc-7615 @@ -8,7 +8,6 @@ status: Draft type: Standards Track category: ERC created: 2024-02-03 -requires: --- ## Abstract This ERC proposes a push-based mechanism for sending data, allowing publisher contract to automatically push certain data to subscriber contracts during a call. The specific implementation relies on two interfaces: one for publisher contract to push data, and another for the subscriber contract to receive data. When the publisher contract is called, it checks if the called function corresponds to subscriber addresses. If it does, the publisher contract push data to the subscriber contracts. From 7741d99aec67fa16109a26279fc07eed3375e833 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:21:40 -0500 Subject: [PATCH 11/15] Rename erc-7615 to erc-7615.md --- ERCS/{erc-7615 => erc-7615.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ERCS/{erc-7615 => erc-7615.md} (100%) diff --git a/ERCS/erc-7615 b/ERCS/erc-7615.md similarity index 100% rename from ERCS/erc-7615 rename to ERCS/erc-7615.md From bfb1bf69eefd259688bd75d08ff6942e847af5d2 Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Tue, 4 Jun 2024 22:44:22 -0400 Subject: [PATCH 12/15] Update erc-7615.md --- ERCS/erc-7615.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7615.md b/ERCS/erc-7615.md index db0166d189..7fc153c155 100644 --- a/ERCS/erc-7615.md +++ b/ERCS/erc-7615.md @@ -2,7 +2,7 @@ eip: 7615 title: Atomic Push-based Data Feed Among Contracts description: An Atomic Mechanism to Allow Publisher Contract Push Data to Subcriber Contracts -author: Elaine Zhang (@lanyinzly) , Jerry , Amandafanny , Shouhao Wong (@wangshouh) , Doris Che (@Cheyukj) +author: Elaine Zhang (@lanyinzly) , Jerry , Amandafanny , Shouhao Wong (@wangshouh) , Doris Che (@Cheyukj) , Henry Yuan (@onehumanbeing) discussions-to: https://ethereum-magicians.org/t/erc-7615-smart-contract-data-push-mechanism/18466 status: Draft type: Standards Track From 05c06c7b99ece961e1102d7a22f295a9375f4a1c Mon Sep 17 00:00:00 2001 From: Lanyin Z <106770708+lanyinzly@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:31:52 -0400 Subject: [PATCH 13/15] update svg graph --- ERCS/erc-7615.md | 25 +-------- assets/erc-7615/ERC7615.svg | 109 ++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 24 deletions(-) create mode 100644 assets/erc-7615/ERC7615.svg diff --git a/ERCS/erc-7615.md b/ERCS/erc-7615.md index 7fc153c155..d16891df76 100644 --- a/ERCS/erc-7615.md +++ b/ERCS/erc-7615.md @@ -62,29 +62,7 @@ It is OPTIONAL for a publisher contract to use the `inbox` mechanism to store da In the fourth step, the subscriber contract SHOULD handle all possible `selector` requests and data in the implementation of `exec` function. In some cases, `exec` MAY call `inbox` function of publisher contract to obtain the pushed data in full. -``` -+---------+ +-----------+ +-------------+ -| Client | | Publisher | | Subscriber | -+---------+ +-----------+ +-------------+ - | | | - | Call somefunc(...) | | - |------------------------->| | - | | | - | | Query Subscriber | - | |----------------- | - | | | | - | |<---------------- | - | | | - | | Call exec(bytes4 selector, bytes calldata data) | - | |------------------------------------------------------->| - | | | - | | Result | - | |<-------------------------------------------------------| - | | | - | Result | | - |<-------------------------| | - | | | -``` +![ERC-7615 Workflow](../assets/erc-7615/ERC7615.svg) ### Contract interface @@ -154,7 +132,6 @@ For the subscriber contract, having the specific function of the request source ## Reference Implementation ```solidity -// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; diff --git a/assets/erc-7615/ERC7615.svg b/assets/erc-7615/ERC7615.svg new file mode 100644 index 0000000000..a8754bac14 --- /dev/null +++ b/assets/erc-7615/ERC7615.svg @@ -0,0 +1,109 @@ +ClientPublisherSubscriber Call somefunc(...)Query SubscriberCall exec(bytes4 selector, bytes calldata data)ResultResult + + + + + + + + + + \ No newline at end of file From 5e9f108f87a35c517becfda45ad4df418e0572b2 Mon Sep 17 00:00:00 2001 From: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:02:00 -0400 Subject: [PATCH 14/15] Update erc-7615.md --- ERCS/erc-7615.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7615.md b/ERCS/erc-7615.md index d16891df76..1462b95255 100644 --- a/ERCS/erc-7615.md +++ b/ERCS/erc-7615.md @@ -62,7 +62,7 @@ It is OPTIONAL for a publisher contract to use the `inbox` mechanism to store da In the fourth step, the subscriber contract SHOULD handle all possible `selector` requests and data in the implementation of `exec` function. In some cases, `exec` MAY call `inbox` function of publisher contract to obtain the pushed data in full. -![ERC-7615 Workflow](../assets/erc-7615/ERC7615.svg) +![Workflow](../assets/erc-7615/ERC7615.svg) ### Contract interface From 6cb0915fb32fc989428e53101726baaf37fae50f Mon Sep 17 00:00:00 2001 From: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:15:08 -0400 Subject: [PATCH 15/15] Update erc-7615.md --- ERCS/erc-7615.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7615.md b/ERCS/erc-7615.md index 1462b95255..86f5317fde 100644 --- a/ERCS/erc-7615.md +++ b/ERCS/erc-7615.md @@ -62,7 +62,7 @@ It is OPTIONAL for a publisher contract to use the `inbox` mechanism to store da In the fourth step, the subscriber contract SHOULD handle all possible `selector` requests and data in the implementation of `exec` function. In some cases, `exec` MAY call `inbox` function of publisher contract to obtain the pushed data in full. -![Workflow](../assets/erc-7615/ERC7615.svg) +![Workflow](../assets/eip-7615/ERC7615.svg) ### Contract interface