├── assets ├── eep-7 │ └── qrcode.png └── eip-1 │ └── process.png ├── EEPS ├── eep-9.md ├── eep-8.md ├── eep-5.md ├── eep-2.md ├── eep-6.md ├── eep-3.md ├── eep-4.md ├── eep-1.md └── eep-7.md └── README.md /assets/eep-7/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EOSIO/EEPs/HEAD/assets/eep-7/qrcode.png -------------------------------------------------------------------------------- /assets/eip-1/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EOSIO/EEPs/HEAD/assets/eip-1/process.png -------------------------------------------------------------------------------- /EEPS/eep-9.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 9 3 | title: Exception-safe recover_key intrinsic 4 | author: Jeeyong Um (@conr2d) 5 | status: Draft 6 | type: Standard 7 | category: Core 8 | created: 2021-10-20 9 | --- 10 | 11 | ## Simple Summary 12 | 13 | An alternative intrinsic for recovering a key that does not throw an exception with invalid input arguments. 14 | 15 | ## Abstract 16 | 17 | `recover_key` intrinsic throws an exception when given signature is invalid. WASM doesn't support exception handling yet, so it will make a whole transaction fail even when it should not. A new intrinsic `recover_key_safe` does same to `recover_key` but doesn't throw an exception when invalid signature is passed. 18 | 19 | ## Motivation 20 | 21 | `ecrecover` precompiled contract of EVM (Ethereum Virtual Machine) recovers a key (truely address) from the signature like `recover_key` intrinsic of EOSIO. When given signature is invalid, `ecrecover` returns an empty byte array rather than throws an exception, so `recover_key` cannot be used to emulate `ecrecover`. Throwing an exception can be avoided by including libsecp256k1 in WASM binary, but recovering a key in WASM takes up to 80ms with eos-vm-jit or 10ms with eos-vm-oc. This consumes CPU bandwidth too much (not usable in practice), so it needs an alternative exception-safe intrinsic for recovering a key to deploy EVM on WASM. 22 | 23 | ## Specification 24 | 25 | Add a new intrinsic `recover_key_safe`. User can know when it fails to recover a key by comparing the returned size with 0. This intrinsic is activated by the protocol feature `RECOVER_KEY_SAFE`. 26 | 27 | ``` c++ 28 | int recover_key_safe(const capi_checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen); 29 | ``` 30 | 31 | 32 | 33 | ## Rationale 34 | 35 | It would be simpler to make `recover_key` not to throw an exception, but it can break existing contract that rely on the current behavior of `recover_key`. (Some contract might not handle invalid signature case, because it made transaction failed automatically.) It would be safer to add a new intrinsic. 36 | 37 | ## Backwards Compatibility 38 | 39 | This needs a consensus upgrade by protocol feature, but will not break backward compatibility in contracts. 40 | 41 | ## Test Cases 42 | 43 | ## Implementations 44 | 45 | ## Security Considerations 46 | 47 | ## Intellectual Property 48 | I hereby agree that this EEP is subject to this copyright waiver and I certify that I have all necessary rights and permissions to make this submission and to agree to such waiver. 49 | -------------------------------------------------------------------------------- /EEPS/eep-8.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 8 3 | title: Time-Bound Permissions 4 | author: Corvin Meyer auf der Heide <@cmadh> 5 | status: Draft 6 | type: Standard 7 | category: Core 8 | created: 2021-08-03 9 | --- 10 | 11 | ## Simple Summary 12 | 13 | For many use cases, it is useful create **permissions with an expiry date**. 14 | 15 | Especially in applications where even small delays in interaction play a major role, the lowest possible delays are necessary to ensure a smooth user experience. To enable minimal delays and improve the user experience as much as possible, during the interaction with an application that communicates with a smart contract, a **custom permission set on specific actions of one or more smart contracts created with a separate key pair that is used locally by the application to sign transactions could be used instead of one of the common wallets**. However, a permanent permission stored locally and used by an app directly is generally more risky than a permission with an expiry date. 16 | 17 | A good example is interaction-rich games based on EOSIO. Communicating with a wallet reduces the user experience by a lot. Custom permissions that allow signing of **non-value-transferring** ingame actions and the use of internal serialisation and signing can greatly enhance the user experience. However, to minimise the risk, users must remove these custom permissions after finishing playing the game, which is unlikely to be done. Expiring permissions where the expiry date can be set to now + time X would increase security. 18 | 19 | ## Abstract 20 | 21 | I suggest adding an expiry date in the form of an eosio-time (uint32_t) to the permission scheme. This could be set both optionally or by default to uint32_max (Sunday, 7 February 2106). 22 | 23 | The implementation should not be very complex and the check of the expiry date during the validation of the signing authority should not play a major role from a performance point of view, as no heavy algorithms are needed to check whether the current time is less or greater than the expiry date. 24 | 25 | ## Motivation 26 | 27 | The motivation comes from the experience we gained during the development of a highly interaction-rich eosio-based game. A specific stack of APIs and libraries, as well as newly developed patterns integrated into traditional game engines to interface with EOSIO-based chains, are necessary to improve the user experience to the highest possible level for both normal consumers and traditional gamers. To reach this target group, further improvements are necessary and the best possible and fastest serialisation and signing of transactions are an elementary component. 28 | 29 | ## Specification 30 | 31 | I leave a more precise specification to the B1 team or other developers with more detailed insights into the implementation of the permission structure. 32 | 33 | ## Rationale 34 | 35 | ## Backwards Compatibility 36 | 37 | ## Test Cases 38 | 39 | ## Implementations 40 | 41 | ## Security Considerations 42 | 43 | ## Intellectual Property 44 | I hereby agree that this EEP is subject to this copyright waiver and I certify that I have all necessary rights and permissions to make this submission and to agree to such waiver. 45 | -------------------------------------------------------------------------------- /EEPS/eep-5.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 5 3 | title: Silent alerting through on-chain permissions 4 | author: Alexandre Bourget 5 | status: Draft 6 | type: Standard 7 | category: Networking 8 | created: 2019-01-10 9 | --- 10 | 11 | ## Abstract 12 | 13 | When critical network-level events happen, block producers need to 14 | notify other block producers quickly, sometimes to take swift 15 | action. It is also a desirable property that the alert be kept under 16 | wrap, and not published directly to the blockchain. Also, block 17 | producers don't want people to trigger their alerts for any reasons. 18 | 19 | We hereby propose a protocol to allow BPs to receive alerts that can 20 | only be triggered by some specific accounts (like the top 40 BPs or 21 | so), and do not show up on chain, yet use on-chain permissions to 22 | validate the authenticity of the alerts. 23 | 24 | ## Specification 25 | 26 | The specification involves: 27 | * a simple proxy able to forward `/v1/chain` calls to a remote EOSIO node 28 | * intercepting calls to `/v1/chain/push_transaction` 29 | * forwarding that call to a remote EOSIO node 30 | * interpreting the response 31 | * triggering an alert 32 | 33 | To submit an alert, someone would need to craft a transaction to an 34 | action on a contract that: a) `require_auth`'s the sending account, 35 | and b) always fails. Upon submission through 36 | `/v1/chain/push_transaction`, only an edge node would be able to 37 | notice that this transaction exists, would execute it and it would 38 | fail with one of two errors: a) authorization failure error, or b) 39 | assertion failure. 40 | 41 | By reading the response from the speculative execution of that 42 | transaction, the proxy would know that the account sending the 43 | transaction authorized the trigger of an alert. Then, according to 44 | local configuration, a proxy could execute some program which would 45 | trigger a notification to registered employees. For example, it could 46 | require 3 alerts from top-21 BPs, before waking up its employees, or 5 47 | alerts from top 50. 48 | 49 | By proxying `/v1/chain/get_required_keys`, `/v1/chain/get_info` calls 50 | to a real network EOSIO node, one can use any tools (like `cleos` or 51 | EOSIO-compatible libraries) to send the alert signal. 52 | 53 | In case the network is completely broken (ex: all EOSIO nodes are 54 | frozen), those sending alerts might have more pain crafting and 55 | signing the transactions, but the protocol would still work provided 56 | that the implementation has the following fallback mechanism: the 57 | proxy would keep a cache of permissions for the accounts it is allowed 58 | to receive notifications from (trusted accounts, or dynamic BP 59 | accounts), and do local signature verification. 60 | 61 | To avoid being used as a forwarder, the proxy would only attempt to 62 | execute or check transactions that have a single action, with 63 | signature `alwaysfail(account notifier)` 64 | [that action would need to exist on a well-known contract, ideally the system contract], 65 | that is configured as stated above. 66 | 67 | 68 | ## Follow-up discussions 69 | 70 | are happening here: https://github.com/EOSIO/eosio.contracts/issues/169 71 | 72 | 73 | ## Copyright 74 | 75 | Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EEPs 2 | EOSIO Enchancement Proposals (EEPs) describe standards for the EOSIO platform, including core protocol specifications, client APIs, and contract standards. 3 | 4 | # Contributing 5 | 6 | 1. Review [EEP-1](EEPS/eep-1.md). 7 | 2. Fork the repository by clicking "Fork" in the top right. 8 | 3. Add your EEP to your fork of the repository. Please follow the format described in [EEP-1](EEPS/eep-1.md) under the 'What belongs in a successful EEP?' section. 9 | 4. Submit a Pull Request to the EOSIO [EEPs repository](https://github.com/EOSIO/EEPs). 10 | 11 | Your first PR should be a first draft of the final EEP. It must meet the formatting criteria enforced by the build (largely, correct metadata in the header). An editor will manually review the first PR for a new EEP and assign it a number before merging it. Make sure you include a `discussions-to` header with the URL to a discussion forum or open GitHub issue where people can discuss the EEP as a whole. 12 | 13 | If your EEP requires images, the image files should be included in a subdirectory of the `assets` folder for that EEP as follow: `assets/eep-X` (for eep **X**). When linking to an image in the EEP, use relative links such as `../assets/eep-X/image.png`. 14 | 15 | Once your first PR is merged, we have a bot that helps out by automatically merging PRs to draft EEPs. For this to work, it has to be able to tell that you own the draft being edited. Make sure that the 'author' line of your EEP contains either your GitHub username or your email address within triangle brackets (ex: < example@email.com >). If you use your email address, that address must be the one publicly shown on [your GitHub profile](https://github.com/settings/profile). 16 | 17 | When you believe your EEP is mature and ready to progress past the draft phase, you should open a PR changing the state of your EEP to 'Submitted'. An editor will review your submission, mark it 'Ready for Review', and set an ad-hoc meeting to discuss the proposal. The discussions will determine how the proposal will flow through the EEPs lifecycle. 18 | 19 | # EEP Status Terms 20 | * **Draft** - the EEP is currently a work in progress and has not yet been submitted 21 | * **Submitted** - the final draft of the EEP has been subitted by the EEP author 22 | * **Ready for Review** - the EEP has been reviewed by an EEP editor and has been added to the agenda for the next EEP review meeting 23 | * **Accepted** - the EEP was analyzed and discussed by the EEP reviewers and has sufficient support for implementation 24 | * **Under Development** - the EEP is currently under developmnet 25 | * **Pending PR Review** -the EEP implementation is currently being reviewed for final acceptance 26 | * **Final** - the EEP has been successfully implemented and is now active 27 | * **Deferred** - the EEP has been shelved for future consideration 28 | * **Living** - this is similar to Final, but denotes an EEP which requires regular updates for accuracy (good for token/wallet standards) 29 | * **Archived** - the EEP is no longer under consideration (withdrawn by author, not enough support for the proposal, etc.) 30 | 31 | # Telegram 32 | If you are interested in discussing proposal ideas, providing feedback on existing proposals or the EEPs process, or want to get more involved, join the EEPs Telegram group. [[EOSIO Enhancement Proposals Telegram](https://t.me/eos_enhancements_proposals)] 33 | -------------------------------------------------------------------------------- /EEPS/eep-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 2 3 | title: Linking Accounts to Web Properties 4 | author: Josh Kauffman , Alexandre Bourget , Marc-Antoine Ross , Stephane Duschesneau , Matthieu Vachon 5 | status: Draft 6 | type: Standard 7 | category: Core 8 | created: 2018-10-10 9 | --- 10 | 11 | ## Summary 12 | 13 | For many use cases, it is useful to an EOS account owner to prove it 14 | owns an account on certain web properties (like social medias, or a 15 | website). 16 | 17 | We are proposing a protocol to do verification of such web properties, 18 | along with a contract that a user can use to claim those 19 | verifications, similar to how [Keybase](https://keybase.io) works. 20 | 21 | This can be used to increase trust of an account, so that another user 22 | will be more or less likely to enter into a transaction with them. 23 | 24 | The goal is to introduce increased trust into the ecosystem. We 25 | envision that Block Explorers will be able to scrape data from this 26 | mechanism to display verified properties. 27 | 28 | 29 | ## Motivation 30 | 31 | The original motivation came from seeing ECAF send out messages to user accounts whom they were trying to reach. 32 | Without an easy and verifiable means for another account to verify that this is the *the* ECAF EOS account, there 33 | is no reason to expect trust to be assumed. 34 | 35 | ## Specification 36 | 37 | We hereby specify a smart contract interface and behavior, a data 38 | structure for on-chain storage, and a verification protocol for each 39 | types of web properties (each social media sites accounts, or more 40 | generally a website). 41 | 42 | ### Proposed smart contract 43 | 44 | We propose the `accountsjson` smart contract, which, very similar to 45 | [producerjson](https://github.com/greymass/producerjson) and [regproxyinfo](https://github.com/AlohaEOS/eos-proxyinfo), stores a piece of JSON in the 46 | format specified herein. 47 | 48 | * Action `set(account_name owner, string json)` 49 | 50 | The `set` action authorized the `owner` to store and pay for RAM of 51 | the storage of the `json` UTF-8 encoded string. It is expected to be a 52 | valid JSON document that follows this specification. 53 | 54 | ### JSON structure 55 | 56 | Example JSON structure: 57 | 58 | ``` 59 | { 60 | "name": "Long form name", 61 | "website": "https://example.com", 62 | "accounts": { 63 | "twitter": { 64 | "handle": "example_account", 65 | "claim": "https://twitter.com/example_account/status/100000000000000000000" 66 | }, 67 | "github": { 68 | "handle": "example_account", 69 | "claim": "https://gist.github.com/example_account/1010101deadbeef1010101" 70 | }, 71 | }, 72 | "contract": { 73 | "repo": "https://github.com/organization/repository", 74 | "rev": "v1.0.0" 75 | } 76 | } 77 | ``` 78 | 79 | Fields: 80 | * `name` **string** -- would be a long-form, properly capitalized, full name of either the person or organization, like "The ACME Company", or "Albert Einstein". 81 | * `website` **string** -- a full-qualified domain name, with connection scheme and optional path. 82 | * `accounts` **Object** -- holds a map of social media properties, which are to be defined in this specification before added (to avoid collision or conflict). 83 | * `accounts.[site].handle` **string** -- defines the simplest expression of the handle on the social media website. For example, a Twitter would **not** include the proverbial `@` sign. 84 | * `accounts.[site].claim` **string** -- the URL of a claim to link the account specified in the `owner` field of the `set()` action call. Claims are specified according to the _verification protocol_ (see below) and are site specific. 85 | * `contract` **Object** -- holds information about the deployed contract on the `owner` account (specified in `set()`), it can be used to build the code living at the given revision and repository, and to assert that the code living on chain under the `owner` account, corresponds to the source code living in the repository. 86 | * `contract.repo` **string** -- holds a URL to a clonable source code repository 87 | * `contract.rev` **string** -- is the revision of the code in that cloned code repository; it can be a tag, a hash or a branch (provided the latter doesn't move) 88 | 89 | 90 | ### Verification protocol 91 | 92 | Verifications can happen for 93 | 94 | Note that the path will be stripped for verification. 95 | 96 | #### Simple CSV file format 97 | 98 | As refered to further down this document, the simple `.csv` file format is comprised of: 99 | 100 | * Optionally specified headers, with values: `chain_id_prefix,account_name` 101 | 102 | * A list of accounts in the format: `chain_id_prefix,account_name` 103 | where `chain_id_prefix` is the first 8 characters of the hexadecimal 104 | representation of the chain_id, followed by a comma `,`, followed by 105 | an EOSIO name-encoded account name (the famous 12 characters-max 106 | account name) 107 | 108 | Example of account `testtesttest` on the EOS mainnet: 109 | aca376f2,testtesttest 110 | 111 | 112 | #### Website verification 113 | 114 | Website verifications requires the 115 | `/.well-known/eosio-accounts/claims.csv` file to be filled, as a 116 | top-level directory of the domain specified in `website`. Verification 117 | strips any path element specified in the `website` field of the `json` 118 | parameter of the `set` action. 119 | 120 | The contents of that `claims.csv` file is defined as the _Simple CSV 121 | file format_ above. 122 | 123 | A website becomes verified when: 124 | 125 | 1. One of the lines in the retrieved `claims.csv` matches the `owner` 126 | account, equal to the `account_name` field in the CSV (for which we 127 | saw a `set` action go through), on the chain with the corresponding 128 | `chain_id`, matching the `chain_id_prefix` specified in the CSV 129 | file. 130 | 131 | 132 | #### GitHub handles and claims 133 | 134 | Verification for GitHub happens by verifying a **gist** published by 135 | the owner of the account, that includes a file named 136 | `eosio-accounts-claims.csv`; that's plural `accounts` and plural 137 | `claims`, separated by dashes, ending with `.csv`. 138 | 139 | The contents of that `eosio-accounts-claims.csv` file is defined as 140 | the _Simple CSV file format_ above. 141 | 142 | A claimed GitHub identity becomes verified when all of these are true: 143 | 144 | 1. One of the lines in retrieved `eosio-accounts-claims.csv` matches 145 | the `owner` account, equal to the `account_name` field in the CSV 146 | (for which we saw a `set` action go through), on the chain with the 147 | corresponding `chain_id`, matching the `chain_id_prefix` specified 148 | in the CSV file. 149 | 150 | 2. The GitHub `handle` claimed under `accounts.github` (in the `json` 151 | parameter of the `set` action) matches the creator of the Gist 152 | (that would be `owner.login` in the response of the GitHub API). 153 | 154 | 155 | #### Twitter handles and claims 156 | 157 | To be defined, but similar to the othe verification methods, verifying 158 | a Tweet in the format: 159 | 160 | ``` 161 | I own the #eosio account [account_name] on the chain [chain_id_prefix]. 162 | ``` 163 | 164 | where, again, the `chain_id_prefix` is the first 8 characters of the 165 | hex representation of the chain's `chain_id`. 166 | 167 | 168 | #### 169 | 170 | 171 | ## References 172 | 173 | [eosproxyinfo]: https://github.com/AlohaEOS/eos-proxyinfo published as `eosproxyinfo` on mainnet (`aca376f2`) 174 | [producerjson]: https://github.com/greymass/producerjson published as `producerjson` on `aca376f2` 175 | [Draft Implementation]: https://github.com/eoscanada/accountsjson 176 | 177 | 178 | ## Copyright 179 | 180 | Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). 181 | -------------------------------------------------------------------------------- /EEPS/eep-6.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 6 3 | title: EOS Mainnet Extension Chains 4 | author: Alexandre Bourget, Richard Reiner, Guillaume Babin, Mathieu Boulianne 5 | status: Draft 6 | type: Standard 7 | category: Networking 8 | created: 2019-04-20 9 | --- 10 | 11 | ## Abstract 12 | 13 | This paper outlines a proposal for __EOS Mainnet Extensions__, which are side-chains of the EOS Mainnet which share user accounts with the Mainnet by means of an account-synchronizing Oracle, described below. 14 | 15 | This approach provides easy and linear horizontal scalability, complementing the already-impressive vertical scalability of the EOSIO platform, and effectively multiplying available resources (RAM, CPU and Network bandwidth) with each network _without_ the creation of any new token. 16 | 17 | This approach, by providing a horizontal multiplier to the vertical scalability of the EOSIO platform, helps to fully realize the scaling potential of EOS, and opens up competition for dapps: dapp developers needing a distributed database can choose the instance that fits their needs, at their price point, or even start their own, all the while keeping the accessible user base growing. 18 | 19 | 20 | 21 | ## Current state of affairs 22 | 23 | The EOSIO platform provides a distributed database abstraction in which people with registered accounts can mutate database tables (by issuing a transaction), provided they follow on-chain rules (defined in smart contracts). 24 | 25 | The EOS mainnet, launched in June 2018, provides impressive scalability (currently performing in the range of thousands of transactions per second), and shares its resources with all its users by means of two methods: 26 | 27 | * a market for RAM allocation 28 | * staking of the network token for CPU / Network bandwidth allocations 29 | 30 | The governance of the EOS Mainnet is managed by delegated proof of stake, meaning that EOS holders vote for a number of entities that produce blocks, with a one token -> one-to-thirty vote setting. 31 | 32 | 33 | 34 | ## Key Aspects of this Proposal 35 | 36 | 1. On a Mainnet Extension, it is impossible to create an account, except that the `eosio` account can do so. 37 | 38 | 2. All account creations are done by synchronizing accounts existing on the EOS Mainnet accounts onto the Extension chain (including changes in authority). The accounts are synced by the BPs running the Extension network. This is done through an Oracle (see below). 39 | 40 | 3. The resources of the Extension network would be managed by the BPs as they offer the physical resources (see below). 41 | 42 | 4. The expectations placed on the BPs of an Extension network are clear: the BPs merely operate the network. The BPs may jointly commit to service levels, which are reflected in the pricing of the resources of the particular Extension network. 43 | 44 | 5. The Extension network does not have its own token, and BPs are paid directly on the EOS Mainnet through a corresponding contract. EOS tokens can flow to the Extension network, through the same Oracle and set of BPs that run the Extension network, and live in the `eosio.token` contract over there. 45 | 46 | 6. Each chain Extension is free to experiment with governance, and the provided services. 47 | 48 | 1. As an example, a BP in an Extension network can be ejected by supermajority vote (15/21) of the other BPs of that network, or other rules defined by them when they launch the Extension network. 49 | 50 | 51 | 52 | ## Trust model 53 | 54 | Users of an Extension Network accept a level of trust in the BPs operating that network, both to some extent in individual BPs and to a greater degree, in the supermajority of those BPs. They do this in order to obtain pragmatic benefits in terms of available resources, SLAs, etc. 55 | 56 | In determining their level of trust in a particular Extension Network and its BPs, users may consider: 57 | 58 | * The individual reputations of the BP entities 59 | * The independence (or not) of the BP entities from one another 60 | * The levels of transparency provided by the BPs, individually and collectively 61 | * On some networks, bonds for correct operation may be posted by the BPs, individually or collectively. 62 | 63 | 64 | 65 | ## Resource allocation and BP incentivization mechanisms 66 | 67 | All three physical resources (RAM, CPU and Network bandwidth) could be initially sold using EOS on the Mainnet and be allocated to the Extension Network. On top of the initial sale of resources, BPs could be rewarded from fees from secondary transactions of these resources, could capture an annual interest rate on held resources, could set resources pricing or use algorithmic market-making like on the Mainnet. 68 | 69 | Other mechanisms could be thought of, but all in all, something close to the cost (plus margin, of perhaps 100%) would be charged to those requiring a decentralized database. 70 | 71 | CPU is absolutely transient. Net creates blockchain bloat, so a long-term fee could exist. RAM is clearly a long-term resource. 72 | 73 | To help with cost expectations and decision making when choosing an Extension network, pricing of resources could be done in USD, based on a price feed ran by the Extension Network BPs. 74 | 75 | Transfering EOS from Mainnet to the Extension Network could be charged at a fixed USD value (set by BPs), and the same for the reverse (from Exten Net to Mainnet), to account for the costs BPs will incur on Mainnet (and generally prevent spam). This fee could be adjusted by those BPs. 76 | 77 | For EOS tokens locked in to allocate resources on the Extension Network, an interest rate would be taken (using an ever-increasing number like vote weighting on Mainnet, so that everyone is affected by changes in interest rate). 78 | 79 | 80 | 81 | ## Oracle design 82 | 83 | Most operations would happen in a smart contract on the EOS mainnet, and corresponding operations would be transported through IBC to the Extension Network: 84 | 85 | * Registration, unregistration of potential BPs 86 | * Modifications of production schedule for the Extension Network: when hiring or firing a BP, or optimizing the handoff latency. 87 | * Transferring EOS to the other network. 88 | * Buying/selling of extension network resources. 89 | 90 | The same Oracle can be used in reverse, sending transactions back to EOS Mainnet, like: 91 | 92 | * Token withdrawals from the Extension Network 93 | * Any sort of operational feedback useful to the different algorithms, like current resource usages, to adjust interest rate. 94 | 95 | Transaction receipts on either network are observed by all BPs running the Extension network (like account creations/updates, modifications of the Extension network schedule, updated resources allocations, token transfers concerning the network, etc..). 96 | 97 | These original transactions are then transformed into transactions targeting the _other_ network. Using the Oracle software, each BP crafts the target transaction locally, then signs it and broadcasts to other BPs (on a small BP-only network) only the associated **signature + transaction hash prefix**. The reason for partial transaction hash propagation is that each node needs to come up with the transaction according to the rules agreed upon, and not broadcast the transaction itself (where others would simply cross-sign blindly). 98 | 99 | Once one of them aggregates 15 signatures, it pushes it to the extension chain. 100 | 101 | Smart contracts on each side must protect against missing block segments, and the Oracle must only propose changes in irreversible blocks. 102 | 103 | 104 | 105 | ## Thoughts on Future Scaling 106 | 107 | When the EOS mainnet has 1 billion users, a good chunk of the RAM will be there solely to store user accounts. At that point, some Extension Networks may sync only parts of the user base (while still disallowing local creation of accounts, which is key), either by sub-`.domains`, or by having people opt into synchronization, by sending an initial transfer to have their account sync'd from then on. 108 | 109 | 110 | ## Follow up discussions 111 | 112 | * [GitHub issue](https://github.com/eoscanada/EEPs/issues/32) for further discussion. 113 | * [Telegram channel](https://t.me/eos_extensions) 114 | 115 | 116 | ## Copyright 117 | 118 | Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). 119 | -------------------------------------------------------------------------------- /EEPS/eep-3.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 3 3 | title: Proposed EOSIO Token Standard 4 | author: Buddy Deck (@deckb) 5 | status: Draft 6 | type: Standard 7 | category: Interface 8 | created: 2021-07-22 9 | --- 10 | 11 | ## Simple Summary 12 | 13 | For the token contract, describe the mandatory and optional tables and actions that can be accessed on an EOSIO chain. 14 | 15 | ## Abstract 16 | 17 | There are many ways to design and implement a token contract. This token standard looks to provide guidelines towards a minimum basic set of mandatory and optional items that make up a token contract. 18 | 19 | ## Motivation 20 | 21 | The first iteration of this standard mirrors the currently implemented eosio.token contract. It will serve as a first step in defining a standard for tokens on EOSIO based chains. This standard will allow common APIs to be developed to query token contracts and enable validation checks on contracts to ensure a contract meets the standard. This proposal is meant to start a conversation between community members and is expected to be iterated on based on those conversations. 22 | 23 | ## Proposed Specification 24 | 25 | ### Tables 26 | 27 | #### accounts 28 | 29 | ##### scope 30 | `name` of the account holder. 31 | 32 | ##### primary key 33 | `symbol` of the token. 34 | 35 | ##### columns 36 | balance: `asset` balance of the token holder. 37 | 38 | #### stat 39 | 40 | ##### scope 41 | `symbol` of the token. 42 | 43 | ##### primary key 44 | `symbol` of the token. 45 | 46 | ##### columns 47 | supply: `asset` holding the current supply of the token. 48 | 49 | max_supply: `asset` holding the maximum supply of the token. 50 | 51 | issuer: `name` of the account that can create more tokens. 52 | 53 | 54 | ### Actions 55 | 56 | #### close 57 | Close the account of the `owner` for the token `symbol`. 58 | ##### required authorizer 59 | The `owner` account holder 60 | 61 | ##### parameters 62 | owner: `name` of the token holder closing the account. 63 | 64 | symbol: `symbol` of the token to close. 65 | 66 | ##### prerequisites 67 | - The `owner` and `symbol` must exist in the accounts table. 68 | - The `owner` balance must be zero. 69 | 70 | ##### postcondition 71 | - The `owner` and `symbol` must not exist in the accounts table. 72 | 73 | #### create 74 | Allows the `issuer` account to create a token with a maximum supply. 75 | 76 | ##### required authorizer 77 | token smart contract account 78 | 79 | ##### parameters 80 | issuer: `name` of the account who can issue tokens. Can be any account name. 81 | 82 | maximum_supply: `asset` setting the maximum supply of the token 83 | 84 | ##### prerequisites 85 | - Token symbol must be valid. 86 | - Token symbol must not exist in stat table. 87 | - maximum_suply has to be smaller than the maximum supply allowed by the system: 2^62 - 1. 88 | - maximum_supply must be positive. 89 | ##### postcondition 90 | - symbol must exist in the stat table 91 | - maximum_supply column must equal maximum_supply parameter 92 | - supply column must equal 0. 93 | 94 | #### issue 95 | Amount of tokens that will be issued to an account. 96 | 97 | ##### required authorizer 98 | `issuer` used when the token was created. 99 | 100 | ##### parameters 101 | to: `name` of the account who can issue the token. 102 | quantity: `asset` amount of the tokens that will be issued. 103 | memo: `string` of characters describing the issuance. 104 | 105 | ##### prerequisites 106 | - The `memo` is less than 256 bytes. 107 | - The `quantity` `symbol` was created prior to `issue` being called. 108 | - `to` is the `issuer` used in the create call. 109 | - `quantity` must be positive and less than the `maximum_supply` - `current_supply` 110 | 111 | ##### postcondition 112 | - `accounts` table must have a scope of to and a primary key of `quantity.symbol` 113 | - `balance` must increase by exactly `quantity` for scope of to and primary key of `quantity.symbol` 114 | - `current_supply` in stat must increase by exactly `quantity` 115 | 116 | #### open 117 | Open a zero balance token account for owner with ram_payer paying for the RAM. Must be a no-op if the accounts table row already exists for this owner and symbol. 118 | 119 | ##### required authorizer 120 | `ram_payer` 121 | 122 | ##### parameters 123 | owner: `name` of the account to hold the zero balance. 124 | symbol: `symbol` of the token to open a token account. 125 | ram_payer: `name` of the account paying for the RAM. 126 | 127 | ##### prerequisites 128 | - `ram_payer` has enough RAM. 129 | - The `owner` account exists. 130 | - The `symbol` was created prior to `open` being called. 131 | ##### postcondition 132 | - `accounts` table must have a scope of to and a primary key of `quantity.symbol` 133 | - `ram_payer` must be payer for the row created in `accounts` with a scope of `symbol` and primary key of `owner` 134 | - `quantity` must be 0 with correct `symbol` if no row existed in `accounts` with a scope of `symbol` and primary key of `owner` prior to this action 135 | 136 | 137 | #### retire 138 | Remove quantity from the current supply. 139 | 140 | ##### required authorizer 141 | `issuer` of the token. 142 | 143 | ##### parameters 144 | quantity: `asset` to remove from circulation. 145 | memo: `string` describing the transaction. 146 | 147 | ##### prerequisites 148 | - `asset.symbol` exists. 149 | - `supply` - `quantity` is greater or equal to 0. 150 | - `memo` is less than 256 bytes. 151 | 152 | ##### postconditions 153 | - The row of `accounts` with a scope `issuer` and primary key of `quantity.symbol` balance column must decrease by exactly `quantity` 154 | - `stat` column `current_supply` must decrease by exactly `quantity` 155 | 156 | #### transfer 157 | Send tokens from the `from` account to the `to` account. 158 | 159 | ##### required authorizer 160 | `from` account 161 | 162 | ##### parameters 163 | from `name` of the account sending the tokens. 164 | to `name` of the account receiving the tokens. 165 | quantity `asset` amount to send. 166 | memo `string` describing the transfer. 167 | 168 | ##### prerequisites 169 | - The `to` account exists and is not equal to `from`. 170 | - `quantity` is positive and is a valid `quantity`. 171 | - `memo` is less than 256 bytes. 172 | - `from` liquid balance is greater than `quantity`. 173 | ##### postconditions 174 | - The row of `accounts` with a scope `from` and primary key of `quantity.symbol` `balance` column must decrease by exactly `quantity` 175 | - The row of `accounts` with a scope `to` and primary key of `quantity.symbol` `balance` column must increase by exactly `quantity` 176 | - `from` account is notified of transfer using `require_recipient` 177 | - `to` account is notified of transfer using `require_recipient` 178 | 179 | #### transferfee (optional) 180 | Send tokens from the `from` account to the `to` account. 181 | 182 | ##### required authorizer 183 | `from` account 184 | 185 | ##### parameters 186 | from `name` of the account sending the tokens. 187 | to `name` of the account receiving the tokens. 188 | quantity `asset` amount to send. 189 | fee `asset` amount to pay as a fee to an account defined by the contract. 190 | memo `string` describing the transfer. 191 | 192 | ##### prerequisites 193 | - The `to` account exists and is not equal to `from`. 194 | - `quantity` is positive and is a valid `quantity`. 195 | - `memo` is less than 256 bytes. 196 | - `from` liquid balance is greater than `fee` plus `quantity`. 197 | 198 | ##### postconditions 199 | - The row of `accounts` with a scope `from` and primary key of `quantity.symbol` `balance` column must decrease by exactly `quantity` + `fee` 200 | - The row of `accounts` with a scope `to` and primary key of `quantity.symbol` `balance` column must increase by exactly `quantity` 201 | - The row of `accounts` with a scope `issuer` and primary key of `quantity.symbol` `balance` column must increase by exactly `fee` 202 | - `from` account is notified of `transfer` using `require_recipient` 203 | - `to` account is notified of `transfer` using `require_recipient` 204 | 205 | #### API 206 | This section contains pseudo code describing what an API could look like. 207 | ##### Get Account Balance 208 | reference 209 | https://developers.eos.io/manuals/eos/latest/nodeos/plugins/chain_api_plugin/api-reference/index#operation/get_table_rows 210 | ###### function 211 | asset getBalance( name code, name account_name, symbol sym ) { 212 | return get_table_rows( code, “accounts”, account_name, lower_bound=sym, limit=1 ).rows[0].balance 213 | } 214 | ##### Get Supply Information 215 | ###### reference 216 | https://developers.eos.io/manuals/eos/latest/nodeos/plugins/chain_api_plugin/api-reference/index#operation/get_table_rows 217 | 218 | ###### function 219 | ``` 220 | asset getSupply( name code, symbol sym ) { 221 | return get_table_rows( code, sym, stat, limt=1 ).rows[0].supply 222 | } 223 | ``` 224 | 225 | ##### Get Total Supply Information 226 | 227 | ###### reference 228 | https://developers.eos.io/manuals/eos/latest/nodeos/plugins/chain_api_plugin/api-reference/index#operation/get_table_rows 229 | 230 | ###### function 231 | ``` 232 | asset getTotalSupply( name code, symbol sym ) { 233 | return get_table_rows( code, sym, stat, limit=1 ).rows[0].max_supply 234 | } 235 | ``` 236 | 237 | ## Backwards Compatibility 238 | 239 | N/A 240 | 241 | ## Test Cases 242 | 243 | # Implementation 244 | 245 | [Sample Contract](https://github.com/EOSIO/eosio.token/tree/main/contracts/eosio.token) 246 | 247 | ## Intellectual Property 248 | I hereby agree that this EEP is subject to this copyright waiver and I certify that I have all necessary rights and permissions to make this submission and to agree to such waiver. 249 | -------------------------------------------------------------------------------- /EEPS/eep-4.md: -------------------------------------------------------------------------------- 1 | --- 2 | eep: 4 3 | title: Creating standard `type` for use with eosio.forum contract 4 | author: Josh Kauffman , Alexandre Bourget , Matthieu Vachon , Shaq Kheder 5 | status: Archived 6 | type: N/A 7 | category: N/A 8 | created: 2018-11-22 9 | --- 10 | 11 | ## Summary 12 | 13 | The `eosio.forum` contract, currently found in the [eoscanada/eosio.forum](https://github.com/eoscanada/eosio.forum) 14 | repository allows for users to cast a vote on a proposal to register their sentiment on-chain. Since this contract 15 | can be used for simple polls all the way up to chain-altering referenda, there exists a need to define the different 16 | kinds of standard uses, as well as the expected inputs/outputs/displays for each. 17 | 18 | *For the purpose of this EEP, we will ignore the messaging aspect of the `eosio.forum` contract (post, unpost, status)* 19 | 20 | ## Motivation 21 | 22 | When the `eosio.forum` contract was announced as being in Beta in November 2018, one of the first things realized 23 | is that there were no clear definitions for what should be within the `type` field when creating a new `proposal`. 24 | Further, there was no clear definition of when certain `types` should dictate further action by Block Producers 25 | based on the result of the vote, nor was there any convention for how UIs were expected to display/handle `proposals`. 26 | 27 | There was also demand for different kinds of responses, as the majority of thought up until launching the beta 28 | was around Yes/No questions, as that was what was relevant for a referendum question as outlined in the Constitution 29 | that was available on the EOS mainnet. Namely, there was need to add definition around multiple choice questions 30 | (3 or more options) and around Multi-Select questions so as to make the contract more useful. 31 | 32 | ## Specification 33 | 34 | ### General Behaviour/Definitions (Apply to all proposal types) 35 | 36 | A `vote_value` of `255` will represent an `Abstain` vote, except for `multiselect-v` which wil utilize a `vote_value` of `0` to represent `Abstain`. 37 | An `Abstain` vote will count towards voter participation of the overall vote (if that metric is being observed). 38 | For example, for proposal type `referendum-v1`, a `vote_value` of `255` shall not count towards `No` or `Yes`, but the staked amount will count towards voter participation for the "15% voter participation threshold". 39 | Any submitted `vote_value` that does not fall into any of the expected results will be ignored. 40 | 41 | Votes are weighted using information from the `staked` table for voter info. If a user has not voted, then the weight 42 | of their vote will be taken from the `delband` table. To clarify, a voter's weight should be equal to their self-staked 43 | and staked-towards-another-account amount. Stake that has been delegated towards an account will not be used when 44 | calculating the weight of their vote. This is to avoid a user going to a delegation service and renting resources 45 | to enhance their voting weight. 46 | 47 | Proxy voting should be handled by first delegating the `staked` amount of a user towards its proxy. If the user 48 | casts a vote on a `proposal`, then their `stake` shall be removed from their proxy and weighted towards their 49 | chosen `vote_value` on its own. 50 | 51 | ### Referendum 52 | 53 | `referendum-v1` should be seen as the only `type` that Block Producers should utilize as a signal 54 | to act upon. The available responses are always `0`:`No`, `1`:`Yes`, `255`:`Abstain` 55 | UIs can display the voting buttons along with their value e.g. "0 - No", "1 - Yes" and "255 - Abstain" 56 | so that a user can easily verify their vote through any block explorer, without the need to already 57 | have the knowledge that a `vote_value` of 0 properly signifies their vote of "No", and so on. 58 | 59 | ``` 60 | { 61 | "type":"referendum-v1", 62 | "content":"content here" 63 | } 64 | ``` 65 | 66 | Example: 67 | ``` 68 | { 69 | "type":"referendum-v1", 70 | "content":"Should EOS change its symbol to SYS?" 71 | } 72 | ``` 73 | **_Summary Notes_** 74 | 75 | Standard `vote_value`: 76 | 77 | `0` - "No" 78 | 79 | `1` - "Yes" 80 | 81 | `255` - "Abstain" 82 | 83 | If a vote of `type`:`referendum-v1` passes the required thresholds as defined in the goverenance documents, 84 | Block Producers should act upon the result of this referendum. 85 | 86 | As of writing, Article XI of the Constitution reads as: 87 | 88 | "This Constitution and its subordinate documents shall not be amended except by a vote of the token holders with no less than 15% vote participation among tokens and no fewer than 10% more Yes than No votes, sustained for 30 continuous days within a 120 day period." 89 | 90 | _See [pre-launch discussion](https://forums.eosgo.io/discussion/820/article-xvi-v0-3-0-draft-eos-io-constitution-amendment#latest) for further clarification_ 91 | 92 | "15% vote participation" is defined as 93 | ``` 94 | `staked`:`total` / `total_EOS_currency_supply` being above 0.15 or not. 95 | ``` 96 | 97 | "10% more Yes than No votes" is defined as a check on whether 98 | ``` 99 | `staked`:`1` > ( 0.55 * ( `staked`:`0` + `staked`:`1` )) 100 | ``` 101 | 102 | ### Yes/No Poll 103 | 104 | `poll-yn-v1` should be used for any polling that uses only Yes/No responses, and 105 | is not being proposed as an actionable vote for Block Producers. This should only be used for polling sentiment. 106 | The available responses are always `0`:`No`, `1`:`Yes` 107 | All UIs should display the voting buttons along with their value e.g. "0 - No" and "1 - Yes" 108 | so that a user can easily verify their vote through any block explorer, without the need to already 109 | have the knowledge that a `vote_value` of 0 properly signifies their vote of "No", and so on. 110 | 111 | ``` 112 | { 113 | "type":"poll-yn-v1", 114 | "content":"content here" 115 | } 116 | ``` 117 | 118 | Example: 119 | ``` 120 | { 121 | "type":"poll-yn-v1", 122 | "content":"Should EOS change its symbol to SYS?" 123 | } 124 | ``` 125 | 126 | **_Summary Notes_** 127 | 128 | Standard `vote_value`: 129 | 130 | `0` - "No" 131 | 132 | `1` - "Yes" 133 | 134 | As this `type` of poll is not used for an official chain-altering decision, Block Producers 135 | should **not** act in any meaningful way to the results of these polls. This can be useful for 136 | determining a path to take in further discussions, or whether or not a question would be worthwhile 137 | being proposed for a `referendum`. 138 | 139 | ### Yes/No/Abstain Poll 140 | 141 | `poll-yna-v1` should be used for any polling that uses only Yes/No/Abstain responses, and 142 | is not being proposed as an actionable vote for Block Producers. This should only be used for polling sentiment. 143 | The available responses are always `0`:`No`, `1`:`Yes`, `255`:`Abstain` 144 | UIs can display the voting buttons along with their value e.g. "0 - No", "1 - Yes", and "255 - Abstain" 145 | so that a user can easily verify their vote through any block explorer, without the need to already 146 | have the knowledge that a `vote_value` of 0 properly signifies their vote of "No", and so on. 147 | 148 | _For clarification, abstain is defined as "formally decline to vote either for or against a proposal or motion"_ 149 | 150 | ``` 151 | { 152 | "type":"poll-yna-v1", 153 | "content":"content here" 154 | } 155 | ``` 156 | 157 | Example: 158 | ``` 159 | { 160 | "type":"poll-yna-v1", 161 | "content":"Should EOS change its symbol to SYS?" 162 | } 163 | ``` 164 | 165 | **_Summary Notes_** 166 | 167 | Standard `vote_value`: 168 | 169 | `0` - "No" 170 | 171 | `1` - "Yes" 172 | 173 | `255` - "Abstain" 174 | 175 | As this `type` of poll is not used for an official chain-altering decision, Block Producers 176 | should **not** act in any meaningful way to the results of these polls. This can be useful for 177 | determining a path to take in further discussions, or whether or not a question would be worthwhile 178 | being proposed for a `referendum`. 179 | 180 | The addition of "Abstain" allows a user to have their vote count towards participation 181 | to help signal community enthusiasm, while essentially delegating their decision to those 182 | who cast a Yes or No vote. This can help for deciding if a vote should then become a 183 | referendum, and whether or not it might receive enough voter participation. 184 | 185 | ### Options Poll 186 | 187 | `options-v1` should be used for any polling that requires multiple custom responses (`proposer` can 188 | specify up to 254 different responses, and reserve `vote_value` of `255` for "Abstain"). 189 | UIs should fetch the possible responses from the "options" array. UIs should push a vote value 190 | equal to the positon of the repsonse in the table (0-indexed). You can display the button as 191 | "`value` - `response`" so that a user can easily verify their vote through any block explorer, while 192 | lowering the amount of RAM needed to vote. 193 | 194 | ``` 195 | { 196 | "type":"options-v1", 197 | "content":"content here" 198 | "options": [ 199 | "option1" 200 | "option2" 201 | "option3" 202 | ] 203 | } 204 | ``` 205 | 206 | Example 207 | ``` 208 | { 209 | "type":"options-v1", 210 | "content":"Should EOS change its symbol?" 211 | "options": [ 212 | "EOS" 213 | "SYS" 214 | "SOE" 215 | "EEE" 216 | "B1" 217 | "Other" 218 | ] 219 | } 220 | ``` 221 | In this example, if a user selected the option "SYS", then the expected `vote_value` will be `1`. 222 | 223 | **_Summary Notes_** 224 | 225 | There are no standard `options` defined for this `type`. Options are all `proposer`-defined. 226 | 227 | 228 | ### Multi-Select Poll (Checkboxes) 229 | 230 | `multi-select-v1` should be used for any polling that requires multiple possible repsonses from 231 | from a single user, with max of 8 possible responses as defined by `proposer`. UIs should fetch 232 | the possible responses from the "options" array. 233 | 234 | The `vote_value` pushed by this `type` of `proposal` functions differently from the previous types, 235 | as it will need to encode multiple values into an 8 bits unsigned integer (one byte). Within the 8 236 | bits available, a value of `0` will signify "unselected" and a value of `1` will signify "selected". 237 | With up to 8 responses available, each bit will correspond to its index in the array (0-indexed), in 238 | big-endian form, highest index being the most significant bit in the final value. 239 | 240 | A `vote_value` of `0` shall represent `Abstain` 241 | 242 | ``` 243 | { 244 | "type":"multi-select-v1", 245 | "content":"content here" 246 | "options": [ 247 | "option1" 248 | "option2" 249 | "option3" 250 | ] 251 | } 252 | ``` 253 | 254 | Example 255 | ``` 256 | { 257 | "type":"multi-select-v1", 258 | "content":"Which of these symbols should EOS change to? Select all that you like." 259 | "options": [ 260 | "EOS" 261 | "SYS" 262 | "SOE" 263 | "EEE" 264 | "B1" 265 | "Other" 266 | ] 267 | } 268 | ``` 269 | 270 | In this example, if a user selected the responses: EOS, B1, and Other, their vote in binary would be 271 | represented as `00110001`. When converted to decimal, this will be represented by a `vote_value` of `49`. 272 | 273 | **_Summary Notes_** 274 | 275 | There are no standard `options` defined for this `type`. Options are all `proposer`-defined. 276 | Each `vote_value` pushed to chain should be broken down from their decimal representation to their 277 | binary representation. `0` will signify all unselected responses, while `1` will signify all selected responses. 278 | 279 | A `vote_value` of `0` represents `Abstain` 280 | 281 | ## References 282 | 283 | * `eosio.forum` [repository](https://github.com/eoscanada/eosio.forum) 284 | * EOS Referendum Working Group on [Telegram](https://t.me/joinchat/HGqkxFAlvsxpRP9c6WvflQ) 285 | * EOS Nation's [Vote Tally Repository](https://github.com/EOS-Nation/eosvotes-tally) 286 | 287 | ## Copyright 288 | 289 | Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). 290 | -------------------------------------------------------------------------------- /EEPS/eep-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 1 3 | title: EEP Purpose and Guidelines 4 | author: EOSIO 5 | status: Living 6 | type: Meta 7 | created: 2018-10-10 8 | updated: 2021-08-11 9 | --- 10 | 11 | ## What is an EEP? 12 | 13 | EEP stands for EOSIO Enhancement Proposal. An EEP is a design document providing information to the EOSIO community, or describing a new feature for EOSIO or its processes or environment. The EEP should provide a concise technical specification of the feature and a rationale for the feature. The EEP author is responsible for building consensus within the community and documenting dissenting opinions. 14 | 15 | This process is specifically for the EOSIO protocol. Proposals for EOS mainnet are out of scope for EEPs. 16 | 17 | ## EEP Rationale 18 | 19 | We intend for EEPs to be the primary mechanism for proposing new features, for collecting community input on an issue, and for documenting the design decisions that have gone into EOSIO. Because EEPs are maintained as text files in a versioned repository, their revision history is the historical record of the feature proposal. 20 | 21 | For EOSIO implementers, EEPs are a convenient way to track the progress of their implementation. Ideally each implementation maintainer would list the EEPs that they have implemented. This will give end users a convenient way to know the current status of a given implementation or library. 22 | 23 | ## EEP Roles & Responsibilities 24 | 25 | Parties involved in the process are the champion or EEP author, the EEP editors, and the EEP reviewers. 26 | 27 | ### Role of an EEP champion or author 28 | 29 | The role of the champion is to write the EEP using the style and format described below, shepherd the discussions in the appropriate forums, and build community consensus around the idea. 30 | 31 | ### Role of an EEP editor 32 | 33 | #### For each new EEP that comes in, an editor does the following: 34 | * Reviews the EEP to check if it is ready, sound, and complete. 35 | * Verify the proposal makes technical sense, even if it does not seem likely to get to final status. 36 | * Verifies the title accurately describe the content. 37 | * Check the EEP for language (spelling, grammar, sentence structure, etc.), markup (Github flavored Markdown), code style. 38 | 39 | If the EEP isn’t ready, the editor will send it back to the author for revision, with specific instructions. 40 | 41 | #### Once the EEP is ready for the repository, the EEP editor will: 42 | * Assign an EEP number (generally the PR number or, if preferred by the author, the Issue # if there was discussion in the Issues section of this repository about this EEP). 43 | * Merge the corresponding pull request. 44 | * Mark the EEP with a 'Ready for Review' status and schedule an ad-hoc EEP review meeting with the EEP author and EEP reviewers to discuss next steps 45 | 46 | Many EEPs are written and maintained by developers with write access to the EOSIO codebase. The EEP editors monitor EEP changes, and correct any structure, grammar, spelling, or markup mistakes we see. 47 | 48 | The editors don’t pass judgment on EEPs. We merely do the administrative & editorial part. 49 | 50 | The current EEP editors are: 51 | * Sana Rauf 52 | * Amanda Clark 53 | 54 | ### Role of the EEP reviewers 55 | 56 | The EEP reviewers are responsible for reviewing EEP submissions and deciding next steps. Once an EEP has been submitted by an author and reviewed by an EEP editor, it is added to the agenda for the next review meeting. 57 | 58 | EEP review meetings will be held ad-hoc at the beginning of the EEP launch and a regular cadence will be determined at a later date. The agenda and meeting details, minutes, and recording will be shared publicly (similar to Ethereum's approach) and facilitated by the EEP editors. Anyone from the EOSIO community is welcome to participate and provide technical input and feedback on EEP submissions. 59 | 60 | ## EEP Workflow 61 | 62 | #### Before Submitting An EEP 63 | * Vet your idea, this will save you time. Ask the EOSIO community first if an idea is original to avoid wasting time on something that will be rejected based on prior research (searching the Internet does not always do the trick). 64 | * It also helps to make sure the idea is applicable to the entire community and not just the author. Just because an idea sounds good to the author does not mean it will work for most people in most areas where EOSIO is used. 65 | 66 | #### Examples of appropriate public forums to gauge interest around your EEP include: 67 | * [the EOS subreddit](https://www.reddit.com/r/eos/) 68 | * [the issues section of the EEPs repository](https://github.com/EOSIO/EEPs/issues) 69 | * [the EEP Telegram Channel](https://t.me/eos_enhancements_proposals) 70 | * the specific mainnet Telegram channels for each EOSIO chain 71 | 72 | In particular, the issues section of the EEPs repository is an excellent place to discuss your proposal with the community and start creating more formalized language around your EEP. 73 | 74 | #### Submit an EEP 75 | 1. Navigate to EOSIO’s official [EEP repository](https://github.com/EOSIO/EEPs) 76 | 2. Use a pull request to update the status. Please include a link to where people should continue discussing your EEP. 77 | 3. The EEP editors will process these requests. Once you’ve submitted your EEP, the EEP will have a ‘Submitted’ status. 78 | 79 | #### EEP Review by an EEP Editor 80 | * An EEP editor will review the submitted EEP. 81 | * If the EEP is ready for review at the next EEP review meeting, the EEP editor will merge the EEP into the main repository. 82 | * If the editor has feedback, the EEP editor will correspond with the author until the EEP is ready for review. 83 | * Review new proposals at the EEP review meeting. 84 | * Once an EEP editor has approved an EEP submission into “Ready for Review” status, it is added to the agenda for the next EEP review meeting. 85 | * At the EEP review meeting, proposals are reviewed and discussed. There are four possible paths an EEP submission may take at the EEP review meeting: 86 | * **Deferred:** the EEP submission presents a good idea for the future but cannot be accepted immediately; it will be revisited in the future 87 | * **Accepted:** the EEP submission presents a good idea and can begin development immediately 88 | * **Living:** the EEP requires regular updates and will be a living proposal 89 | * **Archived:** either the author retracts their EEP submission or the EEP does not obtain the consensus it needs to be implemented 90 | 91 | #### EEP Next Steps 92 | Based on the next steps decided at the EEP review meeting: 93 | * **If Deferred:** the EEP will be revisited at a future meeting 94 | * **If Accepted:** the EEP is now available for development 95 | * **If Living:** the EEP will be regularly reviewed to ensure accuracy 96 | * **If Archived:** the justification will be recorded and the EEP will no longer be pursued 97 | 98 | #### EEP Happy Path 99 | 1. An EOSIO community member submits an EEP proposal in the correct format and a "Submitted" status. 100 | 2. An EEP editor reviews the submission, verifies it is ready for review, schedules time to discuss the EEP with EEP reviewers. 101 | 3. EEP reviewers accept the EEP, making the proposal available for development. Any interested entity may begin the implementation of the EEP. 102 | 4. Once an EEP has been developed, it will go under PR review. 103 | 5. The EEP will pass the PR review and achieve a “Final” status. 104 | 105 | ## EEP Statuses 106 | * **Draft** - the EEP is currently a work in progress and has not yet been submitted 107 | * **Submitted** - the final draft of the EEP has been subitted by the EEP author 108 | * **Ready for Review** - the EEP has been reviewed by an EEP editor and has been added to the agenda for the next EEP review meeting 109 | * **Accepted** - the EEP was analyzed and discussed by the EEP reviewers and has sufficient support for implementation 110 | * **Under Development** - the EEP is currently under developmnet 111 | * **Pending PR Review** -the EEP implementation is currently being reviewed for final acceptance 112 | * **Final** - the EEP has been successfully implemented and is now active 113 | * **Deferred** - the EEP has been shelved for future consideration 114 | * **Living** - this is similar to Final, but denotes an EEP which requires regular updates for accuracy (good for token/wallet standards) 115 | * **Archived** - the EEP is no longer under consideration (withdrawn by author, not enough support for the proposal, etc.) 116 | 117 | ## What belongs in a successful EEP? 118 | It is highly recommended that a single EEP contain a single key proposal or new idea. The more focused the EEP, the more successful it tends to be. A change to one client doesn’t require an EEP; a change that affects multiple clients, or defines a standard for multiple apps to use, does. 119 | 120 | #### An EEP must meet certain minimum criteria: 121 | * It must be a clear and complete description of the proposed enhancement. 122 | * The enhancement must represent a net improvement. 123 | * The proposed implementation, if applicable, must be solid and must not complicate the protocol unduly. 124 | * The proposal must be chain-agnostic. 125 | 126 | #### Each EEP should have the following parts: 127 | **Preamble:** RFC 822 style headers containing metadata about the EEP, including the EEP number, a short descriptive title (limited to a maximum of 44 characters), and the author details. See below for details. 128 | 129 | **Simple Summary:** “If you can’t explain it simply, you don’t understand it well enough.” Provide a simplified and layman-accessible explanation of the EEP. 130 | 131 | **Abstract:** a short (~200 word) description of the technical issue being addressed. 132 | 133 | **Motivation (*optional):** The motivation is critical for EEPs that want to change the EOSIO protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EEP solves. EEP submissions without sufficient motivation may be rejected outright. 134 | 135 | **Specification:** The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current EOSIO platforms (eos-go, eosjs). 136 | 137 | **Rationale:** The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion. 138 | 139 | **Backwards Compatibility:** All EEPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EEP must explain how the author proposes to deal with these incompatibilities. EEP submissions without a sufficient backwards compatibility treatise may be rejected outright. 140 | 141 | **Test Cases:** Test cases for an implementation are mandatory for EEPs that are affecting consensus changes. Other EEPs can choose to include links to test cases if applicable. 142 | 143 | **Implementations:** The implementations must be completed before any EEP is given status “Final”, but it need not be completed before the EEP is merged as draft. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of “rough consensus and running code” is still useful when it comes to resolving many discussions of API details. 144 | 145 | **Security Considerations:** Discuss the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surface risks and can be used throughout the life cycle of the proposal. 146 | 147 | **Intellectual Property:** All EEPs submissions must contain the following text: “I hereby agree that this EEP is subject to this [copyright waiver](https://creativecommons.org/publicdomain/zero/1.0/) and I certify that I have all necessary rights and permissions to make this submission and to agree to such waiver.” 148 | 149 | ## EEP Types 150 | There are four types of EEPs: 151 | 1. A **Standard EEP** describes any change that affects most or all EOSIO implementations, such as a change to the network protocol, a change in block or transaction validity rules, proposed application standards/conventions, or any change or addition that affects the interoperability of applications using EOSIO. 152 | 153 | Furthermore Standard EEPs can be broken down into the following categories. Standards Track EEPs consist of three parts, a design document, implementation, and finally if warranted an update to the formal specification. 154 | * **Core:** improvements requiring a consensus fork, as well as changes that are not necessarily consensus critical but may be relevant to Block Producer and EOSIO discussions 155 | * **Networking:** improvements around the p2p protocol 156 | * **Interface:** includes improvements around client API specifications and standards, and also certain language-level standards like contract ABIs. For contract ABIs, it aligns with the [eosio.contracts repo](https://github.com/EOSIO/eosio.contracts) and discussion should primarily occur in that repository before an EEP is submitted to the EOSIO/EEPs repository 157 | 158 | 2. An **Informational EEP** describes an EOSIO design issue, or provides general guidelines or information to the EOSIO community, but does not propose a new feature. Informational EEPs do not necessarily represent EOSIO community consensus or a recommendation, so users and implementers are free to ignore Informational EEPs or follow their advice. 159 | 160 | 3. A **Meta EEP** describes a process surrounding EOSIO or proposes a change to (or an event in) a process. Process EEPs are like Standard Track EEPs but apply to areas other than the EOSIO protocol itself. They may propose an implementation, but not to EOSIO's codebase; they often require community consensus; unlike Informational EEPs, they are more than recommendations, and users are typically not free to ignore them. Examples include procedures, guidelines, changes to the decision-making process, and changes to the tools or environment used in EOSIO development. Any meta-EEP is also considered a Process EEP. 161 | 162 | 4. An **Archived EEP** desribes a previously submitted EEP submission that does not have a type or category from the list above. 163 | 164 | ## EEP Formats and Templates 165 | 166 | EEPs should be written in [markdown] format. 167 | 168 | Image files should be included in a subdirectory of the `assets` folder for that EEP as follows: `assets/eep-X` (for eep **X**). When linking to an image in the EEP, use relative links such as `../assets/eep-X/image.png`. 169 | 170 | #### EEP Header Preamble 171 | Each EEP must begin with an RFC 822 style header preamble, preceded and followed by three hyphens (`---`). The headers must appear in the following order. Headers marked with an asterisk are optional and are described below. 172 | 173 | All other headers are required. 174 | 175 | `eep:` (this is determined by the EEP editor) 176 | 177 | `title:` (a high-level title of the EEP) 178 | 179 | `author:` 180 | 181 | `* discussions-to:` 182 | 183 | `status:` 184 | 185 | `* review-period-end:` YYYY-MM-DD 186 | 187 | `type:` 188 | 189 | `* category:` 190 | 191 | `created:` 192 | 193 | `* updated:` 194 | 195 | `* requires:` 196 | 197 | `* replaces:` 198 | 199 | `* superseded-by:` 200 | 201 | `* resolution:` 202 | 203 | #### Author Header 204 | 205 | The author header optionally lists the names, email addresses or usernames of the authors/owners of the EEP. Those who prefer anonymity may use a username only, or a first name and a username. 206 | 207 | The format of the author header value must be Random J. User <address@dom.ain> 208 | 209 | or Random J. User (@username) if the email address or GitHub username is included, 210 | 211 | or Random J. User if the email address is not given. 212 | 213 | #### Additional Header & Template Guidelines 214 | 215 | The resolution header is required for Standards Track EEPs only. It contains a URL that should point to an email message or other web resource where the pronouncement about the EEP is made. 216 | 217 | While an EEP is a draft, a `discussions-to` header will indicate the mailing list or URL where the EEP is being discussed. As mentioned above, examples for places to discuss your EEP include: 218 | * an issue in this repo or in a fork of this repo 219 | * [EEPs Channel on Telegram](https://t.me/eos_enhancements_proposals) 220 | * [EOS Mainnet BPs Telegram Channel](https://t.me/joinchat/HbgyfEqlPd_HCo4R8EJsnw) 221 | * EOSIO mainnet Telegram channels 222 | * [Reddit r/eos](https://www.reddit.com/r/eos/) 223 | 224 | No `discussions-to` header is necessary if the EEP is being discussed privately with the author. 225 | 226 | The `type` header specifies the type of EEP: Standards Track, Meta, or Informational. If the track is Standards please include the subcategory (core, networking, interface, or RFC). 227 | 228 | The `category` header specifies the EEP's category. This is required for standards-track EEPs only. 229 | 230 | The `created` header records the date that the EEP was assigned a number. Both headers should be in yyyy-mm-dd format, e.g. 2001-08-14. 231 | 232 | EEPs may have a `requires` header, indicating the EEP numbers that this EEP depends on. 233 | 234 | EEPs may also have a `superseded-by` header indicating that an EEP has been rendered obsolete by a later document; the value is the number of the EEP that replaces the current document. The newer EEP must have a Replaces header containing the number of the EEP that it rendered obsolete. 235 | 236 | Headers that permit lists must separate elements with commas. 237 | 238 | #### Auxiliary Files 239 | 240 | EEPs may include auxiliary files such as diagrams. Such files must be named EEP-XXXX-Y.ext, where “XXXX” is the EEP number, “Y” is a serial number (starting at 1), and “ext” is replaced by the actual file extension (e.g. “png”). 241 | 242 | ## Transferring EEP Ownership 243 | 244 | It occasionally becomes necessary to transfer ownership of EEPs to a new champion. In general, we’d like to retain the original author as a co-author of the transferred EEP, but that’s not always possible or may not be the preference of the original author. A good reason to transfer ownership is because the original author no longer has the time or interest in updating it or following through with the EEP process, or has fallen off the face of the net (i.e. is unreachable or isn’t responding to email). A bad reason to transfer ownership is because you don’t agree with the direction of the EEP. We try to build consensus around an EEP, but if that’s not possible, you can always submit a competing EEP. 245 | 246 | If you are interested in assuming ownership of an EEP, send a message asking to take over, addressed to both the original author and the EEP editor. If the original author doesn’t respond to email in a timely manner, the EEP editor will make a unilateral decision (it’s not like such decisions can’t be reversed). 247 | 248 | ## History 249 | 250 | This document was derived heavily from [Ethereum’s EIP-1] written by Martin Becze, Hudson Jameson, and others, which was derived from [Bitcoin’s BIP-0001] written by Amir Taaki which in turn was derived from [Python’s PEP-0001]. In many places text was simply copied and modified. Although the PEP-0001 text was written by Barry Warsaw, Jeremy Hylton, and David Goodger, they are not responsible for its use in the EOSIO Enhancement Proposal process, and should not be bothered with technical questions specific to EOSIO or EEPs. Please direct all comments, questions, and feedback to the EEP editors. 251 | 252 | ## Legal 253 | 254 | By participating in the EEP process you agree to terms set forth in this document. If you do not agree to these terms, you may not participate in the EEPs process. 255 | 256 | #### Conduct 257 | While participating in this process, please be respectful and constructive, so that participation in our project is a positive experience for everyone. 258 | 259 | ##### Examples of behavior that contributes to creating a positive environment include: 260 | * Using welcoming and inclusive language 261 | * Being respectful of differing viewpoints and experiences 262 | * Gracefully accepting constructive criticism 263 | * Focusing on what is best for the community 264 | * Showing empathy towards other community members 265 | 266 | ##### Examples of unacceptable behavior include: 267 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 268 | * Trolling, insulting/derogatory comments, and personal or political attacks 269 | * Public or private harassment 270 | * Publishing others’ private information, such as a physical or electronic address, without explicit permission 271 | * Other conduct which could reasonably be considered inappropriate in a professional setting 272 | 273 | #### Confidentiality 274 | All EEPs, editor feedback on EEPs, and EEPs reivew meeting discussions or feedback on EEPs are considered non-confidential information and may be disclosed to third parties. This could lead to a third party developing an idea, concept, design or standard described in your EEP without your permission or involvement. 275 | 276 | #### Additional Requirements 277 | 278 | ##### By participating in the EEP process, you certify that: 279 | You are not, are not acting on behalf of another party that is, and no party with a beneficial interest in you is: subject to sanctions administered or enforced by any country or government or otherwise designated on any list of prohibited or restricted parties (including but not limited to the lists maintained by the United Nations Security Council, the U.S. Government, the European Union or its Member States, or other applicable government authority)(“Sanctions”); or 280 | organized or resident in a country or territory that is the subject of country-wide or territory-wide Sanctions. 281 | 282 | ##### And you acknowledge and agree that: 283 | * All EEPs, editor feedback on EEPs and EEP review meeting discussions or written feedback on EEPs are subject to this [copyright waiver](https://creativecommons.org/publicdomain/zero/1.0/). 284 | * The EEP process does not create an obligation to consider, develop or implement any idea, design, concept or standard that you include in an EEP 285 | 286 | The EEP process, including but not limited to EEP editing and EEP reviewer feedback is provided without warranty, guarantee or undertaking of any kind, whether express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. 287 | 288 | In no event shall an EEP editor, an EEP reviewer or Bullish Global or its affiliates (“EEP Participants”) be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the EEP process and you waive any claim that you may have against such parties related to their participation in the EEP process 289 | 290 | You will not make EEP materials available to any person or entity that is the subject of Sanctions or organized or resident in a country or territory that is the subject of country-wide or territory-wide Sanctions. You will comply with all applicable import, re-import, sanctions, anti-boycott, export, and re-export control laws and regulations. If this is not accurate or you do not agree, then you must immediately cease accessing the EEP materials and delete all copies thereof. 291 | 292 | Any reference to any third party or third-party product, resource or service is not an endorsement or recommendation by an EEP Participant. EEP Participants are not responsible for, and disclaim any and all responsibility and liability for, your use of or reliance on any of these resources. 293 | 294 | #### Forward Looking Statements 295 | 296 | When an EEP Participant makes statements expressing its vision, it does not guarantee anything, and all aspects of its vision are subject to change at any time and at such participant’s sole discretion, with or without notice. We call these “forward-looking statements”, which includes statements on an EEP Participant’s website and in other materials, such as statements regarding EOSIO’s development, expected performance, and future features, or business strategy, plans, prospects, developments and objectives. These statements are based on assumptions and are subject to risk, uncertainties and change at any time. 297 | 298 | EEP Participants operate in a rapidly changing environment and new risks emerge from time to time. Given these risks and uncertainties, you are cautioned not to rely on these forward-looking statements. Actual results, performance or events may differ materially from what is predicted in the forward-looking statements. Some of the factors that could cause actual results, performance or events to differ materially from the forward looking statements include, without limitation: technical feasibility and barriers; market trends and volatility; continued availability of capital, financing and personnel; product acceptance; the commercial success of any new products or technologies; competition; government regulation and laws; and general economic, market or business conditions. 299 | 300 | All statements are valid only as of the date of first posting and EEP Participants are not under and expressly disclaim any obligation to update or alter any statements, whether as a result of new information, subsequent events or otherwise. Nothing provided in the EEP process constitutes technological, financial, investment, legal or other advice, either in general or with regard to any particular situation or implementation. Please consult with experts in appropriate areas before implementing or utilizing any content, guidance or feedback received as part of the EEP process. 301 | Trademarks: EOSIO, EOS, the heptahedron and associated logos and related marks are Bullish Global’s trademarks. 302 | 303 | ## Bibliography 304 | 305 | * [eosio.contracts](https://github.com/EOSIO/eosio.contracts) 306 | 307 | * [the EOS subreddit](https://www.reddit.com/r/eos/) 308 | 309 | * [EEP Telegram Channel](https://t.me/eos_enhancements_proposals) 310 | 311 | * [pull request](https://github.com/eoscanada/EEPs/pulls) 312 | 313 | * [the Issues section of this repository](https://github.com/eoscanada/EEPs/issues) 314 | 315 | * [markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) 316 | 317 | * [Ethereum's EIP-1](https://github.com/ethereum/EIPs/) 318 | 319 | * [Bitcoin's BIP-0001](https://github.com/bitcoin/bips) 320 | 321 | * [Python's PEP-0001](https://www.python.org/dev/peps/) 322 | -------------------------------------------------------------------------------- /EEPS/eep-7.md: -------------------------------------------------------------------------------- 1 | --- 2 | EEP: 7 3 | title: ESR (EOSIO Signing Request) 4 | author: Aaron Cox (@aaroncox), Johan Nordberg (@jnordberg) 5 | status: Draft 6 | type: Standard 7 | category: Interface 8 | created: 2019-05-19 9 | updated: 2020-05-09 10 | --- 11 | 12 | **Table of Contents** 13 | 14 | - [Introduction](#ESR---The--EOSIO-Signing-Request--protocol) 15 | - [Summary](#Summary) 16 | - [Abstract](#Abstract) 17 | - [Motivation](#Motivation) 18 | - [Technical Specification](#Technical-Specification) 19 | - [Data Format](#Data-Format) 20 | - [Header](#Header) 21 | - [Payload](#Payload) 22 | - [`chain_id`](#chain_id) 23 | - [`req`](#req) 24 | - [`action | action[]`](#req---action--action) 25 | - [`transaction`](#req---transaction) 26 | - [`identity`](#req---identity) 27 | - [`flags`](#flags) 28 | - [`callback`](#callback) 29 | - [`info`](#info) 30 | - [Request Signatures (Optional)](#Request-Signatures) 31 | - [EOSIO Client Integration](#EOSIO-Client-Integration) 32 | - [Implementation Guidelines](#Implementation-Guidelines) 33 | - [Signature Provider Workflow](#Signature-Provider-Workflow) 34 | 1. [Resolving the Request](#1---Resolving-the-Request) 35 | 2. [Signing the resolved request](#2---Signing-the-resolved-request) 36 | 3. [Broadcasting the transaction](#3---Broadcasting-the-transaction) 37 | 4. [Issuing Callbacks](#4---Issuing-Callbacks) 38 | - [Use Cases](#Use-Cases) 39 | - [Implementations](#Implementations) 40 | - [JS Client Frameworks](#JS-Client-Frameworks) 41 | - [JS Examples](#JS-Examples) 42 | - [JS Libraries](#JS-Libraries) 43 | - [Swift Libraries](#Swift-Libraries) 44 | - [Signature Providers](#Signature-Providers) 45 | - [User Interfaces](#User-Interfaces) 46 | - [Test Cases](#Test-Cases) 47 | - [Appendix](#Appendix) 48 | - [Base64u](#Base64u) 49 | - [Callback Proxies](#Callback-Proxies) 50 | - [Chain Aliases](#Chain-Aliases) 51 | - [Compression](#Compression) 52 | - [Identity Requests](#Identity-Requests) 53 | - [Identity Proof Action](#Identity-Proof-Action) 54 | - [Signing Identity Proof Actions](#Signing-Identity-Proof-Actions) 55 | - [MIME Type](#MIME-Type) 56 | - [Null transaction header](#Null-transaction-header) 57 | - [Signing Request - Placeholders](#Signing-Request---Placeholders) 58 | - [Signing Request - Schema](#Signing-Request---Schema) 59 | - [EOSIO ABI](#Signing-Request-represented-as-a-EOSIO-C-struct) 60 | - [EOSIO C++ struct](#Signing-Request-represented-as-an-EOSIO-ABI) 61 | - [Backwards Compatibility](#Backwards-Compatibility) 62 | - [Change Log](#Change-Log) 63 | - [Acknowledgements](#Acknowledgements) 64 | - [Copyright](#Copyright) 65 | 66 | --- 67 | 68 | # ESR - The "EOSIO Signing Request" protocol 69 | 70 | ### Summary 71 | 72 | A standard protocol for an EOSIO-based signing request payload to allow communication between applications and signature providers. 73 | 74 | ### Abstract 75 | 76 | EOSIO Signing Requests encapsulate transaction data for transport within multiple mediums (e.g. QR codes and hyperlinks), providing a simple cross-application signaling method between very loosely coupled applications. A standardized request data payload allows instant invocation of specific transaction templates within the user's preferred EOSIO signature provider. 77 | 78 | ### Motivation 79 | 80 | The ability to represent a transaction in a standardized signing request format has been a major factor in driving end user adoption within many blockchain ecosystems. Introducing a similar mechanism into the EOSIO ecosystem would speed up adoption by providing a versatile data format which allows requests across any medium. 81 | 82 | While other protocols already exist within EOSIO for more intricate cross-application communication - this proposal seeks to establish a primitive request payload for use in any type of application on any device. 83 | 84 | --- 85 | 86 | # Technical Specification 87 | 88 | The following specification sets out to define the technical standards used and the actual composition of an EOSIO Signing Request payload. 89 | 90 | > Note: Examples in this specification uses the JSON representation of the ABI data. 91 | 92 | ## Signing Request Specification 93 | 94 | In its encapsulated form, an EOSIO Signing Request is a binary data structure which has been [compressed](#Compression) and converted to [base64u](#Base64u), and is representable as a string: 95 | 96 | ``` 97 | gmNgZGRkAIFXBqEFopc6760yugsVYWCA0YIwxgKjuxLSL6-mgmQA 98 | ``` 99 | 100 | The above payload is a signing request for a transaction on the EOS blockchain to perform the `voteproducer` action on the `eosio` contract. The data contained within the action itself also specifies the proxy of `greymassvote`. 101 | 102 | Once decoded and inflated ([preview request](https://eosio.to/gmNgZGRkAIFXBqEFopc6760yugsVYWCA0YIwxgKjuxLSL6-mgmQA)) it will return the following data: 103 | 104 | ```jsonc 105 | { 106 | "callback": "", 107 | "chain_id": ["chain_alias", 1], 108 | "flags": 1, 109 | "info": [], 110 | "req": [ 111 | [ 112 | "action", 113 | { 114 | "account": "eosio", 115 | "name": "voteproducer", 116 | "authorization": [ 117 | { 118 | "actor": "............1", 119 | "permission": "............2" 120 | } 121 | ], 122 | "data": { 123 | "voter": "............1", 124 | "proxy": "greymassvote", 125 | "producers": [] 126 | } 127 | } 128 | ] 129 | ] 130 | } 131 | ``` 132 | 133 | This decoded data can then be used to prompt action from the end user in their preferred signature provider. The signature provider can then [resolve the signing request](#Signature-Provider-Workflow), add a [signature for the transaction](#Signing-the-resolved-request), and potentially trigger a [callback](#callback) and/or broadcast the completed transaction to the blockchain. See the [EOSIO Client Integration](#EOSIO-Client-Integration) section for a more in-depth explanation. 134 | 135 | ### Data Format 136 | 137 | The decoded payload of each Signing Request consists of three parts: 138 | 139 | - a 1-byte header 140 | - a N-byte payload 141 | - an optional 65-byte signature 142 | 143 | ``` 144 | header request signature 145 | 1000001000000000000000000000...[00000000000000000000000000000000...] 146 | ``` 147 | 148 | ### Header 149 | 150 | The header is the 8 initial bits of the data, with the first 7 bits representing the protocol version and the last bit denoting if the data is compressed. The protocol version this document describes is `2`, making the only valid headers: 151 | 152 | - `0x02` a uncompressed payload 153 | - `0x82` a compressed payload 154 | 155 | ### Payload 156 | 157 | Data beyond the 1-byte header forms the representation of the request payload. This structure is as follows (in byte order): 158 | 159 | param | description 160 | ------------------|------------- 161 | [`chain_id`](#chain_id) | Target chain id 162 | [`req`](#req) | The action/tx/identity being requested 163 | [`flags`](#flags) | Various flags for how to process this transaction 164 | [`callback`](#callback) | URL that should be triggered to after the transaction is signed 165 | [`info`](#info) | Additional metadata to pass along with the request 166 | 167 | A representation of this schema can be found in the Appendix as both an [EOSIO C++ struct](#signing-request-represented-as-a-eosio-c-struct) and an [EOSIO ABI Definition](#signing-request-represented-as-an-eosio-abi). 168 | 169 | #### `chain_id` 170 | 171 | The EOSIO blockchain this request is valid for. 172 | 173 | This can be either a full 32-byte chain id: 174 | 175 | ```jsonc 176 | { 177 | "chain_id": "aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906" 178 | } 179 | ``` 180 | 181 | Or a 1-byte [chain alias](#chain-aliases) can be used (`1` being defined EOS): 182 | 183 | 184 | ```jsonc 185 | { 186 | "chain_id": [ "chain_alias", 1 ] 187 | } 188 | ``` 189 | 190 | #### `req` 191 | 192 | The request data is a 2-part tuple, with the first part being the type and the second part being the data itself. 193 | 194 | ```jsonc 195 | { 196 | "req": [ 197 | 'request_type', 198 | 'request_data' 199 | ] 200 | } 201 | ``` 202 | 203 | The data to be processed from the request can be one of the following request types: 204 | 205 | - `action` or `action[]`: a single action or a list of actions 206 | - `transaction`: a full EOSIO transaction 207 | - `identity`: a identity request 208 | 209 | ###### Request type: `action | action[]` 210 | 211 | The most compact and simple form of a signing request is to just pass the action(s) that should be signed. When the request is resolved to a transaction, the client **MUST** create a valid transaction header (see [resolving requests](#resolving-signing-requests)). 212 | 213 | Example: 214 | 215 | ```jsonc 216 | { 217 | "req": [ 218 | "action", 219 | { 220 | "account": "eosio.forum", 221 | "name": "vote", 222 | "authorization": [{"actor": "............1", "permission": "............2"}], 223 | "data": "0100000000000000000000204643BABA0100" 224 | } 225 | ] 226 | } 227 | ``` 228 | 229 | ###### Request type: `transaction` 230 | 231 | A full transaction, TAPoS values and expiration can be defined or all be set to [null transaction header values](#null-transaction-header) to indicate that signature provider should insert appropriate values (see [resolving requests](#resolving-signing-requests)). 232 | 233 | Example: 234 | 235 | ```jsonc 236 | { 237 | "req": [ 238 | "transaction", 239 | { 240 | "expiration": "1970-01-01T00:00:00", // 241 | "ref_block_num": 0, // the "null" header values 242 | "ref_block_prefix": 0, // 243 | "max_net_usage_words": 0, 244 | "max_cpu_usage_ms": 10, 245 | "delay_sec": 10, 246 | "context_free_actions": [], 247 | "actions": [ 248 | { 249 | "account": "eosio.forum", 250 | "name": "vote", 251 | "authorization": [ 252 | { 253 | "actor": "............1", 254 | "permission": "............2" 255 | } 256 | ], 257 | "data": "0100000000000000000000204643BABA0100" 258 | } 259 | ], 260 | "transaction_extensions": [] 261 | } 262 | ] 263 | } 264 | ``` 265 | 266 | ###### Request type: `identity` 267 | 268 | Off-chain identity proof that can be returned via callback, see [identity requests](#identity-requests) for more details. 269 | 270 | #### `flags` 271 | 272 | 1-byte bit-field containing the request flags, available flags (in bit-order) 273 | 274 | 1. Broadcast - if set the transaction **MUST** be broadcast after signing 275 | 2. Background - if set the callback url (if any) **SHOULD** be sent via HTTP POST if the scheme is http or https 276 | 277 | If the broadcast flag is set when the req data is of type `identity` the request **MUST** be rejected. 278 | 279 | #### `callback` 280 | 281 | Callback URL, if set client **SHOULD** attempt to deliver the [callback payload](#callback-payload) to it, see [callbacks](#issuing-callbacks) for more details. 282 | 283 | #### `info` 284 | 285 | Request metadata, key value pairs with arbitrary data that can be used to implement extended functionality. 286 | 287 | Example: 288 | 289 | ```jsonc 290 | { 291 | "info": [ 292 | { 293 | "key": "hello", 294 | "value": "776f726c64" // utf-8 "world" 295 | } 296 | ] 297 | } 298 | ``` 299 | 300 | ### Request Signatures 301 | 302 | Requests can optionally be signed to provide proof of the origin of the request. A signed request has the 8-byte signer account name and 65-byte signature appended to the end of the request data. 303 | 304 | The signing digest is created with `sha256(request_version + utf8("request") + request_data)`. Example for a version 2 request: 305 | 306 | ``` 307 | sha256( 308 | 0272657175657374 309 | __ request data __ 310 | ) 311 | ``` 312 | 313 | --- 314 | 315 | ## EOSIO Client Integration 316 | 317 | ### Implementation Guidelines 318 | 319 | The following are a set of guidelines in which end user applications (e.g. signature providers) that handle EOSIO Signing Requests should respect. 320 | 321 | - EOSIO clients **MUST NOT** automatically act upon the data contained within a Signing Request without the user's authorization. 322 | - EOSIO clients **MUST** decode and present the transaction data in a human readable format for review before creating a signature. 323 | - EOSIO clients **SHOULD** inform the user of any callback which will be executed upon completion of a signing request. 324 | - EOSIO clients **SHOULD** register themselves as the handler for the `esr:` URI scheme by default so long as no other handlers already exist. If a registered handler already exists, they **MAY** prompt the user to change it upon request. 325 | - EOSIO clients **SHOULD** use the [recommended MIME type](#MIME-type) when applicable in their implementations. 326 | 327 | ### Signature Provider Workflow 328 | 329 | Signature providers (a.k.a "Wallets") will need to go through a series of steps in order to interpret and resolve an ESR payload before being able to sign the resulting transaction. 330 | 331 | #### 1. Resolving the Request 332 | 333 | To resolve a signing request to a transaction that can be signed the following steps are taken: 334 | 335 | - [A) Create transaction from payload](#A--Create-transaction-from-payload) 336 | - [B) Resolve authority/action placeholders](#B--Resolve-authority-action-placeholders) 337 | - [C) Insert TAPoS values](#C--Insert-TAPoS-values) 338 | 339 | ###### A) Create transaction from payload 340 | 341 | The payload should be inspected to determine the [request type](#req) and determine how to interpret the request data. 342 | 343 | - Payloads with the `action` and `action[]` types should construct a transaction with the [null header](#null-transaction-header) and then insert the action(s) contained within the request. 344 | - Payloads with type `identity` are resolved to the [identity proof](#identity-proof) action and then treated just like an `action` request. 345 | - For the `transaction` type the full transaction is taken as-is. 346 | 347 | ###### B) Resolve authority/action placeholders 348 | 349 | The action data and authorization is inspected and all fields with the `name` type that contain an [action placeholder](#action-placeholders) value is resolved. 350 | 351 | * `............1` (`uint64(1)`) - Is resolved to the signing account name, e.g. `foobarfoobar` 352 | * `............2` (`uint64(2)`) - Is resolved to the signing account permission, e.g. `active` 353 | 354 | This is performed recursively until all fields have been visited. It is recommended that implementers enforce a max recursion depth of 100. 355 | 356 | ###### C) Insert TAPoS values 357 | 358 | The transaction header is inspected and if it matches the [null transaction header](#null-transaction-header) and the payload type is NOT `identity` appropriate TAPoS and expiration values should be inserted. 359 | 360 | ```jsonc 361 | { 362 | "expiration": "1970-01-01T00:00:00", 363 | "ref_block_num": 0, 364 | "ref_block_prefix": 0, 365 | // ... 366 | } 367 | // resolves to something like 368 | { 369 | "expiration": "2020-02-02T20:20:20", 370 | "ref_block_num": 10444, 371 | "ref_block_prefix": 4158294815, 372 | // ... 373 | } 374 | ``` 375 | 376 | **Note**: other header fields (e.g.`max_cpu_usage_ms` or `delay_sec`) must be left as-is. 377 | 378 | Example: 379 | 380 | ```jsonc 381 | { 382 | "callback": "", 383 | "chain_id": ["chain_alias", 1], 384 | "flags": 1, 385 | "info": [], 386 | "req": [ 387 | [ 388 | "action", 389 | { 390 | "account": "eosio", 391 | "name": "voteproducer", 392 | "authorization": [ 393 | { 394 | "actor": "............1", 395 | "permission": "............2" 396 | } 397 | ], 398 | "data": { 399 | "voter": "............1", 400 | "proxy": "greymassvote", 401 | "producers": [] 402 | } 403 | } 404 | ] 405 | ] 406 | } 407 | ``` 408 | 409 | This request given the signer `foobarfoobar@active` and TAPoS values of `expiration=2020-02-02T20:20:20`, `ref_block_num=10444`, and `ref_block_prefix=4158294815` resolves to: 410 | 411 | ```jsonc 412 | { 413 | "ref_block_num": 10444, 414 | "ref_block_prefix": 4158294815, 415 | "expiration": "2020-02-02T20:20:20", 416 | "max_cpu_usage_ms": 0, 417 | "max_net_usage_words": 0, 418 | "delay_sec": 0, 419 | "context_free_actions": [], 420 | "transaction_extensions": [], 421 | "actions": [ 422 | { 423 | "account": "eosio", 424 | "name": "voteproducer", 425 | "authorization": [ 426 | { "actor": "foobarfoobar", "permission": "active" } 427 | ], 428 | "data": { 429 | "voter": "foobarfoobar", 430 | "proxy": "greymassvote", 431 | "producers": [] 432 | } 433 | } 434 | ] 435 | } 436 | ``` 437 | 438 | ### 2. Signing the resolved request 439 | 440 | Now with a standard EOSIO transaction, the signature provider should use their native capabilities to create a signature for the transaction. 441 | 442 | ### 3. Broadcasting the transaction 443 | 444 | Depending on the value of the [`broadcast`](#flags) flag in the request, the signature provider may be asked to broadcast this transaction directly to the appropriate blockchain before issuing the callback. 445 | 446 | This flag should always be respected by the signature provider, as the application issuing the signing request may want to broadcast the transaction to a specific API endpoint for further processing. 447 | 448 | ### 4. Issuing Callbacks 449 | 450 | An optional parameter of the signing request is the `callback`, which when set indicates how an EOSIO client should proceed after the transaction has been signed and potentially broadcast. The `callback` itself is a string containing a full URL. This URL will be triggered after the transaction has been either signed or broadcast based on the `flags` provided. 451 | 452 | The `flags` value dictates the behavior of EOSIO client, indicating whether it should trigger the callback in the native OS handler (e.g. opening a web browser for `http` or `https`) or perform it in the background. If `background` is set to `true` and the URL protocol is either `http` or `https`, EOSIO clients should `POST` to the URL instead of redirecting/opening it in a web browser. For other protocols background behavior is up to the implementer. 453 | 454 | The callback URL also includes simple templating with some response parameters. The templating format syntax is `{{param_name}}`, e.g.: 455 | 456 | - `https://myapp.com/wallet?tx={{tx}}&included_in={{bn}}` 457 | - `mymobileapp://signed/{{sig}}` 458 | 459 | Available Parameters: 460 | 461 | - `bn`: Block number hint (only present if transaction was broadcast). 462 | - `ex`: Expiration time used when resolving request. 463 | - `rbn`: Reference block num used when resolving request. 464 | - `req`: The originating signing request encoded as a uri string. 465 | - `rid`: Reference block id used when resolving request. 466 | - `sa`: Signer authority string, aka account name. 467 | - `sp`: Signer permission string, e.g. "active". 468 | - `req`: The originating signing request packed as a uri string. 469 | - `sig`: The first signature. 470 | - `sigX`: All signatures are 0-indexed as `sig0`, `sig1`, etc. 471 | 472 | When the callback is performed in the background all the parameters are included as a JSON object. 473 | 474 | --- 475 | 476 | ## Use Cases 477 | 478 | The EOSIO Signing Request format enables many different methods of communication to convey request data from any application to any signature provider. 479 | 480 | The following are a few examples of how these payloads could be transmitted. 481 | 482 | ### Custom URI Scheme Format 483 | 484 | The EOSIO Signing Request in a custom URI scheme format uses the `scheme` and `path` components defined within [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt). 485 | 486 | ``` 487 | esr: 488 | \_/ \_______________/ 489 | | | 490 | scheme path 491 | ``` 492 | 493 | The `scheme` that defines the URI format is `esr`. Any client application capable of handling EOSIO transactions can register itself as the default system handler for this scheme. 494 | 495 | The `path` portion of the URI is a represents a "[Signing Request](#Signing-Request-Specification)". The data that makes up each request is serialized using the same binary format as the EOSIO blockchain. Each request is also encoded using a [url-safe Base64 variant](#base64u) and optionally [compressed using zlib deflate](#compression). 496 | 497 | ###### Format Example 498 | 499 | The following is an example of a `voteproducer` action on the `eosio` contract within the `path` of the URI. 500 | 501 | ``` 502 | esr:gmNgZGRkAIFXBqEFopc6760yugsVYWCA0YIwxgKjuxLSL6-mgmQA 503 | \_/ \__________________________________________________/ 504 | | | 505 | scheme path 506 | ``` 507 | 508 | Once decoded/inflated ([preview request](https://eosio.to/gmNgZGRkAIFXBqEFopc6760yugsVYWCA0YIwxgKjuxLSL6-mgmQA)) it will return the following signing request: 509 | 510 | ``` 511 | { 512 | "callback": "", 513 | "chain_id": [ "chain_alias", 1 ], 514 | "flags": 1, 515 | "info": [], 516 | "req": [ 517 | [ 518 | "action[]", 519 | { 520 | "account": "eosio", 521 | "name": "voteproducer", 522 | "authorization": [ 523 | { 524 | "actor": "............1", 525 | "permission": "............2" 526 | } 527 | ], 528 | "data": { 529 | "voter": "............1", 530 | "proxy": "greymassvote", 531 | "producers": [] 532 | } 533 | } 534 | ] 535 | ] 536 | } 537 | ``` 538 | 539 | ### URI Usage 540 | 541 | Many URI schemes are commonly used within hyperlinks (anchor tags) in HTML and QR codes to allow a camera-based transfer of information in mobile devices. Taking the transaction from the above example of a referendum vote action, with a URI of: 542 | 543 | ``` 544 | esr:gmNgZGRkAIFXBqEFopc6760yugsVYWCA0YIwxgKjuxLSL6-mgmQA 545 | ``` 546 | 547 | The transaction can be triggered with the following examples: 548 | 549 | ###### Hyperlink 550 | 551 | Example: 552 | 553 | ``` 554 | 555 | Clickable Hyperlink 556 | 557 | ``` 558 | 559 | If a user were to click the above link with a EOSIO URI compatible application installed, the transaction would be triggered within the end users chosen EOSIO client. 560 | 561 | ### Custom QR Code Format 562 | 563 | As well as being portable enough for usage within a URI/URL format, the same payload data can also be represented as a QR Code to be consumed by any device with QR scanning capabilities. 564 | 565 | ![qrcode:gmNgZGRkAIFXBqEFopc6760yugsVYWCA0YIwxgKjuxLSL6-mgmQA](../assets/eep-7/qrcode.png) 566 | 567 | Scanning the above QR code on a device with QR Code capabilities could trigger the payload within the end user specified signature provider. 568 | 569 | --- 570 | 571 | ## Implementations 572 | 573 | Existing implementation of the EOSIO URI Scheme (REV 2) include: 574 | 575 | ##### JS Client Session Frameworks 576 | 577 | - [greymass/anchor-link](https://github.com/greymass/anchor-link) ([npm](https://www.npmjs.com/package/anchor-link)): A JavaScript library that uses ESR identity requests to create user sessions for bidirectional communication between applications and signature providers. 578 | - [eosnewyork/eos-transit-anchorlink-provider](https://github.com/eosnewyork/eos-transit/tree/master/packages/eos-transit-anchorlink-provider) ([npm](https://www.npmjs.com/package/eos-transit-anchorlink-provider)): A JavaScript plugin for [eosnewyork/eos-transit](https://github.com/eosnewyork/eos-transit) that uses [greymass/anchor-link](https://github.com/greymass/anchor-link) to allow authentication and signing requests using the ESR protocol. 579 | - [greymass/ual-anchor](https://github.com/greymass/ual-anchor) ([npm](https://www.npmjs.com/package/ual-anchor)): A JavaScript plugin for [EOSIO/universal-authenticator-library](https://github.com/EOSIO/universal-authenticator-library) that uses [greymass/anchor-link](https://github.com/greymass/anchor-link) to allow authentication and signing requests using the ESR protocol. 580 | 581 | ##### JS SDKs/Libraries 582 | - [greymass/eosio-signing-request](https://github.com/greymass/eosio-signing-request) ([npm](https://www.npmjs.com/package/eosio-signing-request)): A JavaScript library to facilitate the creation and consumption of EOSIO Signing Requests. 583 | - [greymass/anchor-link-browser-transport](https://github.com/greymass/anchor-link-browser-transport) ([npm](https://www.npmjs.com/package/anchor-link-browser-transport)): A transport layer and browser/UI toolkit that extends [greymass/anchor-link](https://github.com/greymass/anchor-link) for applications to integrate directly. 584 | - [greymass/anchor-link-console-transport](https://github.com/greymass/anchor-link-console-transport) ([npm](https://www.npmjs.com/package/anchor-link-console-transport)): A transport layer for developers working with ESR to interact with [greymass/anchor-link](https://github.com/greymass/anchor-link) in a console environment. 585 | 586 | ##### JS Examples 587 | 588 | - [greymass/anchor-link-demo](https://github.com/greymass/anchor-link-demo): A VueJS example webapp supporting a single account capable of signing any contract/action using the [greymass/anchor-link](https://github.com/greymass/anchor-link) library. 589 | - [greymass/anchor-link-demo-multipass](https://github.com/greymass/anchor-link-demo-multipass): A ReactJS example webapp supporting multiple accounts and multiple blockchains using the [greymass/anchor-link](https://github.com/greymass/anchor-link) library. 590 | - [greymass/eos-transit-demo-multipass](https://github.com/greymass/eos-transit-demo-multipass): A ReactJS example webapp supporting multiple accounts and multiple blockchains using the [eosnewyork/eos-transit-anchorlink-provider](https://github.com/eosnewyork/eos-transit/tree/master/packages/eos-transit-anchorlink-provider) library. 591 | - [greymass/eosio-signing-request-demo](https://github.com/greymass/eosio-signing-request-demo): Example code using the base [greymass/eosio-signing-request](https://github.com/greymass/eosio-signing-request) library to create request payloads. 592 | - [greymass/greymassfuel-transit-demo](https://github.com/greymass/greymassfuel-transit-demo): A VueJS example webapp using [eosnewyork/eos-transit](https://github.com/eosnewyork/eos-transit) and [eosnewyork/eos-transit-anchorlink-provider](https://github.com/eosnewyork/eos-transit/tree/master/packages/eos-transit-anchorlink-provider) to create example transactions that use OBFA action. 593 | - [greymass/ual-anchor-demo](https://github.com/greymass/ual-anchor-demo): An example based on the [EOSIO/ual-plainjs-renderer](https://github.com/EOSIO/ual-plainjs-renderer/tree/master/examples) example, utilizing [greymass/ual-anchor](https://github.com/greymass/ual-anchor). 594 | - [greymass/ual-reactjs-renderer-demo-multipass](https://github.com/greymass/ual-reactjs-renderer-demo-multipass): A ReactJS example webapp supporting multiple accounts and multiple blockchains using the [greymass/ual-anchor](https://github.com/greymass/ual-anchor) and [ual-reactjs-renderer](https://github.com/EOSIO/ual-reactjs-renderer) libraries. 595 | 596 | 597 | ##### Java Libraries 598 | 599 | - [greymass/eosio-signing-request-java](https://github.com/greymass/eosio-signing-request-java) ([bintray](https://bintray.com/greymass/com.greymass.eosio-signing-request/eosio-signing-request-java)): A Java wrapper for [eosio-signing-request](https://github.com/greymass/eosio-signing-request) to facilitate the creation and consumption of EOSIO Signing Requests. 600 | 601 | ##### Swift Libraries 602 | - [greymass/swift-eosio](https://github.com/greymass/swift-eosio): A library for working with EOSIO blockchains, which has built-in support for ESR requests similar to [greymass/eosio-signing-request](https://github.com/greymass/eosio-signing-request). 603 | 604 | ##### Signature Providers 605 | 606 | - [Anchor](https://github.com/greymass/eos-voter): ESR compatible wallet/signature provider. 607 | 608 | ##### User Interfaces 609 | 610 | - [EOSIO.to](https://eosio.to) ([source code](https://github.com/greymass/eosio.to)): Provides Signing Request verification and signature provider hooks. 611 | - [EOSIO URI Builder](https://greymass.github.io/eosio-uri-builder/) ([source code](https://github.com/greymass/eosio-uri-builder)): User Interface to encode/decode EOSIO Signing Requests. 612 | 613 | --- 614 | 615 | ## Test Cases 616 | 617 | **Note**: These examples all use [eosjs v20.0.0](https://github.com/EOSIO/eosjs/tree/v20.0.0) for its `Serialize` component. 618 | 619 | #### Example - Transaction to encoded PATH 620 | 621 | This example will take an EOSIO Signing Request and convert it into a compressed string. 622 | 623 | [![Edit clever-heisenberg-gobmi](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/clever-heisenberg-gobmi?fontsize=14&hidenavigation=1&theme=dark) 624 | 625 | ```js 626 | /* 627 | EOSIO URI Specification 628 | 629 | Example: Encoding an EOSIO Signing Request into a compressed payload 630 | */ 631 | 632 | const { Serialize } = require('eosjs'); 633 | const zlib = require('zlib'); 634 | const util = require('util'); 635 | 636 | const textEncoder = new util.TextEncoder(); 637 | const textDecoder = new util.TextDecoder(); 638 | 639 | // The signing request to be encoded 640 | const signingRequest = { 641 | // "chain_id": [ "uint8", 1 ], 642 | "callback": "https://domain.com", 643 | "chain_id": [ "chain_id", "aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906"], 644 | "flags": 1, 645 | "info": [], 646 | "req": [ 647 | "action[]", 648 | [ 649 | { 650 | "account": "eosio.forum", 651 | "name": "vote", 652 | "authorization": [ 653 | { 654 | "actor": "............1", 655 | "permission": "............2" 656 | } 657 | ], 658 | "data": "0100000000000000000000204643BABA0100" 659 | } 660 | ] 661 | ], 662 | } 663 | 664 | // The minified ABI struct used to deserialize the request 665 | const abi = {version:"eosio::abi/1.1",types:[{new_type_name:"account_name",type:"name"},{new_type_name:"action_name",type:"name"},{new_type_name:"permission_name",type:"name"},{new_type_name:"chain_alias",type:"uint8"},{new_type_name:"chain_id",type:"checksum256"},{new_type_name:"request_flags",type:"uint8"}],structs:[{name:"permission_level",fields:[{name:"actor",type:"account_name"},{name:"permission",type:"permission_name"}]},{name:"action",fields:[{name:"account",type:"account_name"},{name:"name",type:"action_name"},{name:"authorization",type:"permission_level[]"},{name:"data",type:"bytes"}]},{name:"extension",fields:[{name:"type",type:"uint16"},{name:"data",type:"bytes"}]},{name:"transaction_header",fields:[{name:"expiration",type:"time_point_sec"},{name:"ref_block_num",type:"uint16"},{name:"ref_block_prefix",type:"uint32"},{name:"max_net_usage_words",type:"varuint32"},{name:"max_cpu_usage_ms",type:"uint8"},{name:"delay_sec",type:"varuint32"}]},{name:"transaction",base:"transaction_header",fields:[{name:"context_free_actions",type:"action[]"},{name:"actions",type:"action[]"},{name:"transaction_extensions",type:"extension[]"}]},{name:"info_pair",fields:[{name:"key",type:"string"},{name:"value",type:"bytes"}]},{name:"signing_request",fields:[{name:"chain_id",type:"variant_id"},{name:"req",type:"variant_req"},{name:"flags",type:"request_flags"},{name:"callback",type:"string"},{name:"info",type:"info_pair[]"}]},{name:"identity",fields:[{name:"permission",type:"permission_level?"}]},{name:"request_signature",fields:[{name:"signer",type:"name"},{name:"signature",type:"signature"}]}],variants:[{name:"variant_id",types:["chain_alias","chain_id"]},{name:"variant_req",types:["action","action[]","transaction","identity"]}],actions:[{name:"identity",type:"identity"}]};; 666 | 667 | /** 668 | * ------------------------------------------------ 669 | * Base64u encoding - URL-Safe Base64 variant no padding. 670 | * Based on https://gist.github.com/jonleighton/958841 671 | * ------------------------------------------------ 672 | */ 673 | 674 | const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; 675 | 676 | function encode(data) { 677 | const byteLength = data.byteLength; 678 | const byteRemainder = byteLength % 3; 679 | const mainLength = byteLength - byteRemainder; 680 | 681 | const parts = []; 682 | 683 | let a; 684 | let b; 685 | let c; 686 | let d; 687 | let chunk; 688 | 689 | // Main loop deals with bytes in chunks of 3 690 | for (let i = 0; i < mainLength; i += 3) { 691 | // Combine the three bytes into a single integer 692 | chunk = (data[i] << 16) | (data[i + 1] << 8) | data[i + 2]; 693 | 694 | // Use bitmasks to extract 6-bit segments from the triplet 695 | a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 696 | b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 697 | c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 698 | d = chunk & 63; // 63 = 2^6 - 1 699 | 700 | // Convert the raw binary segments to the appropriate ASCII encoding 701 | parts.push(charset[a] + charset[b] + charset[c] + charset[d]); 702 | } 703 | 704 | // Deal with the remaining bytes 705 | if (byteRemainder === 1) { 706 | chunk = data[mainLength] 707 | 708 | a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2 709 | 710 | // Set the 4 least significant bits to zero 711 | b = (chunk & 3) << 4 // 3 = 2^2 - 1 712 | 713 | parts.push(charset[a] + charset[b]) 714 | } else if (byteRemainder === 2) { 715 | chunk = (data[mainLength] << 8) | data[mainLength + 1] 716 | 717 | a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10 718 | b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4 719 | 720 | // Set the 2 least significant bits to zero 721 | c = (chunk & 15) << 2 // 15 = 2^4 - 1 722 | 723 | parts.push(charset[a] + charset[b] + charset[c]) 724 | } 725 | 726 | return parts.join('') 727 | } 728 | 729 | const buffer = new Serialize.SerialBuffer({ 730 | textEncoder: textEncoder, 731 | textDecoder: textDecoder, 732 | }) 733 | 734 | const requestTypes = Serialize.getTypesFromAbi(Serialize.createInitialTypes(), abi); 735 | const requestAbi = requestTypes.get('signing_request'); 736 | requestAbi.serialize(buffer, signingRequest); 737 | 738 | let header = 2; 739 | header |= 1 << 7; 740 | 741 | const array = new Uint8Array(zlib.deflateRawSync(Buffer.from(buffer.asUint8Array()))); 742 | 743 | // Build the array containing the header as the first byte followed by the request 744 | const data = new Uint8Array(array.byteLength + 1); 745 | data[0] = header; 746 | data.set(array, 1); 747 | 748 | // base64u encode the array to a string 749 | const encoded = encode(data); 750 | console.log(encoded); 751 | 752 | /* Output: 753 | 754 | gmNcs7jsE9uOP6rL3rrcvpMWUmN27LCdleD836_eTzFz-vCSjZGRYcm-EsZXBqEMILDA6C5QBAKYoLQQTAAIFNycd-1iZGAUyigpKSi20tdPyc9NzMzTS87PZQAA 755 | 756 | */ 757 | ```` 758 | 759 | #### Example - Encoded PATH to Transaction 760 | 761 | This example will take a compressed payload string and convert it into an EOSIO Signing Request structure. 762 | 763 | [![Edit mutable-wind-ccvvn](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/mutable-wind-ccvvn?fontsize=14&hidenavigation=1&theme=dark) 764 | 765 | ```js 766 | /* 767 | EOSIO URI Specification 768 | 769 | Example: Decoding and inflating a encoded payload string 770 | */ 771 | 772 | const { Serialize } = require('eosjs'); 773 | const zlib = require('zlib'); 774 | const util = require('util'); 775 | 776 | const textEncoder = new util.TextEncoder(); 777 | const textDecoder = new util.TextDecoder(); 778 | 779 | // The URI path to be decoded 780 | const uriPath = 'gmNcs7jsE9uOP6rL3rrcvpMWUmN27LCdleD836_eTzFz-vCSjZGRYcm-EsZXBqEMILDA6C5QBAKYoLQQTAAIFNycd-1iZGAUyigpKSi20tdPyc9NzMzTS87PZQAA'; 781 | 782 | // The minified ABI struct used to deserialize the request 783 | const abi = {version:"eosio::abi/1.1",types:[{new_type_name:"account_name",type:"name"},{new_type_name:"action_name",type:"name"},{new_type_name:"permission_name",type:"name"},{new_type_name:"chain_alias",type:"uint8"},{new_type_name:"chain_id",type:"checksum256"},{new_type_name:"request_flags",type:"uint8"}],structs:[{name:"permission_level",fields:[{name:"actor",type:"account_name"},{name:"permission",type:"permission_name"}]},{name:"action",fields:[{name:"account",type:"account_name"},{name:"name",type:"action_name"},{name:"authorization",type:"permission_level[]"},{name:"data",type:"bytes"}]},{name:"extension",fields:[{name:"type",type:"uint16"},{name:"data",type:"bytes"}]},{name:"transaction_header",fields:[{name:"expiration",type:"time_point_sec"},{name:"ref_block_num",type:"uint16"},{name:"ref_block_prefix",type:"uint32"},{name:"max_net_usage_words",type:"varuint32"},{name:"max_cpu_usage_ms",type:"uint8"},{name:"delay_sec",type:"varuint32"}]},{name:"transaction",base:"transaction_header",fields:[{name:"context_free_actions",type:"action[]"},{name:"actions",type:"action[]"},{name:"transaction_extensions",type:"extension[]"}]},{name:"info_pair",fields:[{name:"key",type:"string"},{name:"value",type:"bytes"}]},{name:"signing_request",fields:[{name:"chain_id",type:"variant_id"},{name:"req",type:"variant_req"},{name:"flags",type:"request_flags"},{name:"callback",type:"string"},{name:"info",type:"info_pair[]"}]},{name:"identity",fields:[{name:"permission",type:"permission_level?"}]},{name:"request_signature",fields:[{name:"signer",type:"name"},{name:"signature",type:"signature"}]}],variants:[{name:"variant_id",types:["chain_alias","chain_id"]},{name:"variant_req",types:["action","action[]","transaction","identity"]}],actions:[{name:"identity",type:"identity"}]};; 784 | 785 | /** 786 | * Base64u - URL-Safe Base64 variant no padding. 787 | * Based on https://gist.github.com/jonleighton/958841 788 | */ 789 | 790 | const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; 791 | const lookup = new Uint8Array(256); 792 | for (let i = 0; i < 64; i += 1) { lookup[charset.charCodeAt(i)] = i; } 793 | 794 | function decode(input) { 795 | const byteLength = input.length * 0.75; 796 | const data = new Uint8Array(byteLength); 797 | 798 | let a; 799 | let b; 800 | let c; 801 | let d; 802 | let p = 0; 803 | 804 | for (let i = 0; i < input.length; i += 4) { 805 | a = lookup[input.charCodeAt(i)]; 806 | b = lookup[input.charCodeAt(i + 1)]; 807 | c = lookup[input.charCodeAt(i + 2)]; 808 | d = lookup[input.charCodeAt(i + 3)]; 809 | 810 | data[p++] = (a << 2) | (b >> 4); 811 | data[p++] = ((b & 15) << 4) | (c >> 2); 812 | data[p++] = ((c & 3) << 6) | (d & 63); 813 | } 814 | 815 | return data; 816 | } 817 | 818 | // Decode the URI Path string into a Uint8Array byte array 819 | const data = decode(uriPath); 820 | 821 | // Retrieve header byte and check protocol version 822 | const header = data[0]; 823 | const version = header & ~(1 << 7); 824 | if (version !== 2) { 825 | throw new Error('Invalid protocol version'); 826 | } 827 | 828 | // Disregard data beyond header byte 829 | let array = data.slice(1); 830 | 831 | // Determine via header if zlib deflated and inflate if needed 832 | if ((header & 1 << 7) !== 0) { 833 | array = new Uint8Array(zlib.inflateRawSync(Buffer.from(array))); 834 | } 835 | 836 | // Create buffer based on the decoded/decompressed byte array 837 | const buffer = new Serialize.SerialBuffer({ textEncoder, textDecoder, array }); 838 | 839 | // Create and retrieve the signing_request abi 840 | const requestTypes = Serialize.getTypesFromAbi(Serialize.createInitialTypes(), abi); 841 | const requestAbi = requestTypes.get('signing_request'); 842 | 843 | // Deserialize the buffer using the signing_request abi and return request object 844 | const signingRequest = requestAbi.deserialize(buffer); 845 | console.log(util.inspect(signingRequest, { showHidden: false, depth: null })); 846 | 847 | /* Output: 848 | 849 | { 850 | chain_id: [ 851 | 'chain_id', 852 | 'ACA376F206B8FC25A6ED44DBDC66547C36C6C33E3A119FFBEAEF943642F0E906' 853 | ], 854 | req: [ 855 | 'action[]', 856 | [ 857 | { 858 | account: 'eosio.forum', 859 | name: 'vote', 860 | authorization: [ { actor: '............1', permission: '............2' } ], 861 | data: '0100000000000000000000204643BABA0100' 862 | } 863 | ] 864 | ], 865 | flags: 1, 866 | callback: 'https://domain.com', 867 | info: [] 868 | } 869 | 870 | */ 871 | ```` 872 | 873 | --- 874 | 875 | ## Appendix 876 | 877 | ##### Base64u 878 | 879 | An URL-safe version of Base64 where `+` is replaced by `-`, `/` by `_` and the padding (`=`) is trimmed. 880 | 881 | ``` 882 | base64 883 | SGn+dGhlcmUh/k5pY2X+b2b+eW91/nRv/mRlY29kZf5tZf46KQ== 884 | 885 | base64u 886 | SGn-dGhlcmUh_k5pY2X-b2b-eW91_nRv_mRlY29kZf5tZf46KQ 887 | ``` 888 | 889 | ##### Callback Proxies 890 | 891 | In an effort to help protect the privacy of EOSIO account holders, EOSIO clients which handle signing requests should allow a configurable proxy service to further anonymize outgoing callbacks. 892 | 893 | When a callback is made directly from a signing application, the IP address and other identifiable information is sent along with that request could be potentially used in malicious ways. To prevent this, the use of a simple proxy/forwarder can be implemented within the EOSIO client. 894 | 895 | For example, if a signing request specified a callback of: 896 | 897 | ``` 898 | https://example.com/signup?tx=ef82d7c2b81675554a4b58586dcf18c2a03a96ff3b8b408c50b34ed9380f94f5 899 | ``` 900 | 901 | This URL can be URI Encoded and passed to a trusted/no-log 3rd party service in order to forward the information. If a proxy service resided at `https://eosuriproxy.com/redirect/{{URL}}`, the callback URL could be then passed through the service as such: 902 | 903 | ```js 904 | const proxyUri = `https://eosuriproxy.com/redirect/${encodeURIComponent(https://example.com/signup?tx=ef82d7c2b81675554a4b58586dcf18c2a03a96ff3b8b408c50b34ed9380f94f5)}` 905 | ``` 906 | 907 | The proxy service would intercept the callback and forward the request onto the destination URL. 908 | 909 | ##### Chain Aliases 910 | 911 | The following aliases are predefined: 912 | 913 | value | name | chain_id 914 | --------|----------|---------- 915 | `0x00` | RESERVED | 916 | `0x01` | EOS | `aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906` 917 | `0x02` | TELOS | `4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11` 918 | `0x03` | JUNGLE | `038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca` 919 | `0x04` | KYLIN | `5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191` 920 | `0x05` | WORBLI | `73647cde120091e0a4b85bced2f3cfdb3041e266cbbe95cee59b73235a1b3b6f` 921 | `0x06` | BOS | `d5a3d18fbb3c084e3b1f3fa98c21014b5f3db536cc15d08f9f6479517c6a3d86` 922 | `0x07` | MEETONE | `cfe6486a83bad4962f232d48003b1824ab5665c36778141034d75e57b956e422` 923 | `0x08` | INSIGHTS | `b042025541e25a472bffde2d62edd457b7e70cee943412b1ea0f044f88591664` 924 | `0x09` | BEOS | `b912d19a6abd2b1b05611ae5be473355d64d95aeff0c09bedc8c166cd6468fe4` 925 | `0x10` | WAX | `1064487b3cd1a897ce03ae5b6a865651747e2e152090f99c1d19d44e01aea5a4` 926 | `0x11` | PROTON | `384da888112027f0321850a169f737c33e53b388aad48b5adace4bab97f437e0` 927 | `0x12` | FIO | `21dcae42c0182200e93f954a074011f9048a7624c6fe81d3c9541a614a88bd1c` 928 | 929 | ##### Compression 930 | 931 | If the compression bit is set in the header the signing request data is compressed using zlib deflate. 932 | 933 | Using compression is recommended since it generates much shorter URIs (and smaller QR codes) but left optional since when used in a contract bandwidth is often cheaper than CPU time. 934 | 935 | The following example shows the same signing request, compressed vs uncompressed. 936 | 937 | ``` 938 | original: 939 | 940 | esr:AQABAACmgjQD6jBVAAAAVy08zc0BAQAAAAAAAAABAAAAAAAAADEBAAAAAAAAAAAAAAAAAChdoGgGAAAAAAAERU9TAAAAABBzaGFyZSBhbmQgZW5qb3khAQA 941 | 942 | zlib deflated: 943 | 944 | esr:gWNgZGBY1mTC_MoglIGBIVzX5uxZRqAQGMBoQxgDAjRiF2SwgVksrv7BIFqgOCOxKFUhMS9FITUvK79SkZEBAA 945 | ``` 946 | 947 | ##### Identity Requests 948 | 949 | Identity requests can be issued to allow someone to prove ownership of a EOSIO account permission. They can either request a specific permission or any permission to be used as a login request. 950 | 951 | This request type is not valid unless a callback is set since they can not be broadcast on-chain. 952 | 953 | **Note that identity requests can only verify key auths, not account auths. E.g. you can not prove ownership of `bob@active` using `alice@active` even though bob has granted alice an account auth for that permission.** 954 | 955 | ###### Identity Proof Action 956 | 957 | To create the identity proof the wallet signs a special EOSIO transaction that is not valid on-chain. The reason for it being a transaction and not just an arbitrary signature is that some hardware wallets do not support signing anything other than a EOSIO transaction. 958 | 959 | To resolve a identity request to the identity proof action the optional account permssion from the request data is copied to the following action: 960 | 961 | ```jsonc 962 | { 963 | "account": "", // uint64(0) 964 | "name": "identity", 965 | "authorization": [ 966 | { 967 | "actor": "foobarfoobar", 968 | "permission": "active" 969 | } 970 | ], 971 | "data": { 972 | "permission": { 973 | "actor": "foobarfoobar", 974 | "permission": "active" 975 | } 976 | } 977 | } 978 | ``` 979 | 980 | If the permission is not set in the request data the placeholder permission is used instead: 981 | 982 | ```jsonc 983 | { 984 | "account": "", 985 | "name": "identity", 986 | "authorization": [ 987 | { 988 | "actor": "............1", 989 | "permission": "............2" 990 | } 991 | ], 992 | "data": { 993 | "permission": { 994 | "actor": "............1", 995 | "permission": "............2" 996 | } 997 | } 998 | } 999 | ``` 1000 | 1001 | ###### Signing Identity Proof Actions 1002 | 1003 | The signature is just a standard EOSIO transaction signature (chainId + serializedTx + 32bytePadding) but can also be thought of as a magic if a full EOSIO library isn't available at the verification point. 1004 | 1005 | ``` 1006 | sign(sha256( 1007 | __ 32 byte chain id_____________________________________________ 1008 | 00000000000000000000000000000100000000000000000000003ebb3c557201 1009 | __ 16 byte account permission x2 _______________________________ 1010 | ___ 33 byte zero-padding _________________________________________ 1011 | )) 1012 | ``` 1013 | 1014 | ##### MIME Type 1015 | 1016 | In situations where a MIME type is applicable, the following should be used: 1017 | 1018 | ``` 1019 | application/eosio-signing-request 1020 | ``` 1021 | 1022 | If signing requests are being saved to files, the file type extension should be saved as `.esr`, e.g. `myfile.esr`. 1023 | 1024 | ##### Null transaction header 1025 | 1026 | The "null" header consists of expiration date set to `1970-01-01T00:00:00` and ref block number and prefix set to zero and is used to denote that the resolver should fill in appropriate values. 1027 | 1028 | ```jsonc 1029 | { 1030 | "expiration": "1970-01-01T00:00:00", 1031 | "ref_block_num": 0, 1032 | "ref_block_prefix": 0, 1033 | // ... 1034 | } 1035 | ``` 1036 | 1037 | ##### Signing Request - Placeholders 1038 | 1039 | Within the payload of a signing request, placeholders may be set in both `authorization` and `data` (sub)fields. REV 2 of the URI Specification defines two placeholders: 1040 | 1041 | - `............1` represents the account name used to sign the transaction. 1042 | - `............2` represents the account permission used to sign the transaction. 1043 | 1044 | These placeholders should be resolved within EOSIO Clients based on the data provided by the signer when resolving a transaction. 1045 | 1046 | Given the following signing request example: 1047 | 1048 | ```js 1049 | { account: "eosio.token", 1050 | name: "transfer", 1051 | authorization: [{actor: "............1", permission: "............2"}], 1052 | data: { 1053 | from: "............1", 1054 | to: "bar", 1055 | quantity: "42.0000 EOS", 1056 | memo: "Don't panic" }} 1057 | ``` 1058 | 1059 | The EOSIO Client handling the request should notice the placeholder values and resolve their values. In this instance, if it were being signed with the authority `foo@active`, the action would resolve to: 1060 | 1061 | 1062 | ```js 1063 | { account: "eosio.token", 1064 | name: "transfer", 1065 | authorization: [{actor: "foo", permission: "active"}], 1066 | data: { 1067 | from: "foo", 1068 | to: "bar", 1069 | quantity: "42.0000 EOS", 1070 | memo: "Don't panic" }} 1071 | ``` 1072 | 1073 | This allows the end user control over which account to trigger an action with and requires no knowledge of the account within a URI. 1074 | 1075 | ##### Signing Request - Schema 1076 | 1077 | The data represented in a Signing Request can be represented in the following structures. 1078 | 1079 | ###### Signing Request represented as a EOSIO C++ struct: 1080 | 1081 | ```cpp 1082 | #include 1083 | #include 1084 | #include 1085 | 1086 | using namespace eosio; 1087 | using namespace std; 1088 | 1089 | typedef checksum256 chain_id; 1090 | typedef uint8 chain_alias; 1091 | 1092 | struct callback { 1093 | string url; 1094 | bool background; 1095 | }; 1096 | 1097 | struct signing_request { 1098 | variant chain_id; 1099 | variant, transaction> req; 1100 | bool broadcast; 1101 | optional callback; 1102 | } 1103 | ``` 1104 | 1105 | ###### Signing Request represented as an EOSIO ABI: 1106 | 1107 | ```json 1108 | { 1109 | version: 'eosio::abi/1.1', 1110 | types: [ 1111 | { 1112 | new_type_name: 'account_name', 1113 | type: 'name', 1114 | }, 1115 | { 1116 | new_type_name: 'action_name', 1117 | type: 'name', 1118 | }, 1119 | { 1120 | new_type_name: 'permission_name', 1121 | type: 'name', 1122 | }, 1123 | { 1124 | new_type_name: 'chain_alias', 1125 | type: 'uint8', 1126 | }, 1127 | { 1128 | new_type_name: 'chain_id', 1129 | type: 'checksum256', 1130 | }, 1131 | { 1132 | new_type_name: 'request_flags', 1133 | type: 'uint8', 1134 | }, 1135 | ], 1136 | structs: [ 1137 | { 1138 | name: 'permission_level', 1139 | fields: [ 1140 | { 1141 | name: 'actor', 1142 | type: 'account_name', 1143 | }, 1144 | { 1145 | name: 'permission', 1146 | type: 'permission_name', 1147 | }, 1148 | ], 1149 | }, 1150 | { 1151 | name: 'action', 1152 | fields: [ 1153 | { 1154 | name: 'account', 1155 | type: 'account_name', 1156 | }, 1157 | { 1158 | name: 'name', 1159 | type: 'action_name', 1160 | }, 1161 | { 1162 | name: 'authorization', 1163 | type: 'permission_level[]', 1164 | }, 1165 | { 1166 | name: 'data', 1167 | type: 'bytes', 1168 | }, 1169 | ], 1170 | }, 1171 | { 1172 | name: 'extension', 1173 | fields: [ 1174 | { 1175 | name: 'type', 1176 | type: 'uint16', 1177 | }, 1178 | { 1179 | name: 'data', 1180 | type: 'bytes', 1181 | }, 1182 | ], 1183 | }, 1184 | { 1185 | name: 'transaction_header', 1186 | fields: [ 1187 | { 1188 | name: 'expiration', 1189 | type: 'time_point_sec', 1190 | }, 1191 | { 1192 | name: 'ref_block_num', 1193 | type: 'uint16', 1194 | }, 1195 | { 1196 | name: 'ref_block_prefix', 1197 | type: 'uint32', 1198 | }, 1199 | { 1200 | name: 'max_net_usage_words', 1201 | type: 'varuint32', 1202 | }, 1203 | { 1204 | name: 'max_cpu_usage_ms', 1205 | type: 'uint8', 1206 | }, 1207 | { 1208 | name: 'delay_sec', 1209 | type: 'varuint32', 1210 | }, 1211 | ], 1212 | }, 1213 | { 1214 | name: 'transaction', 1215 | base: 'transaction_header', 1216 | fields: [ 1217 | { 1218 | name: 'context_free_actions', 1219 | type: 'action[]', 1220 | }, 1221 | { 1222 | name: 'actions', 1223 | type: 'action[]', 1224 | }, 1225 | { 1226 | name: 'transaction_extensions', 1227 | type: 'extension[]', 1228 | }, 1229 | ], 1230 | }, 1231 | { 1232 | name: 'info_pair', 1233 | fields: [ 1234 | { 1235 | name: 'key', 1236 | type: 'string', 1237 | }, 1238 | { 1239 | name: 'value', 1240 | type: 'bytes', 1241 | }, 1242 | ], 1243 | }, 1244 | { 1245 | name: 'signing_request', 1246 | fields: [ 1247 | { 1248 | name: 'chain_id', 1249 | type: 'variant_id', 1250 | }, 1251 | { 1252 | name: 'req', 1253 | type: 'variant_req', 1254 | }, 1255 | { 1256 | name: 'flags', 1257 | type: 'request_flags', 1258 | }, 1259 | { 1260 | name: 'callback', 1261 | type: 'string', 1262 | }, 1263 | { 1264 | name: 'info', 1265 | type: 'info_pair[]', 1266 | }, 1267 | ], 1268 | }, 1269 | { 1270 | name: 'identity', 1271 | fields: [ 1272 | { 1273 | name: 'permission', 1274 | type: 'permission_level?', 1275 | }, 1276 | ], 1277 | }, 1278 | { 1279 | name: 'request_signature', 1280 | fields: [ 1281 | { 1282 | name: 'signer', 1283 | type: 'name', 1284 | }, 1285 | { 1286 | name: 'signature', 1287 | type: 'signature', 1288 | }, 1289 | ], 1290 | }, 1291 | ], 1292 | variants: [ 1293 | { 1294 | name: 'variant_id', 1295 | types: ['chain_alias', 'chain_id'], 1296 | }, 1297 | { 1298 | name: 'variant_req', 1299 | types: ['action', 'action[]', 'transaction', 'identity'], 1300 | }, 1301 | ], 1302 | actions: [ 1303 | { 1304 | name: 'identity', 1305 | type: 'identity', 1306 | }, 1307 | ], 1308 | } 1309 | ``` 1310 | 1311 | --- 1312 | 1313 | ## Backwards Compatibility 1314 | 1315 | - Revision 2 of the ESR signing protocol introduces breaking changes from Revision 1. 1316 | 1317 | --- 1318 | 1319 | ## Change Log 1320 | 1321 | - 2020/05/20: Updated to Revision 2. 1322 | - 2019/10/28: Added change log, MIME type recommendation 1323 | - 2020/05/29: Add details on request resolution and & signatures 1324 | 1325 | --- 1326 | 1327 | ## Acknowledgements 1328 | 1329 | This proposal is inspired by the Bitcoin's [BIP 0021](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki), Ethereum's [ERC-67](https://github.com/ethereum/EIPs/issues/67), [EIP-681](https://eips.ethereum.org/EIPS/eip-681), [EIP-831](http://eips.ethereum.org/EIPS/eip-831), and Steem's [URI Spec](https://github.com/steemit/steem-uri-spec). Implementations of the URI protocol within these ecosystems pioneered the way by establishing a baseline for future adaptations like this. 1330 | 1331 | --- 1332 | 1333 | ## Copyright 1334 | 1335 | Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). 1336 | --------------------------------------------------------------------------------