--- eip: 7017 title: Notification Interface description: A notifications interface for a more engaging blockchain author: Oliver Stehr (@Oli-art) discussions-to: https://ethereum-magicians.org/t/eip-7017-notifications-interface-for-a-more-engaging-blockchain/11091 status: Draft type: Standards Track category: ERC requires: 681, 5630 created: 2022-11-10 --- ## Abstract The following standard allows addresses / smart contracts to send notifications one-to-one and one-to-many. It achieves it in a trustless and decentralized way and without requiring any on-chain interaction by the receivers. It requires a front-end implementation where the notifications are listened to, filtered and showed to the end user (address owner). Some usecases include but are not limited to: - DAO governance voting anouncement - DEX informing an address about a certain price limit being reached, for example a stop-loss or a margin-call. - An NFT marketplace informing an NFT owner about an offer being made to one of it’s NFTs. - A metaverse informing about an important event. - Warning to an address about an ENS domain expiration date approaching. ## Motivation With the adoption of web3 applications, an increasing necessity arises to be informed about certain events happening on-chain. Users are used to being informed, whether it be about news or updates of their favorite applications. As we are in a time of instant data feeds on social media, instant messaging apps and notifications of events that users care about, notifications are a feature in practically every application that exists in web2. They mostly come to email inboxes, SMSs, inside the applications, or in the notification inbox in the operating system. If they would be taken away, the engagement on these web2 applications would sink. This is not different with web3 applications: users cannot be left in the dark about what is going on in them. Not only that, for some applications, all that matters is the participation of users on certain events, like governance on a DAO. In web2, most of the user account’s are linked to an email address that is required at sign-up. This makes it easy to send notifications to specific users and requires no further complexity as an infrastructure exists to deliver a message to the user using their email address. In web3, on the other hand, there's mostly is only one inbox to send notifications to: addresses. Every smart contract can define its own event’s to which one can listen to, but for each of them, a change has to be done in the frontend to listen to that specific contract and event structure. This poses a problem of coordination between smart contracts and web3 applications that can notify users. This EIP aims at proposing a decentralized approach to send and receive notifications from and to ethereum addresses, including smart contracts, in a standarized way, facilitating front-end intrgrations. These could be: - Wallets - Mobile phone dapps - Email services - Discord / Telegram Bots All of these could be notifying about on-chain notifications to the user. ## 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. An approach that is both simple, decentralized and easy to implement is to use a notifications smart contract standard that is **event-based** to be able to emit notifications to one address or broadcast them to anyone that wants to listen. Off-chain **whitelists** would record all addresses a user wants to allow receiving messages from to avoid spam. This is useful for direct messages from one address to another. Off-chain **subscription lists** would indicate which addresses they want to listen for general broadcasts. This is useful for receiving updates on a project. As a user SHALL NOT record its whitelist and subscription list on-chain, the receiver will not do any transaction. Every compliant contract MUST implement the `IERC7017` interface: ```solidity pragma solidity ^0.8.7; interface IERC7017 { /// @notice Send a message. /// @dev When `to` is the zero address, it is considered a broadcast message. event Message (address indexed from, address indexed to, string data); } ``` The event is the message courier. ### Direct Messages v/s Broadcast Messages Messages can be of two types: Direct Messages or Broadcast Messages. Broadcast Messages have no specific receiver and are meant to announce events to all of its subscribers. They MUST have the `to` paramater set to the zero address: `0x0000000000000000000000000000000000000000`, while direct messages MUST set to the receiver address. ### Data Schema The `data` parameter REQUIRED in the message events MUST have a JSON schema as described in this section. It can be written directly as a string, or passed as a URI containing the JSON. It has two different specifications, one for broadcast messages and another for direct messages. Only small differences exist between them. This is the base specifications for both: ```json { "subject": "The subject of the message", "body": "The body of the message", "image_uri": "An image URI", "transaction_request": "A transaction request" } ``` `image_url` and `transaction_request` are OPTIONAL. The `transaction_request` MUST be in the [ERC-681](./eip-681.md) format. The differences between the schemas of Broadcast Messgaes and Direct Messages are as follows: - Direct message data MUST be encrypted. The encryption method used MUST follow [EIP-5630](./eip-5630.md) encryption standard. - Broadcast message's `subject` SHOULD have a maximum size of 30 characters. - Broadcast message's `body` SHOULD have a maximum size of 205 characters. Here is an example for a broadcast message: ```json { "subject": "This is an ERC-7017 message", "body": "This is a message being broadcasted to show you how a contract implementing IERC-7017 can notify its users about an important event. Attached is an image of a unicorn and a request for you to burn 1 eth.", "image_uri": "https://i.pinimg.com/originals/fc/a3/ee/fca3ee19c83bae8e558bcac23d150001.jpg", "transaction_request": "ethereum:0x0000000000000000000000000000000000000000?value=1e18" } ``` ## Rationale ### Initial Idea The initial idea was to have one smart contract which would be called to send messages to addresses. Such messages would be stored in inboxes linked to every address. This was an obvious mistake, as pointed out by the community, as on-chain storage is not neccesary if the messages are not read from within the EVM. All that is needed is for off-chain reading of events. This also eliminated the need for only one smart contract to manage all the messages and now every smart contract could implement the interface with the events. ### Maximum Subject and Body Size Note that only broadcasted messages have a maximum subject and body size. This is to facilitate notifications UX and UI, as this would be the main use of broadcasting messages: notifying users about stuff. As tho why 30 characters for the subject and 205 for the body, these are sizes that are long enough for informing a user about an event, but also fit inisde a standard desktop and mobile notification. Here's an example for your intuition: > **System Maintenance Today** > Attention: Scheduled maintenance > will be conducted today at 10 PM > UTC. Please expect temporary service > interruptions. We apologize for any > inconvenience caused and appreciate > your understanding. > Your Team. The enforcing on these limits is done on the apps that notify the users. Messages surpassing the limits can be managed as the apps desire, but all messages that are within the limits should be shown to the user. ### Transaction Requests Inside a Message Transaction requests can come in a compact string format when using the ERC-681 format. They can be shown to the user as a button inside of the message. This button would ask for the user to sign a transaction that the message sender is requesting. This further improves the user experience in web3. In case the notification is received in an application that is not a wallet, a QR code can be generated based on the transaction request. Many wallets today come with a QR code scanner that can read transaction requests. ### What about Push Protocol's solution? Push Protocol could be thought as a solution to all the problems described and is something that is already in use. But there are many points that make it's use problematic. This problems are: - Despite what they say, their protocol is not really decentralized, as described in their whitepaper. For example, to send a notification, you send a JSON to their API, which they can then pass over to the users that are listening. This is done off-chain and has no way to be verified. There has to be trust in the server running the protocol. - As described in “subscribing-to-channel” section of their whitepaper, their protocol requires subscribers to do a transaction in order to subscribe or unsubscribe. The lists are stored on-chain, which is something that isn’t necessary, as users could choose who to sisten from by doing a filter in the frontend. - To ease this problem, they decided to incentivize the subscribers by paying them for subscribing. This is a cost that goes to the entities emitting the messages, as they are required to stake DAI on behalf of the protocol. This is yet another cost to consider. - Sending and receiving notifications is not only costly, but involves a process that is unnecessarily tied to their servers. The processes involved are uneasy to implement. Sender’s can’t simply send a message from their smart contract at low cost, but they have to go to a DeFi protocol, create an account, stake DAI, develop a way to deliver the message to the protocol, etc. All of this with poor documentation and transparency. - As described in the governance section of their whitepaper, the protocol is not run by users. All decisions will be made by “the Company”. There is no actual governance mechanism in place. Some of this problems could be solved, but most of them are in the very architecture of their solution. Because of this, a new solution must be implemented to overcome them. ## Reference Implementation ```solidity pragma solidity ^0.8.7; contract ERC7017 is IERC7017 { /** * @dev Send a notification to an address from the address executing the function * @param to address to send a notification to * @param data to send: (json format, URI recomended): * {subject, body, image_url (optional), * transaction_request (optional)} */ function walletDM (address to, string memory data) external virtual { emit Message(msg.sender, to, data); } /** * @dev Send a notification to an address from the smart contract * @param to address to send a notification to * @param data to send: (json format, URI recomended): * {subject, body, image_url (optional), * transaction_request (optional)} */ function contractDM (address to, string memory data) external virtual { emit Message(address(this), to, data); } /** * @dev Send a general notification from the address executing the function * @param data to broadcast: (json format, URI recomended): * {subject, body, attention_level (1, 2 or 3), image_url (optional), * transaction_request (optional)} */ function walletBroadcast (string memory data) external virtual { emit Message (msg.sender, address(0), data); } /** * @dev Send a general notification from the address executing the function * @param data to broadcast: (json format, URI recomended): * {subject, body, attention_level (1, 2 or 3), image_url (optional), * transaction_request (optional)} */ function contractBroadcast (string memory data) external virtual { emit Message (address(this), address(0), data); } } ``` ## Security Considerations There are security considerations for the proposal regarding impersonation threats. > It is up to the client-side application to listen only to contracts which make "sensible" choices as far as the meanings of from and to. This is related to how the clients will interpret and filter the events. There can be malicious contracts that implement the notification interface but whose functions emit events where the sender is a third party that did not consent to send the message. Here is an example of a malitious implementation of a BroadcastMsg event impersonating Vitalik Buterin: ```solidity emit BroadcastMsg (0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045, message); ``` This is why the message sender in the log's topic should be verified against the transaction "from" or transaction "to", depending on the notification type (wallet or contract respectively). Cases where the sender doesn't meet these requirements are acceptable under the specification, but contracts implementing these events should be trustworthy. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).