From f719e9b74321b247dbbfef11ad92acc8d3719115 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 11 Jan 2019 11:25:49 +0000 Subject: [PATCH 001/431] Fix rendering of EIP-155 --- EIPS/eip-155.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EIPS/eip-155.md b/EIPS/eip-155.md index b5f4d3b1..84a36459 100644 --- a/EIPS/eip-155.md +++ b/EIPS/eip-155.md @@ -14,9 +14,11 @@ created: 2016-10-14 ### Parameters - `FORK_BLKNUM`: 2,675,000 - `CHAIN_ID`: 1 (main net) + ### Specification If `block.number >= FORK_BLKNUM` and `v = CHAIN_ID * 2 + 35` or `v = CHAIN_ID * 2 + 36`, then when computing the hash of a transaction for purposes of signing or recovering, instead of hashing only the first six elements (i.e. nonce, gasprice, startgas, to, value, data), hash nine elements, with `v` replaced by `CHAIN_ID`, `r = 0` and `s = 0`. The currently existing signature scheme using `v = 27` and `v = 28` remains valid and continues to operate under the same rules as it does now. + ### Example Consider a transaction with `nonce = 9`, `gasprice = 20 * 10**9`, `startgas = 21000`, `to = 0x3535353535353535353535353535353535353535`, `value = 10**18`, `data=''` (empty). @@ -44,6 +46,7 @@ Notice the use of 37 instead of 27. The signed tx would become: ``` 0xf86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83 ``` + ### Rationale This would provide a way to send transactions that work on Ethereum without working on ETC or the Morden testnet. ETC is encouraged to adopt this EIP but replacing `CHAIN_ID` with a different value, and all future testnets, consortium chains and alt-etherea are encouraged to adopt this EIP replacing `CHAIN_ID` with a unique value. From 79bb399fe77b77afe31ccf7d4c011a8377d70d6e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 Jan 2019 00:15:25 +0100 Subject: [PATCH 002/431] Init generalized account versioning scheme --- EIPS/eip-account-versioning.md | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 EIPS/eip-account-versioning.md diff --git a/EIPS/eip-account-versioning.md b/EIPS/eip-account-versioning.md new file mode 100644 index 00000000..bde6b1fc --- /dev/null +++ b/EIPS/eip-account-versioning.md @@ -0,0 +1,67 @@ +--- +eip: x +title: Generalized Account Versioning Scheme +author: Wei Tang (@sorpaas) +discussions-to: To be added +status: Draft +type: Standards Track +category: Core +created: 2017-12-30 +--- + +## Abstract + +This defines a method of hard forking while maintaining the exact functionality of existing account by allowing multiple versions of the virtual machines to execute in the same block. This is also useful to define future account state structures when we introduce the on-chain WebAssembly virtual machine. + +## Motivation + +By allowing account versioning, we can execute different virtual machine for contracts created at different times. This allows breaking features to be implemented while making sure existing contracts work as expected. + +Note that this specification might not apply to all hard forks. We have emergency hard forks in the past due to network attacks. Whether they should maintain existing account compatibility should be evaluated in individual basis. If the attack can only be executed once against some particular contracts, then the scheme defined here might still be applicable. Otherwise, having a plain emergency hard fork might still be a good idea. + +## Specification + +### Account State + +After the first hard fork using this scheme, newly created account state stored in the world state trie is changed to become a five-item RLP encoding: `nonce`, `balance`, `storageRoot`, `codeHash` and `version`. The `version` field defines that when a contract call transaction or `CALL` opcode is executed against this contract, which version of the virtual machine should be used. Four-item RLP encoding account state are considered to have the `version` 0. + +`CREATE`/`CREATE2` opcode, the contract creation transaction, and a normal call which initialize a new account, would only deploy accounts of the newest version. + +The behavior of `CALLCODE` and `DELEGATECALL` are not affected by the hard fork -- they would fetch the contract code (even if the contract is deployed in a newer version) and still use the virtual machine version defined in the current contract (or in the case of within the input of contract creation transaction or `CREATE` opcode, the newest virtual machine version) to execute the code. + +If a message call transaction creates a new account, the newly created account will have the newest account version number in the network. + +Precompiled contracts, once created, use the given account version. If the account does not exist yet, newest version of the VM is used (as in the standard message call transaction). This is made so that VMs do not need full permission of the state trie but only with in the smart contract boundary. It is expected that once a precompiled contract is created, its behavior will not change. + +### Gas Boundary + +With the boundary between the VM and the blockchain, we don't consider there're additional gas cost involved. VM used defines the gas table applied. As examples, intrinsic gas only applies to actual transactions so only the newest ones are used. `CALL` and `CREATE` will use the old gas cost as the opcode gas cost, and once switched to the new VM, use the new gas cost from there. + +## Example + +Consider we would like to have the REVERT opcode hard fork in Ethereum Classic using this scheme. After the hard fork, we have: + +* Existing accounts are still of four-item RLP encoding. When a transaction has `to` field pointing to them, they're executed using version 0 of EVM. REVERT is the same as INVALID and consumes all the gases. +* A new contract creation transaction is executed using version 1 virtual machine, and would only create version 1 account on the blockchain. When executing them, it uses version 1 of EVM and REVERT uses the new behavior. +* When a version 0 account issues a CALL to version 1 account, sub-execution of the version 1 account uses the version 1 virtual machine. +* When a version 1 account issues a CALL to version 0 account, sub-execution of the version 0 account uses the version 0 vritual machine. +* When a version 0 account issues a CREATE, it always uses the newest version of the virtual machine, so it only creates version 1 new accounts. + +## Discussions + +### Performance + +Currently nearly all full node implementations uses config parameters to decide which virtual machine version to use. Switching vitual machine version is simply an operation that changes a pointer using a different set of config parameters. As a result, this scheme has nearly zero impact to performance. + +### Smart Contract Boundary and Formal Verification + +Many current efforts are on-going for getting smart contracts formally verified. However, for any hard fork that introduces new opcodes or change behaviors of existing opcodes would break the verification of an existing contract has previously be formally verified. Using the scheme described here, we define the boundary of how a smart contract interacts with the blockchain and it might help the formal verification efforts: + +* A smart contract has only immutable access to information of blockchain account balances and codes. +* A smart contract has only immutable access of block information. +* A smart contract or a contract creation transaction can modify only its own storage and codes. +* A smart contract can only interact with the blockchain in a mutable way using `CALL` or `CREATE`. + +### WebAssembly + +This scheme can also be helpful when we deploy on-chain WebAssembly virtual machine. In that case, WASM contracts and EVM contracts can co-exist and the execution boundary and interaction model are clearly defined as above. From e8ca710d9f960a4b8d2d68128bea6420b3bea229 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 Jan 2019 00:18:35 +0100 Subject: [PATCH 003/431] Set EIP number --- EIPS/eip-account-versioning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-account-versioning.md b/EIPS/eip-account-versioning.md index bde6b1fc..b995a27d 100644 --- a/EIPS/eip-account-versioning.md +++ b/EIPS/eip-account-versioning.md @@ -1,5 +1,5 @@ --- -eip: x +eip: 1072 title: Generalized Account Versioning Scheme author: Wei Tang (@sorpaas) discussions-to: To be added From 2b4c9825c7d8cecc0885043a3956404cb25414c0 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 Jan 2019 00:19:13 +0100 Subject: [PATCH 004/431] Typo: wrong EIP number --- EIPS/eip-account-versioning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-account-versioning.md b/EIPS/eip-account-versioning.md index b995a27d..e316884a 100644 --- a/EIPS/eip-account-versioning.md +++ b/EIPS/eip-account-versioning.md @@ -1,5 +1,5 @@ --- -eip: 1072 +eip: 1702 title: Generalized Account Versioning Scheme author: Wei Tang (@sorpaas) discussions-to: To be added From 5e2ff1bdd9ce96b96a97b27472475081a785ceb9 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 Jan 2019 00:20:02 +0100 Subject: [PATCH 005/431] Add discussion link --- EIPS/eip-account-versioning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-account-versioning.md b/EIPS/eip-account-versioning.md index e316884a..4402560d 100644 --- a/EIPS/eip-account-versioning.md +++ b/EIPS/eip-account-versioning.md @@ -2,7 +2,7 @@ eip: 1702 title: Generalized Account Versioning Scheme author: Wei Tang (@sorpaas) -discussions-to: To be added +discussions-to: https://github.com/sorpaas/EIPs/issues/2 status: Draft type: Standards Track category: Core From 5369de0db1783f75e8713248f634eb307a506977 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 16 Jan 2019 00:25:27 +0100 Subject: [PATCH 006/431] Rename eip-account-versioning.md to eip-1702.md --- EIPS/{eip-account-versioning.md => eip-1702.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename EIPS/{eip-account-versioning.md => eip-1702.md} (100%) diff --git a/EIPS/eip-account-versioning.md b/EIPS/eip-1702.md similarity index 100% rename from EIPS/eip-account-versioning.md rename to EIPS/eip-1702.md From b545a6d2eed50657b884de7a30990c1930e88e54 Mon Sep 17 00:00:00 2001 From: ligi Date: Thu, 17 Jan 2019 14:34:30 +0100 Subject: [PATCH 007/431] Add link to chainid.network with more chain ID's closes https://github.com/ethereum-lists/chains/issues/9 --- EIPS/eip-155.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EIPS/eip-155.md b/EIPS/eip-155.md index b5f4d3b1..69241b3c 100644 --- a/EIPS/eip-155.md +++ b/EIPS/eip-155.md @@ -68,3 +68,5 @@ This would provide a way to send transactions that work on Ethereum without work | 1337 | Geth private chains (default) | | 6284 | Görli | | 314158 | Stureby | + +Find more chain ID's on [chainid.network](https://chainid.network) and contribute to [ethereum-lists/chains](https://github.com/ethereum-lists/chains). \ No newline at end of file From 31f2f61088072dbceca58e8a383e7264190f2494 Mon Sep 17 00:00:00 2001 From: Junseok Lee Date: Thu, 17 Jan 2019 22:58:12 +0900 Subject: [PATCH 008/431] typo fix in EIP165 --- EIPS/eip-165.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-165.md b/EIPS/eip-165.md index fe22150f..7a30c8b1 100644 --- a/EIPS/eip-165.md +++ b/EIPS/eip-165.md @@ -84,7 +84,7 @@ Implementation note, there are several logical ways to implement this function. ### How to Detect if a Contract Implements ERC-165 -1. The source contact makes a `STATICCALL` to the destination address with input data: `0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000` and gas 30,000. This corresponds to `contract.supportsInterface(0x01ffc9a7)`. +1. The source contract makes a `STATICCALL` to the destination address with input data: `0x01ffc9a701ffc9a700000000000000000000000000000000000000000000000000000000` and gas 30,000. This corresponds to `contract.supportsInterface(0x01ffc9a7)`. 2. If the call fails or return false, the destination contract does not implement ERC-165. 3. If the call returns true, a second call is made with input data `0x01ffc9a7ffffffff00000000000000000000000000000000000000000000000000000000`. 4. If the second call fails or returns true, the destination contract does not implement ERC-165. From 85f0aae1d2ba020f86e1b6211f820323de8f9034 Mon Sep 17 00:00:00 2001 From: Junseok Lee Date: Thu, 17 Jan 2019 23:00:33 +0900 Subject: [PATCH 009/431] typo fix in EIP1167 --- EIPS/eip-1167.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1167.md b/EIPS/eip-1167.md index d0a189ce..e0b39ad6 100644 --- a/EIPS/eip-1167.md +++ b/EIPS/eip-1167.md @@ -25,7 +25,7 @@ This standard supports use-cases wherein it is desireable to clone exact contrac ## Specification -The exact bytecode of the standard clone contract is this: `363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3` wherein the bytes at idices 10 - 29 (inclusive) are replaced with the 20 byte address of the master functionality contract. +The exact bytecode of the standard clone contract is this: `363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3` wherein the bytes at indices 10 - 29 (inclusive) are replaced with the 20 byte address of the master functionality contract. A reference implementation of this can be found at the [optionality/clone-factory](https://github.com/optionality/clone-factory) github repo. From 7ff054d956964d38e28958b0952b04102ca6b76c Mon Sep 17 00:00:00 2001 From: Bitgamma Date: Wed, 30 Jan 2019 11:00:40 +0300 Subject: [PATCH 010/431] Automatically merged updates to draft EIP(s) 1581 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1581.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1581.md b/EIPS/eip-1581.md index 89c3eac8..e49d8e76 100644 --- a/EIPS/eip-1581.md +++ b/EIPS/eip-1581.md @@ -21,7 +21,7 @@ Applications interacting with the blockchain often make use of additional, non-b ## Specification ### Path levels -We define the following 5 levels in BIP32 path: +We define the following levels in BIP32 path: ```m / purpose' / coin_type' / subpurpose' / key_type' / key_index``` @@ -35,15 +35,15 @@ This part is constant and set to ```m / 43' / 60' / 1581'```, meaning BIP 43 -> All subtrees under this prefix are the scope of this EIP. ### Key type -Describes the purpose for which the key is being used. Key types should be generic. "Instant messaging" is a good example whereas "Whisper" is not. The reason is that you want to be able to use the same identity across different services. Key types are defined at: +Describes the purpose for which the key is being used. Key types should be generic. "Instant messaging" is a good example whereas "Whisper" is not. The reason is that you want to be able to use the same identity across different services. Key types are defined at: TBD Hardened derivation is used at this level. ### Key index -Keys are numbered from index 0 in sequentially increasing manner. -This number is used as child index in BIP32 derivation. +The key index is a field of variable length identifying a specific key. In its simplest case, it is a number from 0 to 2^31-1. If a larger identifier is desired (for example representing a hash or a GUID), the value must be split +across several BIP32 nesting levels, most significant bit first and left aligned, bit-padded with 0s if needed. All levels, except the last one must used hardened key derivation. The last level must use public derivation. This means that every level can carry 31-bit of the identifier to represent. -Public derivation is used at this level. +As an example, let's assume we have a key with key type 4' and a key_index representing a 62-bit ID represented as hexadecimal 0x2BCDEFFEDCBAABCD the complete keypath would be ```m / 43' / 60' / 1581' / 4' / ‭1469833213‬' / ‭1555737549‬ ```. If you are using random identifiers, it might be convenient to generate a conventional GUID, for example 128-bit just fix the value of the most significant bit of each 32-bit word to 1 for all of them, except the last one which will be 0. ## Rationale The structure proposed above follows the BIP43 generic structure and is similar to the widely adopted BIP44 specification. From ce01fd026c6fb3ed0eb5b4e7ebee8057a1a70354 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 30 Jan 2019 23:42:10 -0500 Subject: [PATCH 011/431] Use preferred reference format --- EIPS/eip-609.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/EIPS/eip-609.md b/EIPS/eip-609.md index 94a708c4..203ae6fc 100644 --- a/EIPS/eip-609.md +++ b/EIPS/eip-609.md @@ -20,15 +20,15 @@ This specifies the changes included in the hard fork named Byzantium. - Block >= 4,370,000 on Mainnet - Block >= 1,700,000 on Ropsten testnet - Included EIPs: - - [EIP 100](./eip-100.md) (Change difficulty adjustment to target mean block time including uncles) - - [EIP 140](./eip-140.md) (REVERT instruction in the Ethereum Virtual Machine) - - [EIP 196](./eip-196.md) (Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128) - - [EIP 197](./eip-197.md) (Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128) - - [EIP 198](./eip-198.md) (Precompiled contract for bigint modular exponentiation) - - [EIP 211](./eip-211.md) (New opcodes: RETURNDATASIZE and RETURNDATACOPY) - - [EIP 214](./eip-214.md) (New opcode STATICCALL) - - [EIP 649](./eip-649.md) (Difficulty Bomb Delay and Block Reward Reduction) - - [EIP 658](./eip-658.md) (Embedding transaction status code in receipts) + - [EIP 100](https://eips.ethereum.org/EIPS/eip-100) (Change difficulty adjustment to target mean block time including uncles) + - [EIP 140](https://eips.ethereum.org/EIPS/eip-140) (REVERT instruction in the Ethereum Virtual Machine) + - [EIP 196](https://eips.ethereum.org/EIPS/eip-196) (Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128) + - [EIP 197](https://eips.ethereum.org/EIPS/eip-197) (Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128) + - [EIP 198](https://eips.ethereum.org/EIPS/eip-198) (Precompiled contract for bigint modular exponentiation) + - [EIP 211](https://eips.ethereum.org/EIPS/eip-211) (New opcodes: RETURNDATASIZE and RETURNDATACOPY) + - [EIP 214](https://eips.ethereum.org/EIPS/eip-214) (New opcode STATICCALL) + - [EIP 649](https://eips.ethereum.org/EIPS/eip-649) (Difficulty Bomb Delay and Block Reward Reduction) + - [EIP 658](https://eips.ethereum.org/EIPS/eip-658) (Embedding transaction status code in receipts) ## References From 7e7fe3c19d8e918ead3ea871ad1da8e75e6a3543 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 30 Jan 2019 23:43:44 -0500 Subject: [PATCH 012/431] Update to use preferred citation format --- EIPS/eip-1013.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1013.md b/EIPS/eip-1013.md index 2aa87d14..18c74d1b 100644 --- a/EIPS/eip-1013.md +++ b/EIPS/eip-1013.md @@ -20,11 +20,11 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Cons - Block >= TBD on the Ethereum mainnet - Block >= 4,230,000 on the Ropsten testnet - Included EIPs: - - [EIP 145](./eip-145.md): Bitwise shifting instructions in EVM - - [EIP 1014](./eip-1014.md): Skinny CREATE2 - - [EIP 1052](./eip-1052.md): EXTCODEHASH Opcode - - [EIP 1234](./eip-1234.md): Delay difficulty bomb, adjust block reward - - [EIP 1283](./eip-1283.md): Net gas metering for SSTORE without dirty maps + - [EIP 145](https://eips.ethereum.org/EIPS/eip-145): Bitwise shifting instructions in EVM + - [EIP 1014](https://eips.ethereum.org/EIPS/eip-1014): Skinny CREATE2 + - [EIP 1052](https://eips.ethereum.org/EIPS/eip-1052): EXTCODEHASH Opcode + - [EIP 1234](https://eips.ethereum.org/EIPS/eip-1234): Delay difficulty bomb, adjust block reward + - [EIP 1283](https://eips.ethereum.org/EIPS/eip-1283): Net gas metering for SSTORE without dirty maps ## References From f27695249c070496e91efdddf7a29a4b423ced8a Mon Sep 17 00:00:00 2001 From: Witek Date: Thu, 31 Jan 2019 12:59:50 -0800 Subject: [PATCH 013/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 262 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 247 insertions(+), 15 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 80847afb..ae372b93 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -16,7 +16,7 @@ A standard interface for contracts that manage multiple token types. A single de ## Abstract -This standard outlines a smart contract interface where one can represent any number of Fungible and Non-Fungible token types in a single contract. Existing standards such as ERC-20 require deployment of separate contracts per token type. The ERC-721 standard's Token ID is a single non-fungible index and the group of these non-fungibles is deployed as a single contract with settings for the entire collection. In contrast, the ERC-1155 Multi Token Standard allows for each Token ID to represent a new configurable token type, which may have its own metadata, supply and other attributes. +This standard outlines a smart contract interface that can represent any number of Fungible and Non-Fungible token types. Existing standards such as ERC-20 require deployment of separate contracts per token type. The ERC-721 standard's Token ID is a single non-fungible index and the group of these non-fungibles is deployed as a single contract with settings for the entire collection. In contrast, the ERC-1155 Multi Token Standard allows for each Token ID to represent a new configurable token type, which may have its own metadata, supply and other attributes. The `_id` parameter is contained in each function's parameters and indicates a specific token or token type in a transaction. @@ -184,7 +184,7 @@ interface ERC1155TokenReceiver { ## Metadata -The URI value allows for ID substitution by clients. If the string `%s` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/%s.json` would be replaced with `https://token-cdn-domain/780000000000001e000000000000000000000000000000000000000000000000.json` if the client is referring to token ID `780000000000001e000000000000000000000000000000000000000000000000`. +The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/780000000000001e000000000000000000000000000000000000000000000000.json` if the client is referring to token ID `780000000000001e000000000000000000000000000000000000000000000000`. The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix. @@ -213,7 +213,7 @@ interface ERC1155Metadata_URI { ### ERC-1155 Metadata URI JSON Schema -This JSON schema is loosely based on the "ERC721 Metadata JSON Schema", but includes optional formatting to allow for ID substitution by clients. If the string `%s` exists in any JSON value, it MUST be replaced with the actual token ID, by all client software that follows this standard. +This JSON schema is loosely based on the "ERC721 Metadata JSON Schema", but includes optional formatting to allow for ID substitution by clients. If the string `{id}` exists in any JSON value, it MUST be replaced with the actual token ID, by all client software that follows this standard. The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix. @@ -252,7 +252,7 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo { "name": "Asset Name", "description": "Lorem ipsum...", - "image": "https:\/\/s3.amazonaws.com\/your-bucket\/images\/%s.png", + "image": "https:\/\/s3.amazonaws.com\/your-bucket\/images\/{id}.png", "properties": { "simple_property": "example value", "rich_property": { @@ -275,6 +275,226 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo } ``` +
+Localization + +#### Localization + +Metadata localization should be standardized to increase presentation uniformity accross all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. + +#### JSON Schema + +```json +{ + "title": "Token Metadata", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Identifies the asset to which this token represents", + }, + "decimals": { + "type": "integer", + "description": "The number of decimal places that the token amount should display - e.g. 18, means to divide the token amount by 1000000000000000000 to get its user representation.", + }, + "description": { + "type": "string", + "description": "Describes the asset to which this token represents", + }, + "image": { + "type": "string", + "description": "A URI pointing to a resource with mime type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive.", + }, + "properties": { + "type": "object", + "description": "Arbitrary properties. Values may be strings, numbers, object or arrays.", + }, + "localization": { + "type": "object", + "required": ["uri", "default", "locales"], + "properties": { + "uri": { + "type": "string", + "description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request." + }, + "default": { + "type": "string", + "description": "The locale of the default data within the base JSON" + }, + "locales": { + "type": "array", + "description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)." + } + } + }, + } +} +``` + +#### Localized Sample + +Base URI: +```json +{ + "name": "Advertising Space", + "description": "Each token represents a unique Ad space in the city.", + "localization": { + "uri": "ipfs://QmWS1VAdMD353A6SDk9wNyvkT14kyCiZrNDYAad4w1tKqT/{locale}.json", + "default": "en", + "locales": ["en", "es", "fr"] + } +} +``` + +es.json: +```json +{ + "name": "Espacio Publicitario", + "description": "Cada token representa un espacio publicitario único en la ciudad." +} +``` + +fr.json: +```json +{ + "name": "Espace Publicitaire", + "description": "Chaque jeton représente un espace publicitaire unique dans la ville." +} +``` + +
+ +## Approval + +The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval on a subset of tokens, standardized scoped approval is available as an extension. More complex approval schemes will require the use of an external contract enforcing custom rules. + +### Scoped Approval Extension + +This extension enables restrictions on approval's reach using a standardized method. When considering a smart contract +managing tokens from multiple different domains, it makes sense to limit approvals to those domains. Scoped approval is a +generalization of this idea. ERC-1155 implementors can define scopes as needed. + +
+Interface + +```solidity +pragma solidity ^0.5.2; + +/** + Note: The ERC-165 identifier for this interface is 0x30168307. +*/ +interface ERC1155ScopedApproval { + /** + @dev MUST emit when approval changes for scope. + */ + event ApprovalForScope(address indexed _owner, address indexed _operator, bytes32 indexed _scope, bool _approved); + + /** + @dev MUST emit when the token IDs are added to the scope. + By default, IDs are in no scope. + The range is inclusive: _idStart, _idEnd, and all IDs in between have been added to the scope. + _idStart must be lower than or equal to _idEnd. + */ + event AddIdsToScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); + + /** + @dev MUST emit when the token IDs are removed from the scope. + The range is inclusive: _idStart, _idEnd, and all IDs in between have been removed from the scope. + _idStart must be lower than or equal to _idEnd. + */ + event RemoveIdsFromScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); + + /** @dev MUST emit when a scope URI is set or changes. + URIs are defined in RFC 3986. + The URI MUST point a JSON file that conforms to the "Scope Metadata JSON Schema". + */ + event ScopeURI(string _value, bytes32 indexed _scope); + + /** + @notice Returns the number of scopes that contain _id. + @param _id The token ID + @return The number of scopes containing the ID + */ + function scopeCountForId(uint256 _id) public view returns (uint32); + + /** + @notice Returns a scope that contains _id. + @param _id The token ID + @param _scopeIndex The scope index to query (valid values are 0 to scopeCountForId(_id)-1) + @return The Nth scope containing the ID + */ + function scopeForId(uint256 _id, uint32 _scopeIndex) public view returns (bytes32); + + /** + @notice Returns a URI that can be queried to get scope metadata. This URI should return a JSON document containing, at least the scope name and description. Although supplying a URI for every scope is recommended, returning an empty string "" is accepted for scopes without a URI. + @param _scope The queried scope + @return The URI describing this scope. + */ + function scopeUri(bytes32 _scope) public view returns (string memory); + + /** + @notice Enable or disable approval for a third party ("operator") to manage the caller's tokens in the specified scope. + @dev MUST emit the ApprovalForScope event on success. + @param _operator Address to add to the set of authorized operators + @param _scope Approval scope (can be identified by calling scopeForId) + @param _approved True if the operator is approved, false to revoke approval + */ + function setApprovalForScope(address _operator, bytes32 _scope, bool _approved) external; + + /** + @notice Queries the approval status of an operator for a given owner, within the specified scope. + @param _owner The owner of the Tokens + @param _operator Address of authorized operator + @param _scope Scope to test for approval (can be identified by calling scopeForId) + @return True if the operator is approved, false otherwise + */ + function isApprovedForScope(address _owner, address _operator, bytes32 _scope) public view returns (bool); +} +``` +
+ +
+Scope Metadata JSON Schema + +This shema is similar to the token metadata schema and also allows localization. `{id}` and `{locale}` should be replaced with the proper values. + +```json +{ + "title": "Scope Metadata", + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Identifies the scope in a human-readable way.", + }, + "description": { + "type": "string", + "description": "Describes the scope to allow users to make informed approval decisions.", + }, + "localization": { + "type": "object", + "required": ["uri", "default", "locales"], + "properties": { + "uri": { + "type": "string", + "description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request." + }, + "default": { + "type": "string", + "description": "The locale of the default data within the base JSON" + }, + "locales": { + "type": "array", + "description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)." + } + } + } + } +} +``` +
+ ## Rationale
@@ -319,6 +539,28 @@ As the Ethereum ecosystem continues to grow, many dapps are relying on tradition
+
+ +Approval + +### Approval + +The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It +enables frictionless interaction with exchange and trade contracts. However, it may be desired to restrict approval in +some applications. Restricted approval can prevent losses in cases where users do not audit the contracts they're +approving. No standard API is supplied to manage scopes as this is implementation specific. Some implementations may +opt to offer a fixed number of scopes, or assign a specific set of scopes to certain types. Other implementations may +open up scope configuration to its users and offer methods to create scopes and assign IDs to them. + +Sample use cases for scopes: + +* A company may represent it's fleet of vehicles on the blockchain and it could create a scope for each regional office. +* Game developers could share an ERC-1155 contract where each developer manages tokens under a specified scope. +* Tokens of different value magnitude could be split in separate scopes. 0.01Ξ tokens would be kept separate from +10,000.00Ξ tokens. + +
+ ## Usage This standard can be used to represent multiple token types for an entire domain. Both Fungible and Non-Fungible tokens can be stored in the same smart-contract. @@ -339,16 +581,6 @@ The `balanceOfBatch` function allows clients to retrieve balances of multiple ow -
- -Approval - -### Approval - -The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. Single-token based approval of specific token values is not part of the standard. To scope an approval to a specific set or quantity of tokens, we recommend deploying a contract that contains the desired rules, and directing end-users to approve this contract to manage their set of tokens. - -
-
Enumeration @@ -407,4 +639,4 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok - [Beyond Gaming - Exploring the Utility of ERC-1155 Token Standard!](https://blockgeeks.com/erc-1155-token/) ## Copyright -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file From daaae10e24733fb85ae56db9eda38ddfa22a3a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 6 Feb 2019 12:27:44 +0100 Subject: [PATCH 014/431] EIP-1355: Fix authors list --- EIPS/eip-1355.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1355.md b/EIPS/eip-1355.md index 94197b68..3dbd4df3 100644 --- a/EIPS/eip-1355.md +++ b/EIPS/eip-1355.md @@ -1,7 +1,7 @@ --- eip: 1355 title: Ethash 1a -author: Paweł Bylica , Jean M. Cyr [@jean-m-cyr](https://github.com/jean-m-cyr) +author: Paweł Bylica (@chfast) , Jean M. Cyr (@jean-m-cyr) discussions-to: https://ethereum-magicians.org/t/eip-1355-ethash-1a/1167 status: Draft type: Standards Track From b101fb7932d6006122e0086184586e3a6c65be3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 6 Feb 2019 12:32:06 +0100 Subject: [PATCH 015/431] EIP-1: Fix typo --- EIPS/eip-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index d29e18ad..37fa84b0 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -67,7 +67,7 @@ Other exceptional statuses include: * **Deferred** -- This is for core EIPs that have been put off for a future hard fork. * **Rejected** -- An EIP that is fundamentally broken or a Core EIP that was rejected by the Core Devs and will not be implemented. -* **Active** -- This is similar to Final, but denotes an EIP which which may be updated without changing its EIP number. +* **Active** -- This is similar to Final, but denotes an EIP which may be updated without changing its EIP number. * **Superseded** -- An EIP which was previously final but is no longer considered state-of-the-art. Another EIP will be in Final status and reference the Superseded EIP. ## What belongs in a successful EIP? From b9d464a122d6f2eca4234c813adce9bcc9ff1338 Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Wed, 6 Feb 2019 03:37:11 -0800 Subject: [PATCH 016/431] Automatically merged updates to draft EIP(s) 1193 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1193.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1193.md b/EIPS/eip-1193.md index f6cf3952..86234f3c 100644 --- a/EIPS/eip-1193.md +++ b/EIPS/eip-1193.md @@ -101,11 +101,13 @@ ethereum.on('accountsChanged', listener: (accounts: Array) => void): thi The event emits with `accounts`, an array of the accounts' addresses. -### Constructor +### isEIP1193 + +`isEIP1193` is a public read-only value on the provider to help distinguish itself. ```js -ethereum.constructor.name; -> 'EthereumProvider' +ethereum.isEIP1193; +> true ``` ## Examples @@ -242,6 +244,8 @@ The `eth_requestAccounts` method **MUST** resolve with an array of the account(s ### Events +The provider **SHOULD** extend from `EventEmitter` to provide dapps flexibility in listening to events. In place of full `EventEmitter` functionality, the provider **MAY** provide as many methods as it can reasonably provide, but **MUST** provide at least `on`, `emit`, and `removeListener`. + #### notification All subscriptions received from the node **MUST** emit the `message.params` to the eventName `notification` without modification. @@ -262,9 +266,9 @@ If the network the provider is connected to changes, the provider **MUST** emit If the accounts connected to the Ethereum Provider change at any time, the Ethereum Provider **MUST** send an event with the name `accountsChanged` with args `accounts: Array` containing the accounts' addresses. -### Class +### isEIP1193 -The name of the constructor of the Ethereum Provider **MUST** be `EthereumProvider`. +The provider **MUST** define `public readonly ethereum.isEIP1193: Boolean` ### web3.js Backwards Compatibility @@ -303,6 +307,10 @@ class EthereumProvider extends EventEmitter { window.addEventListener('message', this._handleJsonrpcMessage.bind(this)); } + static get isEIP1193() { + return true; + } + /* Methods */ send(method, params = []) { From 8f0c60c3699c43908c2304619b18884bf0c59e25 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Sun, 10 Feb 2019 16:38:09 -0800 Subject: [PATCH 017/431] Move EIP-1066 to Last Call (#1735) --- EIPS/eip-1066.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1066.md b/EIPS/eip-1066.md index 75ec6af4..dc3b326d 100644 --- a/EIPS/eip-1066.md +++ b/EIPS/eip-1066.md @@ -3,7 +3,7 @@ eip: 1066 title: Status Codes author: Brooklyn Zelenka (@expede), Tom Carchrae (@carchrae), Gleb Naumenko (@naumenkogs) discussions-to: https://ethereum-magicians.org/t/erc-1066-ethereum-status-codes-esc/ -status: Draft +status: Last Call type: Standards Track category: ERC created: 2018-05-05 @@ -229,7 +229,7 @@ Special token and financial concepts. Many related concepts are included in othe | `0x5C` | [reserved] | | `0x5D` | [reserved] | | `0x5E` | [reserved] | -| `0x5F` | Token or Fiunancial Information | +| `0x5F` | Token or Financial Information | #### `0x6*` TBD @@ -351,7 +351,7 @@ Among other things, the meta code `0xFF` may be used to describe what the off-ch | `0x*C` | `0x0C` [reserved] | `0x1C` [reserved] | `0x2C` [reserved] | `0x3C` [reserved] | `0x4C` [reserved] | `0x5C` [reserved] | `0x6C` [reserved] | `0x7C` [reserved] | `0x8C` [reserved] | `0x9C` [reserved] | `0xAC` [reserved] | `0xBC` [reserved] | `0xCC` [reserved] | `0xDC` [reserved] | `0xEC` [reserved] | `0xFC` [reserved] | | `0x*D` | `0x0D` [reserved] | `0x1D` [reserved] | `0x2D` [reserved] | `0x3D` [reserved] | `0x4D` [reserved] | `0x5D` [reserved] | `0x6D` [reserved] | `0x7D` [reserved] | `0x8D` [reserved] | `0x9D` [reserved] | `0xAD` [reserved] | `0xBD` [reserved] | `0xCD` [reserved] | `0xDD` [reserved] | `0xED` [reserved] | `0xFD` [reserved] | | `0x*E` | `0x0E` [reserved] | `0x1E` [reserved] | `0x2E` [reserved] | `0x3E` [reserved] | `0x4E` [reserved] | `0x5E` [reserved] | `0x6E` [reserved] | `0x7E` [reserved] | `0x8E` [reserved] | `0x9E` [reserved] | `0xAE` [reserved] | `0xBE` [reserved] | `0xCE` [reserved] | `0xDE` [reserved] | `0xEE` [reserved] | `0xFE` [reserved] | -| `0x*F` | `0x0F` Informational or Metadata | `0x1F` Permission Details or Control Conditions | `0x2F` Matching Meta or Info | `0x3F` Negotiation Rules or Participation Info | `0x4F` Availability Rules or Info (ex. time since or until) | `0x5F` Token or Fiunancial Information | `0x6F` [reserved] | `0x7F` [reserved] | `0x8F` [reserved] | `0x9F` [reserved] | `0xAF` App-Specific Meta or Info | `0xBF` [reserved] | `0xCF` [reserved] | `0xDF` [reserved] | `0xEF` Cryptography, ID, or Proof Metadata | `0xFF` Off-Chain Info or Meta | +| `0x*F` | `0x0F` Informational or Metadata | `0x1F` Permission Details or Control Conditions | `0x2F` Matching Meta or Info | `0x3F` Negotiation Rules or Participation Info | `0x4F` Availability Rules or Info (ex. time since or until) | `0x5F` Token or Financial Information | `0x6F` [reserved] | `0x7F` [reserved] | `0x8F` [reserved] | `0x9F` [reserved] | `0xAF` App-Specific Meta or Info | `0xBF` [reserved] | `0xCF` [reserved] | `0xDF` [reserved] | `0xEF` Cryptography, ID, or Proof Metadata | `0xFF` Off-Chain Info or Meta | ### Example Function Change From a97dc434930d0ccc4461c97d8c7a920dc585adf2 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Mon, 11 Feb 2019 09:02:08 -0800 Subject: [PATCH 018/431] Automatically merged updates to draft EIP(s) 1066 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1066.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1066.md b/EIPS/eip-1066.md index dc3b326d..d7df61af 100644 --- a/EIPS/eip-1066.md +++ b/EIPS/eip-1066.md @@ -6,6 +6,7 @@ discussions-to: https://ethereum-magicians.org/t/erc-1066-ethereum-status-codes- status: Last Call type: Standards Track category: ERC +review-period-end: 2019-02-25 created: 2018-05-05 version: 1.0.0 --- From 9ab3f596c221e89e459c8b4cc2e9dc60f80bd9f1 Mon Sep 17 00:00:00 2001 From: thec00n Date: Thu, 14 Feb 2019 15:51:04 +0700 Subject: [PATCH 019/431] Automatically merged updates to draft EIP(s) 1470 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1470.md | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/EIPS/eip-1470.md b/EIPS/eip-1470.md index c5ea013b..bda13e61 100644 --- a/EIPS/eip-1470.md +++ b/EIPS/eip-1470.md @@ -68,24 +68,37 @@ Test cases include crafted as well as real-world samples of vulnerable smart con 1. Source code of a smart contract sample; e.g. Solidity, Vyper, etc. 2. Compiled asset from an EVM compiler in machine readable format; e.g. JSON or ethPM. -3. Test result configuration that describes which and how many instances of a weakness variant can be found in a given sample. The YAML schema for the proposed test result configuration is listed below. +3. Test result configuration that describes which and how many instances of a weakness variant can be found in a given sample. The YAML schema for the proposed test case configuration is listed below. ```YAML -description: - type: string - required: true -issues: -- id: +title: SWC config +type: object +required: +- description +- issues +properties: + description: type: string - required: true - count: - type: number - required: true - locations: - - bytecode_offsets: - - type: number - line_numbers: - - type: number + issues: + title: Issues + type: array + items: + title: Issue + type: object + required: + - id + - count + properties: + id: + type: string + count: + type: number + locations: + items: + bytecode_offsets: + type: object + line_numbers: + type: object ``` ## Implementation From 3c568e2e77e4c6d0ae517b20668c59b9cebd40f5 Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Mon, 18 Feb 2019 22:49:35 -0700 Subject: [PATCH 020/431] Update eip-615.md --- EIPS/eip-615.md | 301 ++++++++++++++++++++++++++++-------------------- 1 file changed, 175 insertions(+), 126 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 45216921..b809ff92 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,122 +4,134 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Paweł Bylica, Christian Reitwiessner +author: Greg Colvin , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth), Brooklyn Zelenka (@expede) created: 2016-12-10 -edited: 2017-25-4 +edited: 2019-18-2 --- +## Simple Summary + +This EIP introduces new EVM opcodes and conditions on EVM code to support subroutines and static jumps, deprecates dynamic jumps, and thereby make EVM code amenable to linear-time static analysis. This will provide for better compilation, interpretation, transpilation, and formal analysis of EVM code. + ## Abstract -This EIP introduces new EVM opcodes and conditions on EVM code to support subroutines and static jumps, disallow dynamic jumps, and thereby make EVM code amenable to linear-time static analysis. This will provide for better compilation, interpretation, transpilation, and formal analysis of EVM code. +EVM code is currently difficult to statically analyze, hobbling a critical tool for preventing the many expensive bugs our blockchain has experienced. Futher, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to meet the network's long-term demands. This proposal identifies a major reason for these issues, and proposes changes to the EVM specification to address the problem, making futher efforts towards a safer and more performant the EVM possible. -## MOTIVATION +In particular, it imposes restrictions on EVM code and proposes new instructions to help provide for -All current implementations of the Ethereum Virtual Machine, including the just-in-time compilers, are much too slow. This proposal identifies a major reason for this and proposes changes to the EVM specification to address the problem. +* Better static analysis tools +* Much easier formalization +* Faster interpretation +* Near-linear-time compilation to native code, and to and from eWasm +* Easier code generation from other languages, including + * Solidity + * LLVM IR and thus many languages, incuding + * C, C++, Fortran, Haskell, Java, Ruby and Rust. -In particular, it imposes restrictions on current EVM code and proposes new instructions to help provide for -* better-optimized compilation to native code -* faster interpretation -* faster transpilation to eWASM -* better compilation from other languages, - including eWASM and Solidity -* better formal analysis tools +These goals are achieved by: -These goals are achieved by -* disallowing dynamic jumps -* introducing subroutines - jumps with return support -* disallowing pathological control flow and uses of the stack +* Deprecating dynamic jumps +* Introducing subroutines—jumps with return support +* Disallowing pathological control flow and uses of the stack -We also propose to validate - in linear time - that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. And well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. +We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. And well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. -## THE PROBLEM +## Motivation -Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since every jump can potentially be to any jump destination in the code, the number of possible paths through the code goes up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. But absent dynamic jumps code can be statically analyzed in linear time. +Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since every jump can potentially be to any jump destination in the code, the number of possible paths through the code goes up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at validation time, further inhibiting static and formal analyses. But absent dynamic jumps code can be statically analyzed in linear time. -Static analysis includes validation, and much of optimization, compilation, transpilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. In particular, faster control-flow analysis means faster compilation of EVM code to native code, and better data-flow analysis can help the compiler and the interpreter better track the size of the values on the stack and use native 64- and 32-bit operations when possible. Also, conditions which are checked at validation time don’t have to be checked repeatedly at runtime. +Static analysis includes validation, and much of optimization, compilation, transpilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. In particular, linear-time control-flow analysis means near-linear-time compilation of EVM code, and better data-flow analysis can help the compiler and the interpreter better track the size of the values on the stack and use native 64- and 32-bit operations when possible. Gas metering optimization also becomes much more tractable. Additionally, conditions which are statically checked at validation time don’t have to be checked repeatedly at runtime. -Note that analyses of a contract’s bytecode before execution - such as optimizations performed before interpretation, JIT compilation, and on-the-fly machine code generation - must be efficient and linear-time. Otherwise, specially crafted contracts can be used as attack vectors against clients that use static analysis of EVM code before the creation or execution of contracts. +Note that analyses of a contract’s bytecode before execution—such as optimizations performed before interpretation, compilation, and on-the-fly machine code generation—must be efficient and linear-time. Otherwise, specially crafted contracts can be used as attack vectors against clients that use static analysis of EVM code before the creation or execution of contracts. -## PROPOSAL +## Specification -We propose to deprecate two existing instructions - `JUMP` and `JUMPI`. They take their argument on the stack, which means that unless the value is constant they can jump to any `JUMPDEST`. (In simple cases like `PUSH 0 JUMP` the value on the stack can be known to be constant, but in general it's difficult.) We must nonetheless continue to support them in old code. +### Proposal + +We propose to deprecate two existing instructions—`JUMP` and `JUMPI`. They take their argument on the stack, which means that unless the value is constant they can jump to any `JUMPDEST`. (In simple cases like `PUSH 0 JUMP` the value on the stack can be known to be constant, but in general it's difficult.) We must nonetheless continue to support them in old code. Having deprecated `JUMP` and `JUMPI`, we propose new instructions to support their legitimate uses. -### Preliminaries +#### Preliminaries These forms * `INSTRUCTION x,` * `INSTRUCTION x, y` * `INSTRUCTION n, x ...` -name instructions with one, two, and two or more arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. The arguments are laid out as immediate data bytes following the opcode. The size and encoding of immediate data fields is open to change. In particular, easily-parsed variable-length encodings might prove useful for bytecode offsets - which are in practice small but in principle can be large. +name instructions with one, two, and two or more arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) -### Primitives +#### Primitives -The two most important uses of `JUMP` and `JUMPI` are static jumps and return jumps. Conditional and unconditional static jumps are the mainstay of control flow. Return jumps are implemented as a dynamic jump to a return address pushed on the stack. With the combination of a static jump and a dynamic return jump you can - and Solidity does - implement subroutines. The problem is that static analysis cannot tell the one place the return jump is going, so it must analyze every possibility. +The two most important uses of `JUMP` and `JUMPI` are static jumps and return jumps. Conditional and unconditional static jumps are the mainstay of control flow. Return jumps are implemented as a dynamic jump to a return address pushed on the stack. With the combination of a static jump and a dynamic return jump you can—and Solidity does—implement subroutines. The problem is that static analysis cannot tell the one place the return jump is going, so it must analyze every possibility (a heavy analysis). Static jumps are provided by * `JUMPTO jump_target` * `JUMPIF jump_target` -which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target`, given as four immediate bytes, rather than an address on the stack. +which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target` rather than an address on the stack. To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Brief descriptions follow, and full semantics are given below. * `BEGINSUB n_args, n_results` -marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. `n_args` and `n_results` are given as one immediate byte each. The bytecode for a subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode. +marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. The subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode. * `JUMPSUB jump_target` -jumps to an immediate subroutine address, given as four immediate bytes. +jumps to an immediate subroutine address. * `RETURNSUB` returns from the current subroutine to the instruction following the JUMPSUB that entered it. These five simple instructions form the primitives of the proposal. -### Data +#### Data -In order to validate subroutines, EVM bytecode must be sequentially scanned matching jumps to their destinations. Since creation code has to contain the runtime code as data, that code might not correctly validate in the creation context and also does not have to be validated prior to the execution of the creation code. Because of that, there needs to be a way to place data into the bytecode that will be skipped over and not validated. Such data will prove useful for other purposes as well. +In order to validate subroutines in linear time, EVM bytecode must be sequentially scanned matching jumps to their destinations. Since creation code must contain the runtime code as data, that code might not correctly validate in the creation context and also does not have to be validated prior to the execution of the creation code. There needs to be a way to place data into the bytecode that will be skipped over and not validated. Such data may prove useful for other purposes as well. * `BEGINDATA` specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. -### Indirect Jumps +#### Indirect Jumps -The primitive operations provide for static jumps. Dynamic jumps are also used for O(1) indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. +The primitive operations provide for static jumps. Dynamic jumps are also used for ``O(1)`` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. + +Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. -Dynamic jumps to a `JUMPDEST` are used to implement O(1) jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. * `JUMPV n, jumpdest ...` -jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode. If the index is greater than or equal to `n - 1` the last (default) offset is used. `n` is given as four immediate bytes, all `JUMPDEST` offsets as four immediate bytes each. +jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode. If the index is greater than or equal to `n - 1` the last (default) offset is used. + +Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs. -Dynamic jumps to a `BEGINSUB` are used to implement O(1) virtual functions and callbacks, which take just two pointer dereferences on most CPUs. * `JUMPSUBV n, beginsub ...` -jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode, MSB-first. If the index is greater than or equal to `n - 1` the last (default) offset is used. `n` is given as four immediate bytes, the `n` offsets as four immediate bytes each. +jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode, MSB-first. If the index is greater than or equal to `n - 1` the last (default) offset is used. -`JUMPV` and `JUMPSUBV` are not strictly necessary. They provide O(1) operations that can be replaced by O(n) or O(log n) EVM code using static jumps, but that code will be slower, larger and use more gas for things that can and should be fast, small, and cheap, and that are directly supported in WASM with br_table and call_indirect. +`JUMPV` and `JUMPSUBV` are not strictly necessary. They provide `O(1)` operations that can be replaced by `O(n)` or `O(log n)` EVM code using static jumps, but that code will be slower, larger and use more gas for things that can and should be fast, small, and cheap, and that are directly supported in WASM with br_table and call_indirect. -### Variable Access +#### Variable Access These operations provide convenient access to subroutine parameters and other variables at fixed stack offsets within a subroutine. * `PUTLOCAL n` -Pops the top value on the stack and copies it to local variable `n`. - +Pops the top value on the stack and copies it to local variable `n`[^putlocal_n]. +[^putlocal_n]: The `n` of stack items below the frame pointer to put a value at. + * `GETLOCAL n` -Pushes the value of local variable `n` on the EVM stack. +Pushes the value of local variable `n`[^getlocal_n] on the stack. +[^getlocal_n]: The `n` of stack items below the frame pointer to get a value from. -Local variable `n` is `FP[-n]` as defined below. +Local variable `n` is the nth stack item below the frame pointer—`FP[-n]` as defined below. -## SEMANTICS +### Semantics Jumps to and returns from subroutines are described here in terms of -* the EVM data stack, (as defined in the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf) usually just called “the stack”, -* a return stack of `JUMPSUB` and `JUMPSUBV` offsets, and -* a frame stack of frame pointers. +* The EVM data stack, (as defined in the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)) usually just called “the stack.” +* A return stack of `JUMPSUB` and `JUMPSUBV` offsets. +* A frame stack of frame pointers. We will adopt the following conventions to describe the machine state: * The _program counter_ `PC` is (as usual) the byte offset of the currently executing instruction. -* The _stack pointer_ `SP` corresponds to the number of items on the stack - the _stack size_. As a negative offset it addresses the current top of the stack of data values, where new items are pushed. +* The _stack pointer_ `SP` corresponds to the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)'s substate `s` of the machine state. + * The _stack pointer_ addresses the current top of the stack of data values, where new items are pushed. + * The stack grows towards lower addresses. * The _frame pointer_ `FP` is set to `SP + n_args` at entry to the currently executing subroutine. * The _stack items_ between the frame pointer and the current stack pointer are called the _frame_. * The current number of items in the frame, `FP - SP`, is the _frame size_. @@ -128,97 +140,118 @@ Defining the frame pointer so as to include the arguments is unconventional, but The frame pointer and return stacks are internal to the subroutine mechanism, and not directly accessible to the program. This is necessary to prevent the program from modifying its state in ways that could be invalid. -The first instruction of an array of EVM bytecode begins execution of a _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack - `code size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV` - that is, in the _main_ routine - executes a `STOP`.) +The first instruction of an array of EVM bytecode begins execution of a _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack—`code_size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV`—that is, in the _main_ routine—executes a `STOP`.) Execution of a subroutine begins with `JUMPSUB` or `JUMPSUBV`, which -* push `PC` on the return stack, -* push `FP` on the frame stack, -thus suspending execution of the current subroutine, and -* set `FP` to `SP + n_args`, and -* set `PC` to the specified `BEGINSUB` address, -thus beginning execution of the new subroutine. -(The _main_ routine is not addressable by `JUMPSUB` instructions.) + +* pushes `PC` on the return stack, +* pushes `FP` on the frame stack + * thus suspending execution of the current subroutine, +* sets `FP` to `SP + n_args`, and +* sets `PC` to the specified `BEGINSUB` address + * thus beginning execution of the new subroutine + * the _main_ routine is not addressable by `JUMPSUB` instructions Execution of a subroutine is suspended during and resumed after execution of nested subroutines, and ends upon encountering a `RETURNSUB`, which -* sets `FP` to the top of the virtual frame stack and pops the stack, and -* sets `PC` to top of the return stack and pops the stack + +* sets `FP` to the top of the virtual frame stack and pops the stack, +* sets `PC` to top of the return stack and pops the stack, and * advances `PC` to the next instruction + thus resuming execution of the enclosing subroutine or _main_ program. -A `STOP or `RETURN` also ends the execution of a subroutine. +A `STOP` or `RETURN` also ends the execution of a subroutine. -## VALIDITY +For example, after a `JUMPSUB` to a `BEGINSUB 2, 0` like this +``` +PUSH 10 +PUSH 11 +JUMPSUB _beginsub_ +PUSH 12 +PUSH 13 +``` +the stack looks like this +``` +10 <- FP +11 +12 +13 + <- SP +``` -We would like to consider EVM code valid if and only if no execution of the program can lead to an exceptional halting state. But we must and will validate code in linear time. So our validation does not consider the code’s data and computations, only its control flow and stack use. This means we will reject programs with invalid code paths, even if those paths cannot be executed at runtime. Most conditions can be validated, and will not need to be checked at runtime; the exceptions are sufficient gas and sufficient stack. So some false negatives and runtime checks are the price we pay for linear time validation. +### Validity -_Execution_ is as defined in the Yellow Paper - a sequence of changes in the EVM state. The conditions on valid code are preserved by state changes. At runtime, if execution of an instruction would violate a condition the execution is in an exceptional halting state. The yellow paper defines five such states. ->1 Insufficient gas +We would like to consider EVM code valid iff no execution of the program can lead to an exceptional halting state, but we must validate code in linear time. So our validation does not consider the code’s data and computations, only its control flow and stack use. This means we will reject programs with invalid code paths, even if those paths are not reachable. Most conditions can be validated, and will not need to be checked at runtime; the exceptions are sufficient gas and sufficient stack. As such, static analysis may yield false negatives belonging to well-understood classes of code requiring runtime checks. Aside from those cases, we can validate large classes at validation time and with linear complexity. ->2 More than 1024 stack items +_Execution_ is as defined in the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)—a sequence of changes in the EVM state. The conditions on valid code are preserved by state changes. At runtime, if execution of an instruction would violate a condition the execution is in an exceptional halting state. The Yellow Paper defines five such states. +>**1** Insufficient gas ->3 Insufficient stack items +>**2** More than 1024 stack items ->4 Invalid jump destination +>**3** Insufficient stack items ->5 Invalid instruction +>**4** Invalid jump destination -We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. +>**5** Invalid instruction + +We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. To handle the return stack we expand the conditions on stack size: ->2a The size of the data stack does not exceed 1024. +>**2a** The size of the data stack does not exceed 1024. ->2b The size of the return stack does not exceed 1024. +>**2b** The size of the return stack does not exceed 1024. -Given our more detailed description of the data stack we restate condition 3 - stack underflow - as ->3 `SP` must be less than or equal to `FP` +Given our more detailed description of the data stack we restate condition 3—stack underflow—as +>**3** `SP` must be less than or equal to `FP` -Since the various `DUP` and `SWAP` operations are formalized as taking items off the stack and putting them back on, this prevents `DUP` and `SWAP` from accessing data below the frame pointer, since taking too many items off of the stack would mean that `SP` is less than `FP`. +Since the various `DUP` and `SWAP` operations—as well as `PUTLOCAL` and `GETLOCAL`—are defined as taking items off the stack and putting them back on, this prevents them from accessing data below the frame pointer, since taking too many items off of the stack would mean that `SP` is less than `FP`. -To handle the new jump instructions and subroutine boundaries we expand the conditions on jumps and jump destinations. ->4a `JUMPTO`, `JUMPIF`, and `JUMPV` address only `JUMPDEST` instructions. +To handle the new jump instructions and subroutine boundaries, we expand the conditions on jumps and jump destinations. +>**4a** `JUMPTO`, `JUMPIF`, and `JUMPV` address only `JUMPDEST` instructions. ->4b `JUMPSUB` and `JUMPSUBV` address only `BEGINSUB` instructions. +>**4b** `JUMPSUB` and `JUMPSUBV` address only `BEGINSUB` instructions. ->4c `JUMP` instructions do not address instructions outside of the subroutine they occur in. +>**4c** `JUMP` instructions do not address instructions outside of the subroutine they occur in. We have two new conditions on execution to ensure consistent use of the stack by subroutines: ->6 For `JUMPSUB` and `JUMPSUBV` the frame size is at least the `n_args` of the `BEGINSUB`(s) to jump to. +>**6** For `JUMPSUB` and `JUMPSUBV` the frame size is at least the `n_args` of the `BEGINSUB`(s) to jump to. ->7 For `RETURNSUB` the frame size is equal to the `n_results` of the enclosing `BEGINSUB`. +>**7** For `RETURNSUB` the frame size is equal to the `n_results` of the enclosing `BEGINSUB`. Finally, we have one condition that prevents pathological uses of the stack: ->8 For every instruction in the code the frame size is constant. +>**8** For every instruction in the code the frame size is constant. -In practice, we must test at runtime for conditions 1 and 2 - sufficient gas and sufficient stack. We don’t know how much gas there will be, we don’t know how deep a recursion may go, and analysis of stack depth even for non-recursive programs is non-trivial. +In practice, we must test at runtime for conditions 1 and 2—sufficient gas and sufficient stack. We don’t know how much gas there will be, we don’t know how deep a recursion may go, and analysis of stack depth even for non-recursive programs is nontrivial. All of the remaining conditions we validate statically. -## VALIDATION +### Validation Validation comprises two tasks: -* Checking that jump destinations are correct and instructions valid. -* Checking that subroutines satisfy the conditions on control flow and stack use. +* Check that jump destinations are correct and instructions valid. +* Check that subroutines satisfy the conditions on control flow and stack use. -We sketch out these two validation functions in pseudo-C below. To simplify the presentation only the five primitives are handled (`JUMPV` and `JUMPSUBV` would just add more complexity to loop over their vectors), we assume helper functions for extracting instruction arguments from immediate data and managing the stack pointer and program counter, and some optimizations are forgone. +We sketch out these two validation functions in pseudo-C below. To simplify the presentation only the five primitives are handled (`JUMPV` and `JUMPSUBV` would just add more complexity to loop over their vectors), we assume helper functions for extracting instruction arguments from immediate data and managing the stack pointer and program counter, and some optimizations are forgone. -### Validating jumps +#### Validating Jumps -Validating that jumps are to valid addresses takes two sequential passes over the bytecode - one to build sets of jump destinations and subroutine entry points, another to check that addresses jumped to are in the appropriate sets. +Validating that jumps are to valid addresses takes two sequential passes over the bytecode—one to build sets of jump destinations and subroutine entry points, another to check that addresses jumped to are in the appropriate sets. ``` bytecode[code_size] // contains EVM bytecode to validate is_sub[code_size] // is there a BEGINSUB at PC? is_dest[code_size] // is there a JUMPDEST at PC? sub_for_pc[code_size] // which BEGINSUB is PC in? - + bool validate_jumps(PC) { + current_sub = PC + // build sets of BEGINSUBs and JUMPDESTs - current_sub = 0 for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC)) { if instruction is invalid return false if instruction is BEGINDATA - break + break; if instruction is BEGINSUB is_sub[PC] = true current_sub = PC @@ -227,9 +260,8 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_dest[PC] = true sub_for_pc[PC] = current_sub } - + // check that targets are in subroutine - current_sub = 0 for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC)) { if instruction is BEGINDATA @@ -245,16 +277,18 @@ Validating that jumps are to valid addresses takes two sequential passes over th if sub_for_pc[PC] is not current_sub return false } - return true + return true } ``` Note that code like this is already run by EVMs to check dynamic jumps, including building the jump destination set every time a contract is run, and doing a lookup in the jump destination set before every jump. -### Validating subroutines +#### Subroutine Validation -This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is O(n-vertices + n-edges) +This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`[^subroutine_complexity]. -The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. +[^subroutine_complexity]: The sum of the number of edges and number of verticies in the graph. + +The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. ``` bytecode[code_size] // contains EVM bytecode to validate @@ -263,7 +297,8 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t // we validate each subroutine individually, as if at top level // * PC is the offset in the code to start validating at // * return_pc is the top PC on return stack that RETURNSUB returns to - // * at top level FP = 0, so SP is both the frame size and the stack size + // * at top level FP = SP = 0 is both the frame size and the stack size + // * as items are pushed SP get more negative, so the stack size is -SP validate_subroutine(PC, return_pc, SP) { // traverse code sequentially, recurse for jumps @@ -276,31 +311,31 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t { // check for constant frame size if instruction is JUMPDEST - if SP != frame_size[PC] + if -SP != frame_size[PC] return false // return to break cycle return true } - frame_size[PC] = SP + frame_size[PC] = -SP // effect of instruction on stack n_removed = removed_items(instructions) n_added = added_items(instruction) // check for stack underflow - if SP < n_removed + if -SP < n_removed return false // net effect of removing and adding stack items - SP -= n_removed - SP += n_added + SP += n_removed + SP -= n_added // check for stack overflow - if SP > 1024 + if -SP > 1024 return false - if instruction is STOP, RETURN, SUICIDE or BEGINDATA + if instruction is STOP, RETURN, or SUICIDE return true // violates single entry @@ -315,7 +350,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t { // check for enough arguments sub_pc = jump_target(PC) - if SP < n_args(sub_pc) + if -SP < n_args(sub_pc) return false return true } @@ -324,10 +359,10 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t if instruction is JUMPTO { PC = jump_target(PC) - continue + continue } - // recurse to jump to code to validate + // recurse to jump to code to validate if instruction is JUMPIF { if not validate_subroutine(jump_target(PC), return_pc, SP) @@ -339,36 +374,50 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for _i_ equal to t } // check for right number of results - if SP != n_results(return_pc) + if (-SP != n_results(return_pc) return false return true } ``` -### COSTS & CODES +#### Costs & Codes -All of the instructions are O(1) with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell. +All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell. -We tentatively suggest the following opcodes: +We suggest the following opcodes: ``` -0xB0 JUMPTO -0xB1 JUMPIF -0XB2 JUMPSUB -0xB4 JUMPSUBV -0xB5 BEGINSUB -0xB6 BEGINDATA -0xB8 RETURNSUB -0xB9 PUTLOCAL -0xBA GETLOCAL +0xb0 JUMPTO +0xb1 JUMPIF +0xb2 JUMPV +0xb3 JUMPSUB +0xb4 JUMPSUBV +0xb5 BEGINSUB +0xb6 BEGINDATA +0xb7 RETURNSUB +0xb8 PUTLOCAL +0xb9 GETLOCAL ``` -### GETTING THERE FROM HERE +## Backwards Compatibility These changes would need to be implemented in phases at decent intervals: ->1 If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it. +>**1.** If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it. ->2 A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely. +>**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely. -If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new - but without validation. That is, by delaying step 2. Since we must continue to run old code this is not technically difficult. +If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult. -Implementation of this proposal need not be difficult, At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. JIT code can use native calls. Further optimizations include minimizing runtime checks for exceptions and taking advantage of validated code wherever possible. +## Rationale + +This design was highly constrained by the existing EVM semantics, the requirement for eWasm compatibility, and the security demands of the Ethereum environment. It was also informed by the lead author's previous work implementing Java and Scheme interpreters. As such there was very little room for alternative designs. + +As described above, the approach was simply to deprecate the problematic dynamic jumps, then ask what opcodes were necessary to provide for the features they supported. These needed to include those provided by eWasm, which themselves were modeled after typical hardware. The only real innovation was to move the frame pointer and the return pointer to their own stacks, so as to prevent any possibility of overwriting them. (Although Forth also uses a return stack.) This allowed for treating subroutine arguments as local variables, and facilitated the return of multiple values. + +## Implementation + +Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. Compiled code can use native call instructions, greatly improving performance. Further optimizations include minimizing runtime checks for exceptions, condensing gas metering, and otherwise taking advantage of validated code wherever possible. A lightly tested reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) + + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From f15cd4a294791468435f1d8ae4f471cf1aab3216 Mon Sep 17 00:00:00 2001 From: Dror Tirosh Date: Wed, 20 Feb 2019 19:09:48 +0200 Subject: [PATCH 021/431] Automatically merged updates to draft EIP(s) 1613 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1613.md | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/EIPS/eip-1613.md b/EIPS/eip-1613.md index f474f250..0dd558e3 100644 --- a/EIPS/eip-1613.md +++ b/EIPS/eip-1613.md @@ -1,7 +1,7 @@ --- eip: 1613 title: Gas stations network -author: Yoav Weiss , Dror Tirosh +author: Yoav Weiss , Dror Tirosh , Alex Forshtat discussions-to: https://github.com/yoav-tabookey/EIPs/issues/1 status: Draft type: Standards Track @@ -58,7 +58,6 @@ Roles of a `Relay` node: * Maintain a hot wallet with a small amount of ETH, to pay for gas. * Provide a public interface for user apps to send gasless transactions via channels such as https or whisper. * Publish it's public interfaces and its price (as a multiplier of the actual transaction gas cost) in `RelayHub`. -* Help `RelayHub` maintain the list of relays in a trustless way. Relays are incentivized to remove other verifiably-stale relays. * Optionally monitor reverted transactions of other relays through RelayHub, catching offending relays and claiming their stakes. This can be done by anyone, not just a relay. Implementing a `RelayRecipient` contract: @@ -96,19 +95,14 @@ The process of registering/refreshing a `Relay`: * If starting for the first time (no key yet), generate a key pair for Relay's address. * If Relay's address doesn't hold sufficient funds for gas (e.g. because it was just generated), Relay stays inactive until its owner funds it. * Relay's owner funds it. -* Relay sends the required stake to `RelayHub`. -* Relay calls `RelayHub.register_relay(address owner, uint transaction_fee, string[] url, address optional_stale_relay_for_removal)`, with its `owner` (the address that funded it), - the relay's `transaction fee` (as a multiplier on transaction gas cost), and one or more URL for incoming transactions. - The `optional_stale_relay_for_removal` arg is the address of a stale relay found in the list. -* `RelayHub` checks Relay.balance and emits `NeedsFunding(Relay)` to alert the owner if it runs low. +* Relay's owner sends the required stake to `RelayHub` by calling `RelayHub.stake(address relay, uint unstake_delay)`. +* `RelayHub` puts the `owner` and `unstake delay` in the relays map, indexed by `relay` address. +* Relay calls `RelayHub.register_relay(uint transaction_fee, string memory url)` with the relay's `transaction fee` (as a multiplier on transaction gas cost), and a URL for incoming transactions. * `RelayHub` ensures that Relay has a sufficient stake. -* `RelayHub` puts the `owner`, current `timestamp`, `transaction fee`, and `urls`, in the relays map, indexed by `relay` address. -* `RelayHub` emits an event, `RelayAdded(Relay, transaction_fee, relay_stake, urls)`. -* If `optional_stale_relay_for_removal` is in the relays map and is stale (hasn't communicated in a few days), `RelayHub` removes it. - Relay benefits by receiving a gas refund for the freed storage, so it's incentivized to always include a stale relay if there is one. -* Relay starts a timer to perform a `keepalive` transaction after a certain amount of time if no real transactions are relayed through it. - `Relay` is considered stale if it hasn't sent anything to `RelayHub` in a while, e.g. 4 days. -* `Relay` goes to sleep and waits signing requests. +* `RelayHub` puts the `transaction fee` in the relays map. +* `RelayHub` emits an event, `RelayAdded(Relay, owner, transaction_fee, relay_stake, unstake_delay, url)`. +* Relay starts a timer to perform a `keepalive` transaction every 6000 blocks. +* `Relay` goes to sleep and waits for signing requests. The process of sending a relayed transaction: @@ -120,7 +114,8 @@ The process of sending a relayed transaction: * Sender prepares the transaction with Sender's address, the recipient address, the actual transaction data, Relay's transaction fee, gas price, gas limit, its current nonce from `RelayHub.nonces`, RelayHub's address, and Relay's address, and then signs it. * Sender verifies that `RelayHub.balances[recipient]` holds enough ETH to pay Relay's fee. * Sender verifies that `Relay.balance` has enough eth to send the transaction -* Sender sends the signed transaction to Relay's web interface. +* Sender reads the Relay's current `nonce` value and decides on the `max_nonce` parameter. +* Sender sends the signed transaction amd metadata to Relay's web interface. * `Relay` wraps the transaction with a transaction to `RelayHub`, with zero ETH value. * `Relay` signs the wrapper transaction with its key in order to pay for gas. * `Relay` verifies that: @@ -130,12 +125,14 @@ The process of sending a relayed transaction: * The relay address in the transaction matches Relay's address. * The transaction's recipient has enough ETH deposited in `RelayHub` to pay the transaction fee. * Relay has enough ETH to pay for the gas required by the transaction. + * Value of `max_nonce` is higher than current Relay's `nonce` * If any of Relay's checks fail, it returns an error to sender, and doesn't proceed. * Relay submits the signed wrapped transaction to the blockchain. * Relay immediately returns the signed wrapped transaction to the sender. This step is discussed below, in attacks/mitigations. * `Sender` receives the wrapped transaction and verifies that: * It's a valid relay call to `RelayHub`. from Relay's address. * The transaction's ethereum nonce matches Relay's current nonce. + * The transaction's ethereum nonce is lower than or equal to `max_nonce`. * `Relay` is sufficiently funded to pay for it. * The wrapped transaction is valid and signed by `sender`. * Recipient contract has sufficient funds in `RelayHub.balances` to pay for Relay's fee as stated in the transaction. @@ -153,7 +150,6 @@ The process of sending a relayed transaction: * Verifies that the signature of the internal transaction matches its stated origin (sender's key). * Verifies that the relay address written in the transaction matches msg.sender. * Verifies that the transaction's `nonce` matches the stated origin's nonce in `RelayHub.nonces`. - * Checks `Relay.balance` and emits `NeedsFunding(Relay)` to alert the owner if it runs low. * Calls recipient's `accept_relayed_call` function, asking whether it's going to accept the transaction. If not, `RelayHub` reverts. In this case, Relay doesn't get paid, as it was its responsibility to check `RelayHub.can_relay` before releasing the transaction. * Sends the transaction to the recipient. The call is made using `call()`, so reverts won't kill the transaction, just return false. @@ -181,15 +177,6 @@ The process of winding a `Relay` down: * `Relay` shuts down. * Once the owner's unstake delay is over, owner calls `RelayHub.unstake()`, and withdraws the stake. -Removal of stale/invalid relays: - -* During registration/refresh, `Relay` helps purging stale relays. -* `Relay` scans the relays in `RelayHub`, e.g. by going through old `RelayAdded` events. -* `Relay` looks for stale relays (where the latest recorded `timestamp` is a few days ago). -* If `Relay` finds such relay, it passes the stale relay as `optional_relay_removal` during registration. -* `RelayHub` verifies that the reported stale relay is indeed stale or invalid, removes it from the relays map and emits `RelayRemoved(r)`. - The storage refund offsets Relay's registration cost, so `Relay` is incentivized to remove a stale relay whenever if can find one. - ## Rationale The rationale for the gas stations network design is a combination of two sets of requirements: Easy adoption, and robustness. @@ -236,6 +223,13 @@ The sender then proceeds to select a new relay and send the original transaction The result of such attack is a delay of a few blocks in sending the transaction (until the attack is detected) but the relay gets removed and loses its entire stake. Scaling such attack would be prohibitively expensive, and actually quite profitable for senders and honest relays. +##### Attack: Relay attempts to censor a transaction by signing it, but using a nonce higher than it's current nonce. +In this attack, the Relay did create and return a perfectly valid transaction, but it will not be mined until this Relay fills the gap in the nonce with 'missing' transactions. +This may delay the relaying of some transactions indefinately. In order to mitigate that, the sender includes a `max_nonce` parameter with it's signing request. +It is suggested to be higher by 2-3 from current nonce, to allow the relay process several transactions. + +When the sender receives a transaction signed by a Relay he validates that the nonce used is valid, and if it is not, the client will ignore the given relay and use other relays to relay given transaction. Therefore, there will be no actual delay introduced by such attack. + ##### Attack: Dapp attempts to burn relays funds by implementing an inconsistent accept_relayed_call() and using multiple sender addresses to generate expensive transactions, thus performing a DoS attack on relays and reducing their profitability. In this attack, a contract sets an inconsistent accept_relayed_call (e.g. return zero for even blocks, nonzero for odd blocks), and uses it to exhaust relay resources through unpaid transactions. Relays can easily detect it after the fact. @@ -275,9 +269,6 @@ After it caused this minor delay and got blacklisted, the attacker must wait a m Simultaneously bringing up a number of unreliable relays, large enough to cause a noticeable network delay, would be prohibitively expensive due to the required stake, and even then, all those relays will get blacklisted within a short time. -##### Attack: Relay attempts to unregister other relays. -Removal of stale relays is trustless. RelayHub verifies whether the removed relay has performed any action recently, and would revert any transaction that tries to remove an active relay. - ##### Attack: Attacker attempts to replay a relayed transaction. Transactions include a nonce. RelayHub maintains a nonce (counter) for each sender. Transactions with bad nonces get reverted by RelayHub. Each transaction can only be relayed once. From 08af647d6f87c570189a80bc178d565741402f2d Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Thu, 21 Feb 2019 15:51:48 +1300 Subject: [PATCH 022/431] Delete eip-1175.md (#1764) * Delete eip-1175.md * Rename eip-1491.md to EIPS/eip-1491.md --- eip-1491.md => EIPS/eip-1491.md | 0 eip-1175.md | 533 -------------------------------- 2 files changed, 533 deletions(-) rename eip-1491.md => EIPS/eip-1491.md (100%) delete mode 100644 eip-1175.md diff --git a/eip-1491.md b/EIPS/eip-1491.md similarity index 100% rename from eip-1491.md rename to EIPS/eip-1491.md diff --git a/eip-1175.md b/eip-1175.md deleted file mode 100644 index fa8cc102..00000000 --- a/eip-1175.md +++ /dev/null @@ -1,533 +0,0 @@ ---- -eip: 1175 -title: Wallet & shop standard for all tokens (erc20) -author: Jet Lim (@Nitro888) -discussions-to: https://github.com/ethereum/EIPs/issues/1182 -status: Draft -type: Standards Track -category: ERC -created: 2018-06-21 -requires: 20 ---- - -# All tokens go to heaven -## Simple Summary -Make wallets and shops created from certified contracts make erc20 tokens easy to use for commerce. - -![wallet](https://user-images.githubusercontent.com/11692220/41762799-ee17c480-7636-11e8-9930-681be2c59b56.png) - -## Abstract -The mutual trust between the wallet and the shop created by the authenticated contract allows you to pay for and purchase items at a simple process. - -## Motivation -New standards with improvements have been released, but the majority of tokens currently being developed are erc20 tokens. So I felt I needed a proposal to use old tokens in commerce. - To use various erc20 tokens for trading, you need a custom contract. However, a single wallet with a variety of tokens, and a mutually trusted store, can make transactions that are simple and efficient. The erc20 token is traded through two calls, `approve (address _spender, uint256 _value)` and `transferFrom (address _from, address _to, uint256 _value)`, but when using the wallet contract, `paySafe (address _shop, uint256 _item)`will be traded only in one call. -And if you only reuse the store interface, you can also trade using `payUnsafe (address _shop, uint256 _item)`. - -## Specification -![workflow](https://user-images.githubusercontent.com/11692220/41841025-2ed6e024-78a2-11e8-9faf-2b43aeaa2303.png) -## WalletCenter -### Methods -#### createWallet -Create wallet contract and add to list. Returns the address of new wallet. - -``` js -function createWallet() public returns (address _wallet) -``` - -#### isWallet -Returns true or false value for test this address is a created by createWallet. - -``` js -function isWallet(address _wallet) public constant returns (bool) -``` - -#### createShop -Create Shop contract and add to list. Returns the address of new Shop with erc20 token address. - -``` js -function createShop(address _erc20) public returns (address _shop) -``` - -#### isShop -Returns true or false value for test this address is a created by createWallet. - -``` js -function isShop(address _shop) public constant returns (bool) -``` - -### Events -#### Wallet -Search for my wallet. -``` js -event Wallet(address indexed _owner, address indexed _wallet) -``` - -#### Shop -Search for my shop. -``` js -event Shop(address indexed _owner, address indexed _shop, address indexed _erc20) -``` - -## Wallet -Wallet must be created by wallet center. -### Methods -#### balanceOf -Returns the account balance of Wallet. -``` js -function balanceOf(address _erc20) public constant returns (uint256 balance) -``` - -#### withdrawal -withdrawal `_value` amount of `_erc20` token to `_owner`. -``` js -function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) -``` - -#### paySafe -Pay for safe shop (created by contract) item with item index `_item`. -``` js -function paySafe(address _shop, uint256 _item) onlyOwner onlyShop(_shop) public payable returns (bool success) -``` - -#### payUnsafe -Pay for unsafe shop (did not created by contract) item with item index `_item`. -``` js -function payUnsafe(address _shop, uint256 _item) onlyOwner public payable returns (bool success) -``` - -#### payCancel -Cancel pay and refund. (only weekly model) -``` js -function payCancel(address _shop, uint256 _item) onlyOwner public returns (bool success) -``` - -#### refund -Refund from shop with item index `_item`. -``` js -function refund(uint256 _item, uint256 _value) public payable returns (bool success) -``` - -### Events -#### Pay -``` js -event Pay(address indexed _shop, uint256 indexed _item, uint256 indexed _value) -``` - -#### Refund -``` js -event Refund(address indexed _shop, uint256 indexed _item, uint256 indexed _value) -``` - -## Shop -Shop is created by wallet center or not. but Shop that created by wallet center is called safe shop. -### Methods -#### balanceOf -Returns the account balance of Shop. -``` js -function balanceOf(address _erc20) public constant returns (uint256 balance) -``` - -#### withdrawal -withdrawal `_value` amount of `_erc20` token to `_owner`. -``` js -function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) -``` - -#### pay -Pay from buyer with item index `_item`. -``` js -function pay(uint256 _item) onlyWallet(msg.sender) public payable returns (bool success) -``` - -#### refund -refund token to `_to`. -``` js -function refund(address _buyer, uint256 _item, uint256 _value) onlyWallet(_buyer) onlyOwner public payable returns (bool success) -``` - -#### resister -Listing item for sell. -``` js -function resister(uint8 _category, uint256 _price, uint256 _stock) onlyOwner public returns (uint256 _itemId) -``` - -#### update -Update item state for sell. (change item `_price` or add item `_stock`) -``` js -function update(uint256 _item, uint256 _price, uint256 _stock) onlyOwner public -``` - -#### price -Get token address and price from buyer with item index `_item`. -``` js -function price(uint256 _item) public constant returns (address _erc20, uint256 _value) -``` - -#### canBuy -`_who` can Buy `_item`. -``` js -function canBuy(address _who, uint256 _item) public constant returns (bool _canBuy) -``` - -#### isBuyer -`_who` is buyer of `_item`. -``` js -function isBuyer(address _who, uint256 _item) public constant returns (bool _buyer) -``` - -#### info -Set shop information bytes. -``` js -function info(bytes _msgPack) -``` - -#### upVote -Up vote for this shop. -``` js -function upVote() -``` - -#### dnVote -Down vote for this shop. -``` js -function dnVote() -``` - -#### about -Get shop token, up vote and down vote. -``` js -function about() view returns (address _erc20, uint256 _up, uint256 _down) -``` - -#### infoItem -Set item information bytes. -``` js -function infoItem(uint256 _item, bytes _msgPack) -``` - -#### upVoteItem -Up vote for this item. -``` js -function upVoteItem(uint256 _item) -``` - -#### dnVoteItem -Down vote for this item. -``` js -function dnVoteItem(uint256 _item) -``` - -#### aboutItem -Get Item price, up vote and down vote. -``` js -function aboutItem(uint256 _item) view returns (uint256 _price, uint256 _up, uint256 _down) -``` - -### Events -#### Pay -``` js -event Pay(address indexed _buyer, uint256 indexed _item, uint256 indexed _value) -``` - -#### Refund -``` js -event Refund(address indexed _to, uint256 indexed _item, uint256 indexed _value) -``` - -#### Item -``` js -event Item(uint256 indexed _item, uint256 _price) -``` - -#### Info -``` js -event Info(bytes _msgPack) -``` - -#### InfoItem -``` js -event InfoItem(uint256 indexed _item, bytes _msgPack) -``` - -## Implementation -Sample token contract address is [0x393dd70ce2ae7b30501aec94727968c517f90d52](https://ropsten.etherscan.io/address/0x393dd70ce2ae7b30501aec94727968c517f90d52) - -WalletCenter contract address is [0x1fe0862a4a8287d6c23904d61f02507b5044ea31](https://ropsten.etherscan.io/address/0x1fe0862a4a8287d6c23904d61f02507b5044ea31) - -WalletCenter create shop contract address is [0x59117730D02Ca3796121b7975796d479A5Fe54B0](https://ropsten.etherscan.io/address/0x59117730D02Ca3796121b7975796d479A5Fe54B0) - -WalletCenter create wallet contract address is [0x39da7111844df424e1d0a0226183533dd07bc5c6](https://ropsten.etherscan.io/address/0x39da7111844df424e1d0a0226183533dd07bc5c6) - - -## Appendix -``` js -pragma solidity ^0.4.24; - -contract ERC20Interface { - function totalSupply() public constant returns (uint); - function balanceOf(address tokenOwner) public constant returns (uint balance); - function allowance(address tokenOwner, address spender) public constant returns (uint remaining); - function transfer(address to, uint tokens) public returns (bool success); - function approve(address spender, uint tokens) public returns (bool success); - function transferFrom(address from, address to, uint tokens) public returns (bool success); - - event Transfer(address indexed from, address indexed to, uint tokens); - event Approval(address indexed tokenOwner, address indexed spender, uint tokens); -} - -contract SafeMath { - function safeAdd(uint a, uint b) public pure returns (uint c) { - c = a + b; - require(c >= a); - } - function safeSub(uint a, uint b) public pure returns (uint c) { - require(b <= a); - c = a - b; - } - function safeMul(uint a, uint b) public pure returns (uint c) { - c = a * b; - require(a == 0 || c / a == b); - } - function safeDiv(uint a, uint b) public pure returns (uint c) { - require(b > 0); - c = a / b; - } -} - -contract _Base { - address internal owner; - address internal walletCenter; - - modifier onlyOwner { - require(owner == msg.sender); - _; - } - modifier onlyWallet(address _addr) { - require(WalletCenter(walletCenter).isWallet(_addr)); - _; - } - modifier onlyShop(address _addr) { - require(WalletCenter(walletCenter).isShop(_addr)); - _; - } - - function balanceOf(address _erc20) public constant returns (uint256 balance) { - if(_erc20==address(0)) - return address(this).balance; - return ERC20Interface(_erc20).balanceOf(this); - } - - function transfer(address _to, address _erc20, uint256 _value) internal returns (bool success) { - require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value); - if(_erc20==address(0)) - _to.transfer(_value); - else - ERC20Interface(_erc20).approve(_to,_value); - return true; - } - - function withdrawal(address _erc20, uint256 _value) public returns (bool success); - - event Pay(address indexed _who, uint256 indexed _item, uint256 indexed _value); - event Refund(address indexed _who, uint256 indexed _item, uint256 indexed _value); - event Prize(address indexed _who, uint256 indexed _item, uint256 indexed _value); -} - -contract _Wallet is _Base { - constructor(address _who) public { - owner = _who; - walletCenter = msg.sender; - } - - function pay(address _shop, uint256 _item) private { - require(_Shop(_shop).canBuy(this,_item)); - - address _erc20; - uint256 _value; - (_erc20,_value) = _Shop(_shop).price(_item); - - transfer(_shop,_erc20,_value); - _Shop(_shop).pay(_item); - emit Pay(_shop,_item,_value); - } - - function paySafe(address _shop, uint256 _item) onlyOwner onlyShop(_shop) public payable returns (bool success) { - pay(_shop,_item); - return true; - } - function payUnsafe(address _shop, uint256 _item) onlyOwner public payable returns (bool success) { - pay(_shop,_item); - return true; - } - function payCancel(address _shop, uint256 _item) onlyOwner public returns (bool success) { - _Shop(_shop).payCancel(_item); - return true; - } - - function refund(address _erc20, uint256 _item, uint256 _value) public payable returns (bool success) { - require((_erc20==address(0)?msg.value:ERC20Interface(_erc20).allowance(msg.sender,this))==_value); - if(_erc20!=address(0)) - ERC20Interface(_erc20).transferFrom(msg.sender,this,_value); - emit Refund(msg.sender,_item,_value); - return true; - } - function prize(address _erc20, uint256 _item, uint256 _value) public payable returns (bool success) { - require((_erc20==address(0)?msg.value:ERC20Interface(_erc20).allowance(msg.sender,this))==_value); - if(_erc20!=address(0)) - ERC20Interface(_erc20).transferFrom(msg.sender,this,_value); - emit Prize(msg.sender,_item,_value); - return true; - } - - function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) { - require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value); - if(_erc20==address(0)) - owner.transfer(_value); - else - ERC20Interface(_erc20).transfer(owner,_value); - return true; - } -} - -contract _Shop is _Base, SafeMath{ - address erc20; - constructor(address _who, address _erc20) public { - owner = _who; - walletCenter = msg.sender; - erc20 = _erc20; - } - - struct item { - uint8 category; // 0 = disable, 1 = non Stock, non Expire, 2 = can Expire (after 1 week), 3 = stackable - uint256 price; - uint256 stockCount; - - mapping(address=>uint256) customer; - } - - uint index; - mapping(uint256=>item) items; - - function pay(uint256 _item) onlyWallet(msg.sender) public payable returns (bool success) { - require(canBuy(msg.sender, _item)); - require((erc20==address(0)?msg.value:ERC20Interface(erc20).allowance(msg.sender,this))==items[_item].price); - - if(erc20!=address(0)) - ERC20Interface(erc20).transferFrom(msg.sender,this,items[_item].price); - - if(items[_item].category==1 || items[_item].category==2 && now > safeAdd(items[_item].customer[msg.sender], 1 weeks)) - items[_item].customer[msg.sender] = now; - else if(items[_item].category==2 && now < safeAdd(items[_item].customer[msg.sender], 1 weeks) ) - items[_item].customer[msg.sender] = safeAdd(items[_item].customer[msg.sender], 1 weeks); - else if(items[_item].category==3) { - items[_item].customer[msg.sender] = safeAdd(items[_item].customer[msg.sender],1); - items[_item].stockCount = safeSub(items[_item].stockCount,1); - } - - emit Pay(msg.sender,_item,items[_item].customer[msg.sender]); - return true; - } - - function payCancel(uint256 _item) onlyWallet(msg.sender) public returns (bool success) { - require (items[_item].category==2&&safeAdd(items[_item].customer[msg.sender],2 weeks)>now&&balanceOf(erc20)>=items[_item].price); - - items[_item].customer[msg.sender] = safeSub(items[_item].customer[msg.sender],1 weeks); - transfer(msg.sender, erc20, items[_item].price); - _Wallet(msg.sender).refund(erc20,_item,items[_item].price); - emit Refund(msg.sender,_item,items[_item].price); - - return true; - } - function refund(address _to, uint256 _item) onlyWallet(_to) onlyOwner public payable returns (bool success) { - require(isBuyer(_to,_item)&&items[_item].category>0&&(items[_item].customer[_to]>0||(items[_item].category==2&&safeAdd(items[_item].customer[_to],2 weeks)>now))); - require((erc20==address(0)?address(this).balance:ERC20Interface(erc20).balanceOf(this))>=items[_item].price); - - if(items[_item].category==1) - items[_item].customer[_to] = 0; - else if(items[_item].category==2) - items[_item].customer[_to] = safeSub(items[_item].customer[_to],1 weeks); - else - items[_item].customer[_to] = safeSub(items[_item].customer[_to],1); - - transfer(_to, erc20, items[_item].price); - _Wallet(_to).refund(erc20,_item,items[_item].price); - emit Refund(_to,_item,items[_item].price); - - return true; - } - - event Item(uint256 indexed _item, uint256 _price); - function resister(uint8 _category, uint256 _price, uint256 _stock) onlyOwner public returns (uint256 _itemId) { - require(_category>0&&_category<4); - require(_price>0); - items[index] = item(_category,_price,_stock); - index = safeAdd(index,1); - emit Item(index,_price); - return safeSub(index,1); - } - function update(uint256 _item, uint256 _price, uint256 _stock) onlyOwner public { - require(items[_item].category>0); - require(_price>0); - uint256 temp = items[_item].price; - items[_item].price = _price; - items[_item].stockCount = safeAdd(items[_item].stockCount,_stock); - - if(temp!=items[_item].price) - emit Item(index,items[_item].price); - } - - function price(uint256 _item) public constant returns (address _erc20, uint256 _value) { - return (erc20,items[_item].price); - } - - function canBuy(address _who, uint256 _item) public constant returns (bool _canBuy) { - return (items[_item].category>0) && - !(items[_item].category==1&&items[_item].customer[_who]>0) && - (items[_item].stockCount>0); - } - - function isBuyer(address _who, uint256 _item) public constant returns (bool _buyer) { - return (items[_item].category==1&&items[_item].customer[_who]>0)||(items[_item].category==2&&safeAdd(items[_item].customer[_who],1 weeks)>now)||(items[_item].category==3&&items[_item].customer[_who]>0); - } - - uint lastWithdrawal; - function withdrawal(address _erc20, uint256 _value) onlyOwner public returns (bool success) { - require(safeAdd(lastWithdrawal,1 weeks)<=now); - require((_erc20==address(0)?address(this).balance:ERC20Interface(_erc20).balanceOf(this))>=_value); - if(_erc20==address(0)) - owner.transfer(_value); - else - ERC20Interface(_erc20).transfer(owner,_value); - lastWithdrawal = now; - return true; - } -} - -contract WalletCenter { - mapping(address=>bool) public wallet; - event Wallet(address indexed _owner, address indexed _wallet); - function createWallet() public returns (address _wallet) { - _wallet = new _Wallet(msg.sender); - wallet[_wallet] = true; - emit Wallet(msg.sender,_wallet); - return _wallet; - } - function isWallet(address _wallet) public constant returns (bool) { - return wallet[_wallet]; - } - mapping(address=>bool) public shop; - event Shop(address indexed _owner, address indexed _shop, address indexed _erc20); - function createShop(address _erc20) public returns (address _shop) { - _shop = new _Shop(msg.sender,_erc20); - shop[_shop] = true; - emit Shop(msg.sender,_shop,_erc20); - return _shop; - } - function isShop(address _shop) public constant returns (bool) { - return shop[_shop]; - } -} -``` -## Copyright -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From e5a68c897a618938ddd404555fa4a10d39f65a06 Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Thu, 21 Feb 2019 12:19:13 -0700 Subject: [PATCH 023/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 126 +++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 66 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index b809ff92..18213d3b 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,58 +4,51 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth), Brooklyn Zelenka (@expede) +author: Greg Colvin , Brooklyn Zelenka , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) +discussion to: https://github.com/ethereum/EIPs/issues/615 created: 2016-12-10 edited: 2019-18-2 --- ## Simple Summary -This EIP introduces new EVM opcodes and conditions on EVM code to support subroutines and static jumps, deprecates dynamic jumps, and thereby make EVM code amenable to linear-time static analysis. This will provide for better compilation, interpretation, transpilation, and formal analysis of EVM code. +In the 21st century, on a blockchain circulating billions of ETH, formal specification and verification are an essential tool against loss. Yet the design of the EVM makes this unnecessarily difficult. Further, the design of the EVM makes low-gas-cost, high-performance execution difficult. We propose to move forward with proposals to resolve these problems by tightening the security guarantees and pushing the performance limits of the EVM. ## Abstract -EVM code is currently difficult to statically analyze, hobbling a critical tool for preventing the many expensive bugs our blockchain has experienced. Futher, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to meet the network's long-term demands. This proposal identifies a major reason for these issues, and proposes changes to the EVM specification to address the problem, making futher efforts towards a safer and more performant the EVM possible. - -In particular, it imposes restrictions on EVM code and proposes new instructions to help provide for - -* Better static analysis tools -* Much easier formalization -* Faster interpretation -* Near-linear-time compilation to native code, and to and from eWasm -* Easier code generation from other languages, including - * Solidity - * LLVM IR and thus many languages, incuding - * C, C++, Fortran, Haskell, Java, Ruby and Rust. - -These goals are achieved by: - -* Deprecating dynamic jumps -* Introducing subroutines—jumps with return support -* Disallowing pathological control flow and uses of the stack +EVM code is currently difficult to statically analyze, hobbling critical tools for preventing the many expensive bugs our blockchain has experienced. Further, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to reduce the need for precompiles and otherwise meet the network's long-term demands. This proposal identifies dynamic jumps as a major reason for these issues, and proposes changes to the EVM specification to address the problem, making further efforts towards a safer and more performant the EVM possible. We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. And well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. ## Motivation -Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since every jump can potentially be to any jump destination in the code, the number of possible paths through the code goes up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at validation time, further inhibiting static and formal analyses. But absent dynamic jumps code can be statically analyzed in linear time. +Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since every jump can potentially be to any jump destination in the code, the number of possible paths through the code goes up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses. -Static analysis includes validation, and much of optimization, compilation, transpilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. In particular, linear-time control-flow analysis means near-linear-time compilation of EVM code, and better data-flow analysis can help the compiler and the interpreter better track the size of the values on the stack and use native 64- and 32-bit operations when possible. Gas metering optimization also becomes much more tractable. Additionally, conditions which are statically checked at validation time don’t have to be checked repeatedly at runtime. +Absent dynamic jumps code can be statically analyzed in linear time. Static analysis includes validation, and much of optimization, compilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. And absent dynamic jumps, and with proper subroutines the EVM is a better target for code generation from other languages, including +* Solidity +* Vyper +* LLVM—languages with an LLVM backend include C, C++, Common Lisp, D, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift. -Note that analyses of a contract’s bytecode before execution—such as optimizations performed before interpretation, compilation, and on-the-fly machine code generation—must be efficient and linear-time. Otherwise, specially crafted contracts can be used as attack vectors against clients that use static analysis of EVM code before the creation or execution of contracts. +The result is that all of the following validations and optimizations can be done at deployment time with **linear** **`(n)`** **or** **near-linear** **`(n log n)`** **time complexity** +* The absence of most exception halting conditions can be validated. +* The maximum use of resources can be sometimes be calculated. +* Bytecode can be compiled to machine code. +* Compilation can optimize use of smaller registers. +* Compilation can optimize injection of gas metering. + +Note that near-linear `(n log n)` time complexity is essential. Otherwise, specially crafted contracts can be used as attack vectors against any validations and optimizations. ## Specification ### Proposal -We propose to deprecate two existing instructions—`JUMP` and `JUMPI`. They take their argument on the stack, which means that unless the value is constant they can jump to any `JUMPDEST`. (In simple cases like `PUSH 0 JUMP` the value on the stack can be known to be constant, but in general it's difficult.) We must nonetheless continue to support them in old code. - -Having deprecated `JUMP` and `JUMPI`, we propose new instructions to support their legitimate uses. +We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. #### Preliminaries These forms * `INSTRUCTION x,` +* `INSTRUCTION n,` * `INSTRUCTION x, y` * `INSTRUCTION n, x ...` @@ -138,7 +131,7 @@ We will adopt the following conventions to describe the machine state: Defining the frame pointer so as to include the arguments is unconventional, but better fits our stack semantics and simplifies the remainder of the proposal. -The frame pointer and return stacks are internal to the subroutine mechanism, and not directly accessible to the program. This is necessary to prevent the program from modifying its state in ways that could be invalid. +The frame pointer and return stacks are internal to the subroutine mechanism, and not directly accessible to the program. This is necessary to prevent the program from modifying its own state in ways that could be invalid. The first instruction of an array of EVM bytecode begins execution of a _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack—`code_size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV`—that is, in the _main_ routine—executes a `STOP`.) @@ -224,6 +217,45 @@ In practice, we must test at runtime for conditions 1 and 2—sufficient gas and All of the remaining conditions we validate statically. + +#### Costs & Codes + +All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell. + +We suggest the following opcodes: +``` +0xb0 JUMPTO +0xb1 JUMPIF +0xb2 JUMPV +0xb3 JUMPSUB +0xb4 JUMPSUBV +0xb5 BEGINSUB +0xb6 BEGINDATA +0xb7 RETURNSUB +0xb8 PUTLOCAL +0xb9 GETLOCAL +``` + +## Backwards Compatibility + +These changes would need to be implemented in phases at decent intervals: +>**1.** If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it. + +>**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely. + +If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult. + +## Rationale + +This design was highly constrained by the existing EVM semantics, the requirement for eWasm compatibility, and the security demands of the Ethereum environment. It was also informed by the lead author's previous work implementing Java and Scheme interpreters. As such there was very little room for alternative designs. + +As described above, the approach was simply to deprecate the problematic dynamic jumps, then ask what opcodes were necessary to provide for the features they supported. These needed to include those provided by eWasm, which themselves were modeled after typical hardware. The only real innovation was to move the frame pointer and the return pointer to their own stacks, so as to prevent any possibility of overwriting them. (Although Forth also uses a return stack.) This allowed for treating subroutine arguments as local variables, and facilitated the return of multiple values. + +## Implementation + +Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. Compiled code can use native call instructions, greatly improving performance. Further optimizations include minimizing runtime checks for exceptions, condensing gas metering, and otherwise taking advantage of validated code wherever possible. A lightly tested reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) + +## APPENDIX ### Validation Validation comprises two tasks: @@ -344,7 +376,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t // return to top or from recursion to JUMPSUB if instruction is RETURNSUB - break; + return true;; if instruction is JUMPSUB { @@ -380,44 +412,6 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t } ``` -#### Costs & Codes - -All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell. - -We suggest the following opcodes: -``` -0xb0 JUMPTO -0xb1 JUMPIF -0xb2 JUMPV -0xb3 JUMPSUB -0xb4 JUMPSUBV -0xb5 BEGINSUB -0xb6 BEGINDATA -0xb7 RETURNSUB -0xb8 PUTLOCAL -0xb9 GETLOCAL -``` - -## Backwards Compatibility - -These changes would need to be implemented in phases at decent intervals: ->**1.** If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it. - ->**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely. - -If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult. - -## Rationale - -This design was highly constrained by the existing EVM semantics, the requirement for eWasm compatibility, and the security demands of the Ethereum environment. It was also informed by the lead author's previous work implementing Java and Scheme interpreters. As such there was very little room for alternative designs. - -As described above, the approach was simply to deprecate the problematic dynamic jumps, then ask what opcodes were necessary to provide for the features they supported. These needed to include those provided by eWasm, which themselves were modeled after typical hardware. The only real innovation was to move the frame pointer and the return pointer to their own stacks, so as to prevent any possibility of overwriting them. (Although Forth also uses a return stack.) This allowed for treating subroutine arguments as local variables, and facilitated the return of multiple values. - -## Implementation - -Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. Compiled code can use native call instructions, greatly improving performance. Further optimizations include minimizing runtime checks for exceptions, condensing gas metering, and otherwise taking advantage of validated code wherever possible. A lightly tested reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) - - ## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 7dfe25eafd03ff56c58891a9b34689a5d5a35b1d Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 22 Feb 2019 08:23:23 +1300 Subject: [PATCH 024/431] Update eip-1577.md --- EIPS/eip-1577.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1577.md b/EIPS/eip-1577.md index 61025061..f16af8ed 100644 --- a/EIPS/eip-1577.md +++ b/EIPS/eip-1577.md @@ -32,7 +32,7 @@ The value returned by `contenthash` MUST be represented as a machine-readable [m protoCodes and their meanings are specified in the [multiformats/multicodec](https://github.com/multiformats/multicodec) repository. -The encoding of the value depends on the content type specified by the protoCode. Values with protocodes of 0xee and 0xef represent IPFS and Swarm content; these values are encoded as v1 [CIDs](https://github.com/multiformats/cid) without a base prefix, meaning their value is formatted as follows: +The encoding of the value depends on the content type specified by the protoCode. Values with protocodes of 0xe3 and 0xe4 represent IPFS and Swarm content; these values are encoded as v1 [CIDs](https://github.com/multiformats/cid) without a base prefix, meaning their value is formatted as follows: ``` From 13104c666650442471fa661e36d3426d3f30fa87 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 22 Feb 2019 08:38:05 +1300 Subject: [PATCH 025/431] Graphql node interface (#1767) * First draft of graphql EIP * Try and fix table. * Try again to fix table. * Sort table * Update eip-tbd.md * Update eip-tbd.md * Update eip-tbd.md * Update eip-tbd.md * Update eip-tbd.md * Update eip-tbd.md * Update eip-tbd.md * Create eip-draft-graphql.md * Update eip-draft-graphql.md * Update and rename eip-draft-graphql.md to eip-1767.md * Remove eip-tbd --- EIPS/eip-1767.md | 396 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 EIPS/eip-1767.md diff --git a/EIPS/eip-1767.md b/EIPS/eip-1767.md new file mode 100644 index 00000000..adf9daaa --- /dev/null +++ b/EIPS/eip-1767.md @@ -0,0 +1,396 @@ +--- +eip: 1767 +title: GraphQL interface to Ethereum node data +author: Nick Johnson (@arachnid) +discussions-to: https://ethereum-magicians.org/t/graphql-interface-to-ethereum-node-data/2710 +status: Draft +type: Standards Track +category: Interface +created: 2019-02-14 +--- + +## Abstract +This EIP specifies a GraphQL schema for accessing data stored on an Ethereum node. It aims to provide a complete replacement to the read-only information exposed via the present JSON-RPC interface, while improving on usability, consistency, efficiency, and future-proofing. + +## Motivation +The current JSON-RPC interface for Ethereum nodes has a number of shortcomings. It's informally and incompletely specified in areas, which has led to incompatibilities around issues such as representation of empty byte strings ("" vs "0x" vs "0x0"), and it has to make educated guesses about the data a user will request, which often leads to unnecessary work. + +For example, the `totalDifficulty` field is stored separately from the block header in common Ethereum node implementations, and many callers do not require this field. However, every call to `eth_getBlock` still retrieves this field, requiring a separate disk read, because the RPC server has no way of knowing if the user requires this field or not. + +Similarly, transaction receipts in go-ethereum are stored on disk as a single binary blob for each block. Fetching a receipt for a single transaction requires fetching and deserializing this blob, then finding the relevant entry and returning it; this is accomplished by the `eth_getTransactionReceipt` API call. A common task for API consumers is to fetch all the receipts in a block; as a result, node implementations end up fetching and deserializing the same data repeatedly, leading to `O(n^2)` effort to fetch all transaction receipts from a block instead of `O(n)`. + +Some of these issues could be fixed with changes to the existing JSON-RPC interface, at the cost of complicating the interface somewhat. Instead, we propose adopting a standard query language, GraphQL, which facilitates more efficient API implementations, while also increasing flexibility. + +## Specification + +### Node API + +Compatible nodes MUST provide a GraphQL endpoint available over HTTP. This SHOULD be offered on port 8547 by default. The path to the GraphQL endpoint SHOULD be '/graphql'. + +Compatible nodes MAY offer a GraphiQL interactive query explorer on the root path ('/'). + +### Schema + +The GraphQL schema for this service is defined as follows: +``` +# Bytes32 is a 32 byte binary string, represented as 0x-prefixed hexadecimal. +scalar Bytes32 +# Address is a 20 byte Ethereum address, represented as 0x-prefixed hexadecimal. +scalar Address +# Bytes is an arbitrary length binary string, represented as 0x-prefixed hexadecimal. +# An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nybbles. +scalar Bytes +# BigInt is a large integer. Input is accepted as either a JSON number or as a string. +# Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all +# 0x-prefixed hexadecimal. +scalar BigInt +# Long is a 64 bit unsigned integer. +scalar Long + +schema { + query: Query + mutation: Mutation +} + +# Account is an Ethereum account at a particular block. +type Account { + # Address is the address owning the account. + address: Address! + # Balance is the balance of the account, in wei. + balance: BigInt! + # TransactionCount is the number of transactions sent from this account, + # or in the case of a contract, the number of contracts created. Otherwise + # known as the nonce. + transactionCount: Long! + # Code contains the smart contract code for this account, if the account + # is a (non-self-destructed) contract. + code: Bytes! + # Storage provides access to the storage of a contract account, indexed + # by its 32 byte slot identifier. + storage(slot: Bytes32!): Bytes32! +} + +# Log is an Ethereum event log. +type Log { + # Index is the index of this log in the block. + index: Int! + # Account is the account which generated this log - this will always + # be a contract account. + account(block: Long): Account! + # Topics is a list of 0-4 indexed topics for the log. + topics: [Bytes32!]! + # Data is unindexed data for this log. + data: Bytes! + # Transaction is the transaction that generated this log entry. + transaction: Transaction! +} + +# Transaction is an Ethereum transaction. +type Transaction { + # Hash is the hash of this transaction. + hash: Bytes32! + # Nonce is the nonce of the account this transaction was generated with. + nonce: Long! + # Index is the index of this transaction in the parent block. This will + # be null if the transaction has not yet beenn mined. + index: Int + # From is the account that sent this transaction - this will always be + # an externally owned account. + from(block: Long): Account! + # To is the account the transaction was sent to. This is null for + # contract-creating transactions. + to(block: Long): Account + # Value is the value, in wei, sent along with this transaction. + value: BigInt! + # GasPrice is the price offered to miners for gas, in wei per unit. + gasPrice: BigInt! + # Gas is the maximum amount of gas this transaction can consume. + gas: Long! + # InputData is the data supplied to the target of the transaction. + inputData: Bytes! + # Block is the block this transaction was mined in. This will be null if + # the transaction has not yet been mined. + block: Block + + # Status is the return status of the transaction. This will be 1 if the + # transaction succeeded, or 0 if it failed (due to a revert, or due to + # running out of gas). If the transaction has not yet been mined, this + # field will be null. + status: Long + # GasUsed is the amount of gas that was used processing this transaction. + # If the transaction has not yet been mined, this field will be null. + gasUsed: Long + # CumulativeGasUsed is the total gas used in the block up to and including + # this transaction. If the transaction has not yet been mined, this field + # will be null. + cumulativeGasUsed: Long + # CreatedContract is the account that was created by a contract creation + # transaction. If the transaction was not a contract creation transaction, + # or it has not yet been mined, this field will be null. + createdContract(block: Long): Account + # Logs is a list of log entries emitted by this transaction. If the + # transaction has not yet been mined, this field will be null. + logs: [Log!] +} + +# BlockFilterCriteria encapsulates log filter criteria for a filter applied +# to a single block. +input BlockFilterCriteria { + # Addresses is list of addresses that are of interest. If this list is + # empty, results will not be filtered by address. + addresses: [Address!] + # Topics list restricts matches to particular event topics. Each event has a list + # of topics. Topics matches a prefix of that list. An empty element array matches any + # topic. Non-empty elements represent an alternative that matches any of the + # contained topics. + # + # Examples: + # - [] or nil matches any topic list + # - [[A]] matches topic A in first position + # - [[], [B]] matches any topic in first position, B in second position + # - [[A], [B]] matches topic A in first position, B in second position + # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position + topics: [[Bytes32!]!] +} + +# Block is an Ethereum block. +type Block { + # Number is the number of this block, starting at 0 for the genesis block. + number: Long! + # Hash is the block hash of this block. + hash: Bytes32! + # Parent is the parent block of this block. + parent: Block + # Nonce is the block nonce, an 8 byte sequence determined by the miner. + nonce: Bytes! + # TransactionsRoot is the keccak256 hash of the root of the trie of transactions in this block. + transactionsRoot: Bytes32! + # TransactionCount is the number of transactions in this block. if + # transactions are not available for this block, this field will be null. + transactionCount: Int + # StateRoot is the keccak256 hash of the state trie after this block was processed. + stateRoot: Bytes32! + # ReceiptsRoot is the keccak256 hash of the trie of transaction receipts in this block. + receiptsRoot: Bytes32! + # Miner is the account that mined this block. + miner(block: Long): Account! + # ExtraData is an arbitrary data field supplied by the miner. + extraData: Bytes! + # GasLimit is the maximum amount of gas that was available to transactions in this block. + gasLimit: Long! + # GasUsed is the amount of gas that was used executing transactions in this block. + gasUsed: Long! + # Timestamp is the unix timestamp at which this block was mined. + timestamp: BigInt! + # LogsBloom is a bloom filter that can be used to check if a block may + # contain log entries matching a filter. + logsBloom: Bytes! + # MixHash is the hash that was used as an input to the PoW process. + mixHash: Bytes32! + # Difficulty is a measure of the difficulty of mining this block. + difficulty: BigInt! + # TotalDifficulty is the sum of all difficulty values up to and including + # this block. + totalDifficulty: BigInt! + # OmmerCount is the number of ommers (AKA uncles) associated with this + # block. If ommers are unavailable, this field will be null. + ommerCount: Int + # Ommers is a list of ommer (AKA uncle) blocks associated with this block. + # If ommers are unavailable, this field will be null. Depending on your + # node, the transactions, transactionAt, transactionCount, ommers, + # ommerCount and ommerAt fields may not be available on any ommer blocks. + ommers: [Block] + # OmmerAt returns the ommer (AKA uncle) at the specified index. If ommers + # are unavailable, or the index is out of bounds, this field will be null. + ommerAt(index: Int!): Block + # OmmerHash is the keccak256 hash of all the ommers (AKA uncles) + # associated with this block. + ommerHash: Bytes32! + # Transactions is a list of transactions associated with this block. If + # transactions are unavailable for this block, this field will be null. + transactions: [Transaction!] + # TransactionAt returns the transaction at the specified index. If + # transactions are unavailable for this block, or if the index is out of + # bounds, this field will be null. + transactionAt(index: Int!): Transaction + # Logs returns a filtered set of logs from this block. + logs(filter: BlockFilterCriteria!): [Log!]! +} + +# CallData represents the data associated with a local contract call. +# All fields are optional. +input CallData { + # From is the address making the call. + from: Address + # To is the address the call is sent to. + to: Address + # Gas is the amount of gas sent with the call. + gas: Long + # GasPrice is the price, in wei, offered for each unit of gas. + gasPrice: BigInt + # Value is the value, in wei, sent along with the call. + value: BigInt + # Data is the data sent to the callee. + data: Bytes +} + +# CallResult is the result of a local call operationn. +type CallResult { + # Data is the return data of the called contract. + data: Bytes! + # GasUsed is the amount of gas used by the call, after any refunds. + gasUsed: Long! + # Status is the result of the call - 1 for success or 0 for failure. + status: Long! +} + +# FilterCriteria encapsulates log filter criteria for searching log entries. +input FilterCriteria { + # FromBlock is the block at which to start searching, inclusive. Defaults + # to the latest block if not supplied. + fromBlock: Long + # ToBlock is the block at which to stop searching, inclusive. Defaults + # to the latest block if not supplied. + toBlock: Long + # Addresses is a list of addresses that are of interest. If this list is + # empty, results will not be filtered by address. + addresses: [Address!] + # Topics list restricts matches to particular event topics. Each event has a list + # of topics. Topics matches a prefix of that list. An empty element array matches any + # topic. Non-empty elements represent an alternative that matches any of the + # contained topics. + # + # Examples: + # - [] or nil matches any topic list + # - [[A]] matches topic A in first position + # - [[], [B]] matches any topic in first position, B in second position + # - [[A], [B]] matches topic A in first position, B in second position + # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position + topics: [[Bytes32!]!] +} + +# SyncState contains the current synchronisation state of the client. +type SyncState{ + # StartingBlock is the block number at which synchronisation started. + startingBlock: Long! + # CurrentBlock is the point at which synchronisation has presently reached. + currentBlock: Long! + # HighestBlock is the latest known block number. + highestBlock: Long! + # PulledStates is the number of state entries fetched so far, or null + # if this is not known or not relevant. + pulledStates: Long + # KnownStates is the number of states the node knows of so far, or null + # if this is not known or not relevant. + knownStates: Long +} + +type Query { + # Account fetches an Ethereum account at the specified block number. + # If blockNumber is not provided, it defaults to the most recent block. + account(address: Address!, blockNumber: Long): Account! + # Block fetches an Ethereum block by number or by hash. If neither is + # supplied, the most recent known block is returned. + block(number: Long, hash: Bytes32): Block + # Blocks returns all the blocks between two numbers, inclusive. If + # to is not supplied, it defaults to the most recent known block. + blocks(from: Long!, to: Long): [Block!]! + # Transaction returns a transaction specified by its hash. + transaction(hash: Bytes32!): Transaction + # Call executes a local call operation. If blockNumber is not specified, + # it defaults to the most recent known block. + call(data: CallData!, blockNumber: Long): CallResult + # EstimateGas estimates the amount of gas that will be required for + # successful execution of a transaction. If blockNumber is not specified, + # it defaults ot the most recent known block. + estimateGas(data: CallData!, blockNumber: Long): Long! + # Logs returns log entries matching the provided filter. + logs(filter: FilterCriteria!): [Log!]! + # GasPrice returns the node's estimate of a gas price sufficient to + # ensure a transaction is mined in a timely fashion. + gasPrice: BigInt! + # ProtocolVersion returns the current wire protocol version number. + protocolVersion: Int! + # Syncing returns information on the current synchronisation state. + syncing: SyncState +} + +type Mutation { + # SendRawTransaction sends an RLP-encoded transaction to the network. + sendRawTransaction(data: Bytes!): Bytes32! +} +``` + +Nodes MAY offer a superset of this schema, by adding new fields or types. Experimental or client-specific fields MUST be prefixed with '_client_' (eg, '_geth_' or '_parity_'). Unprefixed fields MUST be specified in a new EIP that extends this one. + +## Rationale +Ethereum nodes have been moving away from providing read-write functionality such as transaction and message signing, and from other services such as code compilation, in favor of a more 'unix-like' approach where each task is performed by a dedicated process. We have thus specified a core set of types and fields that reflects this trend, leaving out functionality that is presently, or intended to be, deprecated: + + - `eth_compile*` calls are deprecated, and hence not provided here. + - `eth_accounts`, `eth_sign`, and `eth_sendTransaction` are considered by many to be deprecated, and are not provided here; callers should use local accounts or a separate signing daemon instead. + +Further, two areas of the current API interface have been omitted for simplicity in this initial standard, with the intention that they will be defined in a later EIP: + + - Filters will require use of GraphQL subscriptions, and require careful consideration around the desire for nodes without local per-caller state. + - Mining functionality is less-used and benefits less from reimplementation in GraphQL, and should be specified in a separate EIP. + +## Backwards Compatibility + +This schema implements the bulk of the current read-only functionality provided by the JSON-RPC node interface. Existing RPC calls can be mapped to GraphQL queries as follows: + +| RPC | Status | Description | +| --- | ------ | ----------- | +| eth_blockNumber | IMPLEMENTED | `{ block { number } }` | +| eth_call | IMPLEMENTED | `{ call(data: { to: "0x...", data: "0x..." }) { data status gasUsed } }` | +| eth_estimateGas | IMPLEMENTED | `{ estimateGas(data: { to: "0x...", data: "0x..." }) }` | +| eth_gasPrice | IMPLEMENTED | `{ gasPrice }` | +| eth_getBalance | IMPLEMENTED | `{ account(address: "0x...") { balance } }` | +| eth_getBlockByHash | IMPLEMENTED | `{ block(hash: "0x...") { ... } }` | +| eth_getBlockByNumber | IMPLEMENTED | `{ block(number: 123) { ... } }` | +| eth_getBlockTransactionCountByHash | IMPLEMENTED | `{ block(hash: "0x...") { transactionCount } }` | +| eth_getBlockTransactionCountByNumber | IMPLEMENTED | `{ block(number: x) { transactionCounnt } }` | +| eth_getCode | IMPLEMENTED | `{ account(address: "0x...") { code } }` | +| eth_getLogs | IMPLEMENTED | `{ logs(filter: { ... }) { ... } }` or `{ block(...) { logs(filter: { ... }) { ... } } }` | +| eth_getStorageAt | IMPLEMENTED | `{ account(address: "0x...") { storage(slot: "0x...") } }` | +| eth_getTransactionByBlockHashAndIndex | IMPLEMENTED | `{ block(hash: "0x...") { transactionAt(index: x) { ... } } }` | +| eth_getTransactionByBlockNumberAndIndex | IMPLEMENTED | `{ block(number: n) { transactionAt(index: x) { ... } } }` | +| eth_getTransactionByHash | IMPLEMENTED | `{ transaction(hash: "0x...") { ... } }` | +| eth_getTransactionCount | IMPLEMENTED | `{ account(address: "0x...") { transactionCount } }` | +| eth_getTransactionReceipt | IMPLEMENTED | `{ transaction(hash: "0x...") { ... } }` | +| eth_getUncleByBlockHashAndIndex | IMPLEMENTED | `{ block(hash: "0x...") { ommerAt(index: x) { ... } } }` | +| eth_getUncleByBlockNumberAndIndex | IMPLEMENTED | `{ block(number: n) { ommerAt(index: x) { ... } } }` | +| eth_getUncleCountByBlockHash | IMPLEMENTED | `{ block(hash: "0x...") { ommerCount } }` | +| eth_getUncleCountByBlockNumber | IMPLEMENTED | `{ block(number: x) { ommerCount } }` | +| eth_protocolVersion | IMPLEMENTED | `{ protocolVersion }` | +| eth_sendRawTransaction | IMPLEMENTED | `mutation { sendRawTransaction(data: data) }` | +| eth_syncing | IMPLEMENTED | `{ syncing { ... } }` | +| eth_getCompilers | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. | +| eth_compileLLL | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. | +| eth_compileSolidity | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. | +| eth_compileSerpent | NOT IMPLEMENTED | Compiler functionality is deprecated in JSON-RPC. | +| eth_newFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. | +| eth_newBlockFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. | +| eth_newPendingTransactionFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. | +| eth_uninstallFilter | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. | +| eth_getFilterChanges | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. | +| eth_getFilterLogs | NOT IMPLEMENTED | Filter functionality may be specified in a future EIP. | +| eth_accounts | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. | +| eth_sign | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. | +| eth_sendTransaction | NOT IMPLEMENTED | Accounts functionality is not part of the core node API. | +| eth_coinbase | NOT IMPLEMENTED | Mining functionality to be defined separately. | +| eth_getWork | NOT IMPLEMENTED | Mining functionality to be defined separately. | +| eth_hashRate | NOT IMPLEMENTED | Mining functionality to be defined separately. | +| eth_mining | NOT IMPLEMENTED | Mining functionality to be defined separately. | +| eth_submitHashrate | NOT IMPLEMENTED | Mining functionality to be defined separately. | +| eth_submitWork | NOT IMPLEMENTED | Mining functionality to be defined separately. | + +For specific reasoning behind omitted functionality, see the Rationale section. + +## Test Cases +TBD. + +## Implementation +A go-ethereum implementation was completed in [PR 18445](https://github.com/ethereum/go-ethereum/pull/18445) and will be available in a forthcoming geth release. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 9854104efb3789fceb86984b7201f57f8b54ae5b Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Sun, 24 Feb 2019 09:37:10 +1300 Subject: [PATCH 026/431] Automatically merged updates to draft EIP(s) 1767 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1767.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1767.md b/EIPS/eip-1767.md index adf9daaa..013cbd2d 100644 --- a/EIPS/eip-1767.md +++ b/EIPS/eip-1767.md @@ -1,7 +1,7 @@ --- eip: 1767 title: GraphQL interface to Ethereum node data -author: Nick Johnson (@arachnid) +author: Nick Johnson (@arachnid), Raúl Kripalani (@raulk), discussions-to: https://ethereum-magicians.org/t/graphql-interface-to-ethereum-node-data/2710 status: Draft type: Standards Track @@ -21,6 +21,10 @@ Similarly, transaction receipts in go-ethereum are stored on disk as a single bi Some of these issues could be fixed with changes to the existing JSON-RPC interface, at the cost of complicating the interface somewhat. Instead, we propose adopting a standard query language, GraphQL, which facilitates more efficient API implementations, while also increasing flexibility. +## Prior Art + +Nick Johnson and [EthQL](https://github.com/ConsenSys/ethql) independently developed a GraphQL schema for node data. Once the parties were made aware of the shared effort, they made efforts to bring their schemas into alignment. The current schema proposed in this EIP is derived primarily from the EthQL schema. + ## Specification ### Node API From 2c6a87ce8f158769df5ed0934594bbcf2e448d47 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Sun, 24 Feb 2019 09:49:11 +1300 Subject: [PATCH 027/431] Automatically merged updates to draft EIP(s) 1767 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1767.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1767.md b/EIPS/eip-1767.md index 013cbd2d..e6e06d4f 100644 --- a/EIPS/eip-1767.md +++ b/EIPS/eip-1767.md @@ -1,7 +1,7 @@ --- eip: 1767 title: GraphQL interface to Ethereum node data -author: Nick Johnson (@arachnid), Raúl Kripalani (@raulk), +author: Nick Johnson (@arachnid), Raúl Kripalani (@raulk), Kris Shinn (@kshinn) discussions-to: https://ethereum-magicians.org/t/graphql-interface-to-ethereum-node-data/2710 status: Draft type: Standards Track From 06480720ae3b62259006c60630914fb80d2f6d4d Mon Sep 17 00:00:00 2001 From: Ryan Ghods Date: Sun, 24 Feb 2019 14:16:51 -0800 Subject: [PATCH 028/431] Automatically merged updates to draft EIP(s) 1193 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1193.md | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/EIPS/eip-1193.md b/EIPS/eip-1193.md index 86234f3c..4302426f 100644 --- a/EIPS/eip-1193.md +++ b/EIPS/eip-1193.md @@ -12,11 +12,7 @@ requires: 1102 ## Summary -This EIP formalizes an Ethereum Provider JavaScript API for consistency across clients and applications. - -The provider is designed to be minimal containing 2 methods: `send` and `on`. It emits 5 types of events: `notification`, `connect`, `close`, `networkChanged`, and `accountsChanged`. - -It is intended to be available on `window.ethereum`. +This EIP formalizes an Ethereum Provider JavaScript API for consistency across clients and applications. The provider is designed to be minimal and is intended to be available on `window.ethereum` for cross environment compatibility. ## API @@ -34,11 +30,11 @@ See the [available methods](https://github.com/ethereum/wiki/wiki/JSON-RPC#json- #### eth_requestAccounts -By default, the provider supplied to a new dapp has is a "read-only" provider with no accounts authenticated. +By default, the provider supplied to a new dapp has is a "read-only" provider with no accounts authenticated. See [EIP 1102: Opt-in account exposure](https://eips.ethereum.org/EIPS/eip-1102). To request accounts, call `ethereum.send('eth_requestAccounts')`. This will ask the user which account(s) they would like to authenticate to the dapp. -Promise resolves with an array of the account(s) addresses. +Promise resolves with an array of the enabled account(s) addresses. ### Events @@ -101,15 +97,6 @@ ethereum.on('accountsChanged', listener: (accounts: Array) => void): thi The event emits with `accounts`, an array of the accounts' addresses. -### isEIP1193 - -`isEIP1193` is a public read-only value on the provider to help distinguish itself. - -```js -ethereum.isEIP1193; -> true -``` - ## Examples ```js @@ -242,6 +229,8 @@ If no accounts are authenticated, the `eth_requestAccounts` method **MUST** ask The `eth_requestAccounts` method **MUST** resolve with an array of the account(s) addresses or reject with an `Error`. If the account(s) enabled by the provider change, the `accountsChanged` event **MUST** also emit. +For full specification of the `eth_requestAccounts` RPC method, see [EIP 1102: Opt-in account exposure](https://eips.ethereum.org/EIPS/eip-1102). + ### Events The provider **SHOULD** extend from `EventEmitter` to provide dapps flexibility in listening to events. In place of full `EventEmitter` functionality, the provider **MAY** provide as many methods as it can reasonably provide, but **MUST** provide at least `on`, `emit`, and `removeListener`. @@ -266,13 +255,9 @@ If the network the provider is connected to changes, the provider **MUST** emit If the accounts connected to the Ethereum Provider change at any time, the Ethereum Provider **MUST** send an event with the name `accountsChanged` with args `accounts: Array` containing the accounts' addresses. -### isEIP1193 - -The provider **MUST** define `public readonly ethereum.isEIP1193: Boolean` - ### web3.js Backwards Compatibility -If the implementing Ethereum Provider would like to be compatible with `web3.js` prior to `1.0.0-beta38`, it **MUST** provide two methods: `sendAsync(payload: Object, callback: (error: any, result: any) => void): void` and `isConnected(): Boolean`. +If the implementing Ethereum Provider would like to be compatible with `web3.js` prior to `1.0.0-beta38`, it **MUST** provide the method: `sendAsync(payload: Object, callback: (error: any, result: any) => void): void`. ### Error object and codes @@ -296,7 +281,6 @@ class EthereumProvider extends EventEmitter { super(); // Init storage - this._isConnected = false; this._nextJsonrpcId = 0; this._promises = {}; @@ -307,10 +291,6 @@ class EthereumProvider extends EventEmitter { window.addEventListener('message', this._handleJsonrpcMessage.bind(this)); } - static get isEIP1193() { - return true; - } - /* Methods */ send(method, params = []) { @@ -404,12 +384,10 @@ class EthereumProvider extends EventEmitter { } _emitConnect() { - this._isConnected = true; this.emit('connect'); } _emitClose(code, reason) { - this._isConnected = false; this.emit('close', code, reason); } @@ -438,10 +416,6 @@ class EthereumProvider extends EventEmitter { ); }); } - - isConnected() { - return this._isConnected; - } } ``` From a510ac916cf1c0b408e5b04468e98fff8f1824cb Mon Sep 17 00:00:00 2001 From: Kris Shinn Date: Sun, 24 Feb 2019 21:14:55 -0800 Subject: [PATCH 029/431] Automatically merged updates to draft EIP(s) 1767 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1767.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1767.md b/EIPS/eip-1767.md index e6e06d4f..21f5f195 100644 --- a/EIPS/eip-1767.md +++ b/EIPS/eip-1767.md @@ -96,7 +96,7 @@ type Transaction { # Nonce is the nonce of the account this transaction was generated with. nonce: Long! # Index is the index of this transaction in the parent block. This will - # be null if the transaction has not yet beenn mined. + # be null if the transaction has not yet been mined. index: Int # From is the account that sent this transaction - this will always be # an externally owned account. @@ -238,7 +238,7 @@ input CallData { data: Bytes } -# CallResult is the result of a local call operationn. +# CallResult is the result of a local call operation. type CallResult { # Data is the return data of the called contract. data: Bytes! @@ -306,7 +306,7 @@ type Query { call(data: CallData!, blockNumber: Long): CallResult # EstimateGas estimates the amount of gas that will be required for # successful execution of a transaction. If blockNumber is not specified, - # it defaults ot the most recent known block. + # it defaults to the most recent known block. estimateGas(data: CallData!, blockNumber: Long): Long! # Logs returns log entries matching the provided filter. logs(filter: FilterCriteria!): [Log!]! From 5463adcf50d57d84eb2b2cba4b1e3b8d18529b27 Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Mon, 25 Feb 2019 19:09:29 -0700 Subject: [PATCH 030/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 153 +++++++++++++++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 53 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 18213d3b..66a5cc45 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -5,9 +5,8 @@ status: Draft type: Standards Track category: Core author: Greg Colvin , Brooklyn Zelenka , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) -discussion to: https://github.com/ethereum/EIPs/issues/615 +discussion to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 created: 2016-12-10 -edited: 2019-18-2 --- ## Simple Summary @@ -27,10 +26,11 @@ Currently the EVM supports dynamic jumps, where the address to jump to is an arg Absent dynamic jumps code can be statically analyzed in linear time. Static analysis includes validation, and much of optimization, compilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. And absent dynamic jumps, and with proper subroutines the EVM is a better target for code generation from other languages, including * Solidity * Vyper -* LLVM—languages with an LLVM backend include C, C++, Common Lisp, D, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift. +* LLVM IR + * front ends include C, C++, Common Lisp, D, EVM, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift The result is that all of the following validations and optimizations can be done at deployment time with **linear** **`(n)`** **or** **near-linear** **`(n log n)`** **time complexity** -* The absence of most exception halting conditions can be validated. +* The absence of most exceptional halting states can be validated. * The maximum use of resources can be sometimes be calculated. * Bytecode can be compiled to machine code. * Compilation can optimize use of smaller registers. @@ -38,23 +38,36 @@ The result is that all of the following validations and optimizations can be don Note that near-linear `(n log n)` time complexity is essential. Otherwise, specially crafted contracts can be used as attack vectors against any validations and optimizations. +Especially important is efficient translation to and from eWasm. To that end we maintain a close correspondence between EVM and eWasm operations. + +| Wasm | EIP-615 | +| -------- | -------- | +| br | JUMPTO | +| br_if | JUMPIF | +| br_table | JUMPV | +| call | JUMPSUB | +| call_indirect | JUMPSUBV | +| return | RETURN | +| local.get | GETLOCAL | +| local.put | PUTLOCAL | +| tables | DATA | + ## Specification ### Proposal -We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. +We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. In particular, it must remain possible to compile Solidity and Vyper code to EVM bytecode, and EVM bytecode to eWasm code, with no significant loss of performance or increase in gas price. #### Preliminaries These forms -* `INSTRUCTION x,` -* `INSTRUCTION n,` +* `INSTRUCTION` +* `INSTRUCTION x` * `INSTRUCTION x, y` -* `INSTRUCTION n, x ...` -name instructions with one, two, and two or more arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) +name instructions with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) -#### Primitives +#### Branches and Subroutines The two most important uses of `JUMP` and `JUMPI` are static jumps and return jumps. Conditional and unconditional static jumps are the mainstay of control flow. Return jumps are implemented as a dynamic jump to a return address pushed on the stack. With the combination of a static jump and a dynamic return jump you can—and Solidity does—implement subroutines. The problem is that static analysis cannot tell the one place the return jump is going, so it must analyze every possibility (a heavy analysis). @@ -74,44 +87,38 @@ jumps to an immediate subroutine address. * `RETURNSUB` returns from the current subroutine to the instruction following the JUMPSUB that entered it. -These five simple instructions form the primitives of the proposal. +#### Switches and Virtual Functions -#### Data - -In order to validate subroutines in linear time, EVM bytecode must be sequentially scanned matching jumps to their destinations. Since creation code must contain the runtime code as data, that code might not correctly validate in the creation context and also does not have to be validated prior to the execution of the creation code. There needs to be a way to place data into the bytecode that will be skipped over and not validated. Such data may prove useful for other purposes as well. - -* `BEGINDATA` -specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. - -#### Indirect Jumps - -The primitive operations provide for static jumps. Dynamic jumps are also used for ``O(1)`` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. +Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. -* `JUMPV n, jumpdest ...` -jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode. If the index is greater than or equal to `n - 1` the last (default) offset is used. +* `JUMPV n, jump_targets` +jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the BEGINDATA bytecode as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs. -* `JUMPSUBV n, beginsub ...` -jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline in the bytecode, MSB-first. If the index is greater than or equal to `n - 1` the last (default) offset is used. - -`JUMPV` and `JUMPSUBV` are not strictly necessary. They provide `O(1)` operations that can be replaced by `O(n)` or `O(log n)` EVM code using static jumps, but that code will be slower, larger and use more gas for things that can and should be fast, small, and cheap, and that are directly supported in WASM with br_table and call_indirect. +* `JUMPSUBV n, jump_targets` +jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the DATA bytecode, as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. #### Variable Access -These operations provide convenient access to subroutine parameters and other variables at fixed stack offsets within a subroutine. +These operations provide convenient access to subroutine parameters and local variables at fixed stack offsets within a subroutine. Otherwise only sixteen variables can be directly addressed. * `PUTLOCAL n` -Pops the top value on the stack and copies it to local variable `n`[^putlocal_n]. -[^putlocal_n]: The `n` of stack items below the frame pointer to put a value at. - -* `GETLOCAL n` -Pushes the value of local variable `n`[^getlocal_n] on the stack. -[^getlocal_n]: The `n` of stack items below the frame pointer to get a value from. +Pops the stack to the local variable `n`. -Local variable `n` is the nth stack item below the frame pointer—`FP[-n]` as defined below. +* `GETLOCAL n` +Pushes the local variable `n` onto the stack. + +Local variable `n` is the nth stack item below the frame pointer, as defined below. + +#### Data + +There needs to be a way to place unreachable data into the bytecode that will be skipped over and not validated. Indirect jump tables will not be valid code. Initialization code must create runtime code from data that might not be valid code. And unreachable data might prove useful to programs for other purposes. + +* `BEGINDATA` +specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. ### Semantics @@ -123,11 +130,12 @@ Jumps to and returns from subroutines are described here in terms of We will adopt the following conventions to describe the machine state: * The _program counter_ `PC` is (as usual) the byte offset of the currently executing instruction. * The _stack pointer_ `SP` corresponds to the [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf)'s substate `s` of the machine state. - * The _stack pointer_ addresses the current top of the stack of data values, where new items are pushed. + * `SP[0]` is where a new item is can be pushed on the stack. + * `SP[1]` is the first item on the stack, which can be popped off the stack. * The stack grows towards lower addresses. -* The _frame pointer_ `FP` is set to `SP + n_args` at entry to the currently executing subroutine. -* The _stack items_ between the frame pointer and the current stack pointer are called the _frame_. -* The current number of items in the frame, `FP - SP`, is the _frame size_. +* The _frame pointer_ `FP` is set to `SP + n_args` at entry to the currently executing subroutine. + * The _stack items_ between the frame pointer and the current stack pointer are called the _frame_. + * The current number of items in the frame, `FP - SP`, is the _frame size_. Defining the frame pointer so as to include the arguments is unconventional, but better fits our stack semantics and simplifies the remainder of the proposal. @@ -142,33 +150,72 @@ Execution of a subroutine begins with `JUMPSUB` or `JUMPSUBV`, which * thus suspending execution of the current subroutine, * sets `FP` to `SP + n_args`, and * sets `PC` to the specified `BEGINSUB` address - * thus beginning execution of the new subroutine - * the _main_ routine is not addressable by `JUMPSUB` instructions + * thus beginning execution of the new subroutine. -Execution of a subroutine is suspended during and resumed after execution of nested subroutines, and ends upon encountering a `RETURNSUB`, which +The _main_ routine is not addressable by `JUMPSUB` instructions. Execution of a subroutine is suspended during and resumed after execution of nested subroutines, and ends upon encountering a `RETURNSUB`, which * sets `FP` to the top of the virtual frame stack and pops the stack, +* sets `SP` to `FP + n_results`, * sets `PC` to top of the return stack and pops the stack, and * advances `PC` to the next instruction -thus resuming execution of the enclosing subroutine or _main_ program. -A `STOP` or `RETURN` also ends the execution of a subroutine. +thus resuming execution of the enclosing subroutine or _main_ program. A `STOP` or `RETURN` also ends the execution of a subroutine. -For example, after a `JUMPSUB` to a `BEGINSUB 2, 0` like this +For example, starting from this stack, +``` +_________________ + | locals 20 <- FP +frame | 21 +______|___________ 22 + <- SP +``` +and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` ``` PUSH 10 PUSH 11 -JUMPSUB _beginsub_ -PUSH 12 -PUSH 13 +JUMPSUB beginsub +``` +and initializing three local variables +``` +PUSH 99 +PUSH 98 +PUSH 97 ``` the stack looks like this ``` -10 <- FP -11 -12 -13 - <- SP + 20 + 21 +__________________ 22 + | arguments 10 <- FP +frame |___________ 11 + | locals 99 + | 98 +______|___________ 97 + <- SP +``` +After some amount of computation the stack could look like this +``` + 20 + 21 +__________________ 22 + | returns 44 <- FP + | 43 +frame |___________ 42 + | locals 13 + | 14 +______|___________ 15 + <- SP +``` +and after `RETURNSUB` would look like this +``` +_________________ + | locals 20 <- FP + | 21 +frame |___________ 22 + | returns 44 + | 43 +______|___________ 42 + <- SP ``` ### Validity From c942b7194ea99f5da3a5baed2eedadfd3052b20d Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Mon, 25 Feb 2019 20:21:07 -0700 Subject: [PATCH 031/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 66a5cc45..08fb7cb1 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -74,17 +74,21 @@ The two most important uses of `JUMP` and `JUMPI` are static jumps and return ju Static jumps are provided by * `JUMPTO jump_target` * `JUMPIF jump_target` + which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target` rather than an address on the stack. To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Brief descriptions follow, and full semantics are given below. * `BEGINSUB n_args, n_results` + marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. The subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode. * `JUMPSUB jump_target` + jumps to an immediate subroutine address. * `RETURNSUB` + returns from the current subroutine to the instruction following the JUMPSUB that entered it. #### Switches and Virtual Functions @@ -94,11 +98,13 @@ Dynamic jumps are also used for `O(1)` indirection: an address to jump to is sel Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. * `JUMPV n, jump_targets` + jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the BEGINDATA bytecode as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs. * `JUMPSUBV n, jump_targets` + jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the DATA bytecode, as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. #### Variable Access @@ -106,9 +112,11 @@ jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the These operations provide convenient access to subroutine parameters and local variables at fixed stack offsets within a subroutine. Otherwise only sixteen variables can be directly addressed. * `PUTLOCAL n` + Pops the stack to the local variable `n`. * `GETLOCAL n` + Pushes the local variable `n` onto the stack. Local variable `n` is the nth stack item below the frame pointer, as defined below. @@ -118,6 +126,7 @@ Local variable `n` is the nth stack item below the frame pointer, as defined bel There needs to be a way to place unreachable data into the bytecode that will be skipped over and not validated. Indirect jump tables will not be valid code. Initialization code must create runtime code from data that might not be valid code. And unreachable data might prove useful to programs for other purposes. * `BEGINDATA` + specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. ### Semantics @@ -133,7 +142,7 @@ We will adopt the following conventions to describe the machine state: * `SP[0]` is where a new item is can be pushed on the stack. * `SP[1]` is the first item on the stack, which can be popped off the stack. * The stack grows towards lower addresses. -* The _frame pointer_ `FP` is set to `SP + n_args` at entry to the currently executing subroutine. +* The _frame pointer_ `FP` is set to `SP + n_args` at entry to the currently executing subroutine. * The _stack items_ between the frame pointer and the current stack pointer are called the _frame_. * The current number of items in the frame, `FP - SP`, is the _frame size_. From 38724ef728f583b06aa097e67f8f6b1a31e56b44 Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Mon, 25 Feb 2019 21:24:28 -0700 Subject: [PATCH 032/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 69 ++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 08fb7cb1..3e176f2e 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -61,35 +61,38 @@ We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and pro #### Preliminaries These forms -* `INSTRUCTION` -* `INSTRUCTION x` -* `INSTRUCTION x, y` +> `INSTRUCTION` +> +> `INSTRUCTION x` +> +> `INSTRUCTION x, y` -name instructions with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) +name an `INSTRUCTION` with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) #### Branches and Subroutines The two most important uses of `JUMP` and `JUMPI` are static jumps and return jumps. Conditional and unconditional static jumps are the mainstay of control flow. Return jumps are implemented as a dynamic jump to a return address pushed on the stack. With the combination of a static jump and a dynamic return jump you can—and Solidity does—implement subroutines. The problem is that static analysis cannot tell the one place the return jump is going, so it must analyze every possibility (a heavy analysis). Static jumps are provided by -* `JUMPTO jump_target` -* `JUMPIF jump_target` - -which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target` rather than an address on the stack. +> `JUMPTO jump_target` +> +> `JUMPIF jump_target` +> +> which are the same as `JUMP` and `JUMPI` except that they jump to an immediate `jump_target` rather than an address on the stack. To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Brief descriptions follow, and full semantics are given below. -* `BEGINSUB n_args, n_results` +> `BEGINSUB n_args, n_results` +> +> marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. The subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode. -marks the **single** entry to a subroutine. `n_args` items are taken off of the stack at entry to, and `n_results` items are placed on the stack at return from the subroutine. The subroutine ends at the next `BEGINSUB` instruction (or `BEGINDATA`, below) or at the end of the bytecode. +> `JUMPSUB jump_target` +> +> jumps to an immediate subroutine address. -* `JUMPSUB jump_target` - -jumps to an immediate subroutine address. - -* `RETURNSUB` - -returns from the current subroutine to the instruction following the JUMPSUB that entered it. +> `RETURNSUB` +> +>returns from the current subroutine to the instruction following the JUMPSUB that entered it. #### Switches and Virtual Functions @@ -97,37 +100,37 @@ Dynamic jumps are also used for `O(1)` indirection: an address to jump to is sel Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. -* `JUMPV n, jump_targets` - -jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the BEGINDATA bytecode as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. +> `JUMPV n, jump_targets` +> +> jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the BEGINDATA bytecode as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs. -* `JUMPSUBV n, jump_targets` - -jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the DATA bytecode, as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. +> `JUMPSUBV n, jump_targets` +> +>jumps to one of a vector of `n` `BEGINSUB` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the DATA bytecode, as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. #### Variable Access These operations provide convenient access to subroutine parameters and local variables at fixed stack offsets within a subroutine. Otherwise only sixteen variables can be directly addressed. -* `PUTLOCAL n` +> `PUTLOCAL n` +> +> Pops the stack to the local variable `n`. -Pops the stack to the local variable `n`. +> `GETLOCAL n` +> +> Pushes the local variable `n` onto the stack. -* `GETLOCAL n` - -Pushes the local variable `n` onto the stack. - -Local variable `n` is the nth stack item below the frame pointer, as defined below. +Local variable `n` is the nth stack item below the frame pointer, `FP[-n]`, as defined below. #### Data There needs to be a way to place unreachable data into the bytecode that will be skipped over and not validated. Indirect jump tables will not be valid code. Initialization code must create runtime code from data that might not be valid code. And unreachable data might prove useful to programs for other purposes. -* `BEGINDATA` - -specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. +> `BEGINDATA` +> +> specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. ### Semantics From 281e28362cc4f3a31700aa9e330e36b9070e5d75 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Wed, 27 Feb 2019 14:40:16 -0800 Subject: [PATCH 033/431] Automatically merged updates to draft EIP(s) 1328 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1328.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/EIPS/eip-1328.md b/EIPS/eip-1328.md index 4142fa96..63d61278 100644 --- a/EIPS/eip-1328.md +++ b/EIPS/eip-1328.md @@ -7,12 +7,11 @@ category: ERC status: Draft created: 2018-08-15 discussions-to: https://ethereum-magicians.org/t/wallet-connect-eip/850 -requires: 831 --- ## Simple Summary -A standard to create WalletConnect URIs for establishing connections between wallets and applications. +A standard to create WalletConnect URIs to initiate connections between applications and wallets. ## Abstract @@ -22,33 +21,33 @@ This standard defines how the data to connect some application and a wallet can ### Syntax -Function call URIs follow the ERC-831 URI format, with the following parameters: +WalletConnect request URI with the following parameters: - request = "ethereum" ":" [ "wc-" ]sessionId [ "@" version ][ "?" parameters ] - sessionId = STRING + request = "wc" ":" topic [ "@" version ][ "?" parameters ] + topic = STRING version = 1*DIGIT parameters = parameter *( "&" parameter ) parameter = key "=" value - key = "name" / "bridge" / "symKey" - value = NUMBER / STRING + key = "bridge" / "key" + value = STRING ### Semantics -Required parameters are dependent on the WalletConnect standard version which currently is specified to only include mobile-to-desktop connection sessions which only require `name` which describes the dapp name, `bridge` which includes the bridge URL, `symKey` which includes the symmetric key in base64. +Required parameters are dependent on the Walletconnect protocol version which currently includes the `key`, hex string of symmetric key, and `bridge`, encoded url of the bridge used for establishing the connection. ### Example ``` -ethereum:wc-8a5e5bdc-a0e4-4702-ba63-8f1a5655744f@1?name=DappExample&bridge=https://bridge.example.com&symKey=KzpSTk1pezg5eTJRNmhWJmoxdFo6UDk2WlhaOyQ5N0U= +wc:8a5e5bdc-a0e4-4702-ba63-8f1a5655744f@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=41791102999c339c844880b23950704cc43aa840f3739e365323cda4dfa89e7a ``` ## Rationale -The need for this ERC stems from the discussion to move away from JSON format used in current beta version of the WalletConnect standard which makes for very inneficient parsing of the intent of the QR code, making it easier to create better QR code parsers APIs for Wallets to implement for other compatible EIPs using the ERC-831 URI format for Ethereum. Also by using a URI instead of a JSON inside the QR-Code the Android Intent system can be leveraged. +The need for this ERC stems from the discussion to move away from JSON format used in the alpha version of the WalletConnect protocol which makes for very inneficient parsing of the intent of the QR code, making it easier to create better QR code parsers APIs for Wallets to implement. Also by using a URI instead of a JSON inside the QR-Code the Android Intent system can be leveraged. ## References -1. ERC-831, http://eips.ethereum.org/EIPS/eip-831 +1. WalletConnect Technical Specification, https://docs.walletconnect.org/tech-spec ## Copyright From c644af1925d500319d8a8de3c140d9d603a01e1f Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Thu, 28 Feb 2019 12:22:37 -0700 Subject: [PATCH 034/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 75 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 3e176f2e..97c4aa12 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,7 +4,7 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Brooklyn Zelenka , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) +author: Greg Colvin , Brooklyn Zelenka <@expede> , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) discussion to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 created: 2016-12-10 --- @@ -21,13 +21,13 @@ We also propose to validate—in linear time—that EVM contracts correctly use ## Motivation -Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since every jump can potentially be to any jump destination in the code, the number of possible paths through the code goes up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses. +Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since many jumps can potentially be to any jump destination in the code, the number of possible paths through the code can go up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses. Absent dynamic jumps code can be statically analyzed in linear time. Static analysis includes validation, and much of optimization, compilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. And absent dynamic jumps, and with proper subroutines the EVM is a better target for code generation from other languages, including * Solidity * Vyper * LLVM IR - * front ends include C, C++, Common Lisp, D, EVM, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift + * front ends include C, C++, Common Lisp, D, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift The result is that all of the following validations and optimizations can be done at deployment time with **linear** **`(n)`** **or** **near-linear** **`(n log n)`** **time complexity** * The absence of most exceptional halting states can be validated. @@ -38,7 +38,13 @@ The result is that all of the following validations and optimizations can be don Note that near-linear `(n log n)` time complexity is essential. Otherwise, specially crafted contracts can be used as attack vectors against any validations and optimizations. -Especially important is efficient translation to and from eWasm. To that end we maintain a close correspondence between EVM and eWasm operations. +## Specification + +### Proposal + +We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. In particular, it must remain possible to compile Solidity and Vyper code to EVM bytecode, with no significant loss of performance or increase in gas price. + +Especially important is efficient translation to and from eWasm. To that end we maintain a close correspondence between eWasm instructions and proposed EVM instructions. | Wasm | EIP-615 | | -------- | -------- | @@ -50,24 +56,18 @@ Especially important is efficient translation to and from eWasm. To that end we | return | RETURN | | local.get | GETLOCAL | | local.put | PUTLOCAL | -| tables | DATA | - -## Specification - -### Proposal - -We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. In particular, it must remain possible to compile Solidity and Vyper code to EVM bytecode, and EVM bytecode to eWasm code, with no significant loss of performance or increase in gas price. +| tables | DATA | #### Preliminaries These forms -> `INSTRUCTION` +> *`INSTRUCTION`* > -> `INSTRUCTION x` +> *`INSTRUCTION x`* > -> `INSTRUCTION x, y` +> *`INSTRUCTION x, y`* -name an `INSTRUCTION` with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) +name an *`INSTRUCTION`* with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) #### Branches and Subroutines @@ -94,7 +94,7 @@ To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Br > >returns from the current subroutine to the instruction following the JUMPSUB that entered it. -#### Switches and Virtual Functions +#### Switches, Callbacks, and Virtual Functions Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. @@ -126,7 +126,7 @@ Local variable `n` is the nth stack item below the frame pointer, `FP[-n]`, as d #### Data -There needs to be a way to place unreachable data into the bytecode that will be skipped over and not validated. Indirect jump tables will not be valid code. Initialization code must create runtime code from data that might not be valid code. And unreachable data might prove useful to programs for other purposes. +There needs to be a way to place unreachable data into the bytecode that will be skipped over and not validated. Indirect jump vectors will not be valid code. Initialization code must create runtime code from data that might not be valid code. And unreachable data might prove useful to programs for other purposes. > `BEGINDATA` > @@ -214,8 +214,7 @@ __________________ 22 | 43 frame |___________ 42 | locals 13 - | 14 -______|___________ 15 +______|___________ 14 <- SP ``` and after `RETURNSUB` would look like this @@ -314,7 +313,7 @@ As described above, the approach was simply to deprecate the problematic dynamic Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. Compiled code can use native call instructions, greatly improving performance. Further optimizations include minimizing runtime checks for exceptions, condensing gas metering, and otherwise taking advantage of validated code wherever possible. A lightly tested reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) -## APPENDIX +## Appendix A ### Validation Validation comprises two tasks: @@ -375,9 +374,7 @@ Note that code like this is already run by EVMs to check dynamic jumps, includin #### Subroutine Validation -This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`[^subroutine_complexity]. - -[^subroutine_complexity]: The sum of the number of edges and number of verticies in the graph. +This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|): The sum of the number of edges and number of verticies in the graph. The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. @@ -470,6 +467,38 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t return true } ``` +## Appendix B +### EVM Analysis + +There is a large and growing ecosystem of researchers, authors, teachers, auditors, and analytic tools--providing software and services focused on the correctness and security of EVM code. A small saample is given here. + +#### Some Tools + +* [Contract Library](https://contract-library.com/) +* [EthereumJ](https://github.com/ethereum/ethereumj) +* [Exthereum](https://github.com/exthereum/blockchain) +* [Harmony](https://github.com/ether-camp/ethereum-harmony) +* [JEB](https://www.pnfsoftware.com/blog/ethereum-smart-contract-decompiler/) +* [Mythril](https://github.com/ConsenSys/mythril) +* [Securify](https://github.com/eth-sri/securify) +* [Skale](https://www.skalelabs.com/) +* [Status](https://status.im/) + +#### Some Papers + +* [A Formal Verification Tool for Ethereum VM Bytecode](https://www.google.com/url?q=http://fsl.cs.illinois.edu/FSL/papers/2018/park-zhang-saxena-daian-rosu-2018-fse/park-zhang-saxena-daian-rosu-2018-fse-public.pdf) +* [A Lem formalization of EVM and some Isabelle/HOL proofs](https://github.com/pirapira/eth-isabelle) +* [A survey of attacks on Ethereum smart contracts](https://eprint.iacr.org/2016/1007.pdf) +* [Defining the Ethereum Virtual Machine for Interactive Theorem Provers](https://www.google.com/url?q=http://fc17.ifca.ai/wtsc/Defining%2520the%2520Ethereum%2520Virtual%2520Machine%2520for%2520Interactive%2520Theorem%2520Provers.pdf) +* [Ethereum 2.0 Specifications](https://github.com/ethereum/eth2.0-specs) +* [Formal Verification of Smart Contracts](https://www.cs.umd.edu/~aseem/solidetherplas.pdf) +* [JelloPaper: Human Readable Semantics of EVM in K](https://jellopaper.org/) +* [KEVM: A Complete Semantics of the Ethereum Virtual Machine.](https://www.ideals.illinois.edu/bitstream/handle/2142/97207/hildenbrandt-saxena-zhu-rodrigues-guth-daian-rosu-2017-tr.pdf) +* [Making Smart Contracts Smarter](https://eprint.iacr.org/2016/633.pdf) +* [Securify: Practical Security Analysis of Smart Contracts](https://arxiv.org/pdf/1806.01143.pdf) +* [The Thunder Protocol](https://docs.thundercore.com/thunder-whitepaper.pdf) +* [Towards Verifying Ethereum Smart Contract Bytecode in Isabelle/HOL](https://ts.data61.csiro.au/publications/csiro_full_text//Amani_BBS_18.pdf) + ## Copyright From fde32dfd6b24bac7bfabf6c1ebe3f5a603d5ff4c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 28 Feb 2019 20:06:29 +0000 Subject: [PATCH 035/431] Mark Constantinople and all its references Final (#1787) --- EIPS/eip-1013.md | 2 +- EIPS/eip-1014.md | 2 +- EIPS/eip-1052.md | 2 +- EIPS/eip-1234.md | 2 +- EIPS/eip-1283.md | 2 +- EIPS/eip-145.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-1013.md b/EIPS/eip-1013.md index 2aa87d14..ce2c9bed 100644 --- a/EIPS/eip-1013.md +++ b/EIPS/eip-1013.md @@ -3,7 +3,7 @@ eip: 1013 title: "Hardfork Meta: Constantinople" author: Nick Savers (@nicksavers) type: Meta -status: Draft +status: Final created: 2018-04-20 requires: 145, 1014, 1052, 1234, 1283 --- diff --git a/EIPS/eip-1014.md b/EIPS/eip-1014.md index f2c0575c..5b667bfa 100644 --- a/EIPS/eip-1014.md +++ b/EIPS/eip-1014.md @@ -4,7 +4,7 @@ title: Skinny CREATE2 author: Vitalik Buterin (@vbuterin) category: Core type: Standards Track -status: Accepted +status: Final created: 2018-04-20 --- diff --git a/EIPS/eip-1052.md b/EIPS/eip-1052.md index 2374eec4..cce394ec 100644 --- a/EIPS/eip-1052.md +++ b/EIPS/eip-1052.md @@ -3,7 +3,7 @@ eip: 1052 title: EXTCODEHASH opcode author: Nick Johnson , Paweł Bylica discussions-to: https://ethereum-magicians.org/t/extcodehash-opcode/262 -status: Accepted +status: Final type: Standards Track category: Core created: 2018-05-02 diff --git a/EIPS/eip-1234.md b/EIPS/eip-1234.md index e9767df9..5cf44307 100644 --- a/EIPS/eip-1234.md +++ b/EIPS/eip-1234.md @@ -5,7 +5,7 @@ author: Afri Schoedon (@5chdn) discussions-to: https://ethereum-magicians.org/t/eip-1234-constantinople-difficulty-bomb-delay-and-block-reward-adjustment/833 type: Standards Track category: Core -status: Accepted +status: Final created: 2018-07-19 --- diff --git a/EIPS/eip-1283.md b/EIPS/eip-1283.md index 52838fe7..da763300 100644 --- a/EIPS/eip-1283.md +++ b/EIPS/eip-1283.md @@ -3,7 +3,7 @@ eip: 1283 title: Net gas metering for SSTORE without dirty maps author: Wei Tang (@sorpaas) discussions-to: https://github.com/sorpaas/EIPs/issues/1 -status: Accepted +status: Final type: Standards Track category: Core created: 2018-08-01 diff --git a/EIPS/eip-145.md b/EIPS/eip-145.md index 2fd46574..e3cc6591 100644 --- a/EIPS/eip-145.md +++ b/EIPS/eip-145.md @@ -4,7 +4,7 @@ title: Bitwise shifting instructions in EVM author: Alex Beregszaszi (@axic), Paweł Bylica type: Standards Track category: Core -status: Accepted +status: Final created: 2017-02-13 --- From 958c4c09194c19646b996cc98217d77f78a23d78 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 28 Feb 2019 23:55:15 +0000 Subject: [PATCH 036/431] Add ethereum.org blog post about constantinople (#1790) --- EIPS/eip-1013.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1013.md b/EIPS/eip-1013.md index ce2c9bed..89767d4f 100644 --- a/EIPS/eip-1013.md +++ b/EIPS/eip-1013.md @@ -28,7 +28,8 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Cons ## References -The list above includes the EIPs discussed as candidates for Constantinople at the All Core Dev [Constantinople Session #1](https://github.com/ethereum/pm/issues/55). See also [Constantinople Progress Tracker](https://github.com/ethereum/pm/wiki/Constantinople-Progress-Tracker). +1. The list above includes the EIPs discussed as candidates for Constantinople at the All Core Dev [Constantinople Session #1](https://github.com/ethereum/pm/issues/55). See also [Constantinople Progress Tracker](https://github.com/ethereum/pm/wiki/Constantinople-Progress-Tracker). +2. https://blog.ethereum.org/2019/02/22/ethereum-constantinople-st-petersburg-upgrade-announcement/ ## Copyright From 400841d948fcd76e099a6bee03b0d5ca1f751d4f Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 1 Mar 2019 10:36:04 +0100 Subject: [PATCH 037/431] Create eip-1716.md (#1769) Co-Authored-By: MariusVanDerWijden --- EIPS/eip-1716.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 EIPS/eip-1716.md diff --git a/EIPS/eip-1716.md b/EIPS/eip-1716.md new file mode 100644 index 00000000..a0d0d10b --- /dev/null +++ b/EIPS/eip-1716.md @@ -0,0 +1,38 @@ +--- +eip: 1716 +title: "Hardfork Meta: Petersburg" +author: Afri Schoedon (@5chdn), Marius van der Wijden (@MariusVanDerWijden) +type: Meta +status: Final +created: 2019-01-21 +requires: 1013, 1283 +--- + +## Abstract + +This meta-EIP specifies the changes included in the Ethereum hardfork that removes [EIP-1283](./eip-1283.md) from [Constantinople](./eip-1013.md). + +## Specification + +- Codename: Petersburg +- Aliases: St. Petersfork, Peter's Fork, Constantinople Fix +- Activation: + - `Block >= 7_280_000` on the Ethereum mainnet + - `Block >= 4_939_394` on the Ropsten testnet + - `Block >= 10_255_201` on the Kovan testnet + - `Block >= 9_999_999` on the Rinkeby testnet + - `Block >= 0` on the Görli testnet +- Removed EIPs: + - [EIP 1283](./eip-1283.md): Net gas metering for SSTORE without dirty maps + +If `Petersburg` and `Constantinople` are applied at the same block, `Petersburg` takes precedence: with the net effect of EIP-1283 being _disabled_. + +If `Petersburg` is defined with an earlier block number than `Constantinople`, then there is _no immediate effect_ from the `Petersburg` fork. However, when `Constantinople` is later activated, EIP-1283 should be _disabled_. + +## References + +The list above includes the EIPs that had to be removed from Constantinople due to a [potential reentrancy attack vector](https://medium.com/chainsecurity/constantinople-enables-new-reentrancy-attack-ace4088297d9). Removing this was agreed upon at the [All-Core-Devs call #53 in January 2019](https://github.com/ethereum/pm/issues/70). + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 860dd38347b5c3a99cdbad6d135b01df72835d6a Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 1 Mar 2019 11:37:00 +0000 Subject: [PATCH 038/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index a76073d2..5236fb84 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -5,6 +5,7 @@ author: Alex Beregszaszi (@axic), Afri Schoedon (@5chdn) type: Meta status: Draft created: 2019-01-04 +requires: 1716 --- ## Abstract @@ -17,6 +18,10 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - Activation: TBD - Included EIPs: TBD +## References + +TBA + ## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 70f30f66561ec84e78bdcbb631333e6fb283793a Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Fri, 1 Mar 2019 08:41:08 -0700 Subject: [PATCH 039/431] Get Brooke's email right this time --- EIPS/eip-615.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 97c4aa12..3fec51a1 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,7 +4,7 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Brooklyn Zelenka <@expede> , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) +author: Greg Colvin , Brooklyn Zelenka , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) discussion to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 created: 2016-12-10 --- From 6a3633beedaae0f03e7e08fe22f22a428e20431e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 1 Mar 2019 18:08:18 +0000 Subject: [PATCH 040/431] Automatically merged updates to draft EIP(s) 902 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-902.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-902.md b/EIPS/eip-902.md index f81a1775..648f8298 100644 --- a/EIPS/eip-902.md +++ b/EIPS/eip-902.md @@ -7,7 +7,7 @@ type: Standards Track category: ERC status: Draft created: 2018-02-14 -require: 1066 +requires: 1066 --- # Simple Summary From 1a9ff713b056e3c2e57fa16cfce7cbc0faf29900 Mon Sep 17 00:00:00 2001 From: Albert Date: Fri, 1 Mar 2019 19:28:30 +0100 Subject: [PATCH 041/431] Fix typo (#1746) --- EIPS/eip-721.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-721.md b/EIPS/eip-721.md index a1fd5780..7a344681 100644 --- a/EIPS/eip-721.md +++ b/EIPS/eip-721.md @@ -405,7 +405,7 @@ XXXXERC721, by William Entriken -- a scalable example implementation **Issues** 1. The Original ERC-721 Issue. https://github.com/ethereum/eips/issues/721 -1. Solidity Issue \#2330 -- Interface Functions are Axternal. https://github.com/ethereum/solidity/issues/2330 +1. Solidity Issue \#2330 -- Interface Functions are External. https://github.com/ethereum/solidity/issues/2330 1. Solidity Issue \#3412 -- Implement Interface: Allow Stricter Mutability. https://github.com/ethereum/solidity/issues/3412 1. Solidity Issue \#3419 -- Interfaces Can't Inherit. https://github.com/ethereum/solidity/issues/3419 1. Solidity Issue \#3494 -- Compiler Incorrectly Reasons About the `selector` Function. https://github.com/ethereum/solidity/issues/3494 From 3c15ef57d69645129c6de135e3e394575dc17b56 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 1 Mar 2019 18:31:33 +0000 Subject: [PATCH 042/431] Add activation block numbers to Constantinople (#1792) --- EIPS/eip-1013.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1013.md b/EIPS/eip-1013.md index 89767d4f..d7922af7 100644 --- a/EIPS/eip-1013.md +++ b/EIPS/eip-1013.md @@ -17,8 +17,10 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Cons - Codename: Constantinople - Aliases: Metropolis/Constantinople, Metropolis part 2 - Activation: - - Block >= TBD on the Ethereum mainnet - - Block >= 4,230,000 on the Ropsten testnet + - `Block >= 7_280_000` on the Ethereum mainnet + - `Block >= 4,230,000` on the Ropsten testnet + - `Block >= 9_200_000` on the Kovan testnet + - `Block >= 3_660_663` on the Rinkeby testnet - Included EIPs: - [EIP 145](./eip-145.md): Bitwise shifting instructions in EVM - [EIP 1014](./eip-1014.md): Skinny CREATE2 From 2007c98c3c859c32f46c1a74cc8f2b293fb1e337 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Fri, 1 Mar 2019 14:03:41 -0500 Subject: [PATCH 043/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 3fec51a1..692a6c3c 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,7 +4,7 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Brooklyn Zelenka , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) +author: Greg Colvin , Brooklyn Zelenka (@expede), Paweł Bylica (@chfast), Christian Reitwiessner (@chriseth) discussion to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 created: 2016-12-10 --- From c0e4e93b91a52bce85db0d9d5f91f2f7eb30f8b5 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 1 Mar 2019 19:08:49 +0000 Subject: [PATCH 044/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 692a6c3c..a6906ede 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -5,7 +5,7 @@ status: Draft type: Standards Track category: Core author: Greg Colvin , Brooklyn Zelenka (@expede), Paweł Bylica (@chfast), Christian Reitwiessner (@chriseth) -discussion to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 +discussions-to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 created: 2016-12-10 --- From ab198334ea7cf901950548a45c9612226a063e7b Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 1 Mar 2019 20:06:28 +0000 Subject: [PATCH 045/431] Automatically merged updates to draft EIP(s) 1706 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1706.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1706.md b/EIPS/eip-1706.md index affd8195..c3f7ca0f 100644 --- a/EIPS/eip-1706.md +++ b/EIPS/eip-1706.md @@ -4,10 +4,10 @@ title: Disable SSTORE with gasleft lower than call stipend author: Alex Forshtat (alex@tabookey.com), Yoav Weiss (yoav@tabookey.com) discussions-to: https://github.com/alex-forshtat-tbk/EIPs/issues/1 status: Draft -type: Standards Track (Core, Networking, Interface, ERC) -category (*only required for Standard Track): Core +type: Standards Track +category: Core created: 2019-01-15 -requires (*optional): 1283 +requires: 1283 --- From 9a089a819dcaadde65f875eca68615264c424784 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 2 Mar 2019 07:39:52 +0000 Subject: [PATCH 046/431] Fix header of EIP1081 (#1798) --- EIPS/eip-1081.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/EIPS/eip-1081.md b/EIPS/eip-1081.md index 5cc921fd..d5a7556c 100644 --- a/EIPS/eip-1081.md +++ b/EIPS/eip-1081.md @@ -1,13 +1,13 @@ --- eip: 1081 -Title: Standard Bounties -Authors: Mark Beylin , Kevin Owocki , Ricardo Guilherme Schmidt (@3esmit) -Discussions-to: https://gitter.im/bounties-network/Lobby -Status: Draft -Type: Standards Track -Category: ERC -Created: 2018-05-14 -Requires: 20 +title: Standard Bounties +author: Mark Beylin , Kevin Owocki , Ricardo Guilherme Schmidt (@3esmit) +discussions-to: https://gitter.im/bounties-network/Lobby +status: Draft +type: Standards Track +category: ERC +created: 2018-05-14 +requires: 20 --- ## Simple Summary From 8f98d5b7dcf9ea96db8f5dfaf1c9aabf840d2fd0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sat, 2 Mar 2019 07:40:43 +0000 Subject: [PATCH 047/431] Fix headers of EIP926/927 (#1801) --- EIPS/eip-926.md | 2 +- EIPS/eip-927.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-926.md b/EIPS/eip-926.md index 5e210373..b8497376 100644 --- a/EIPS/eip-926.md +++ b/EIPS/eip-926.md @@ -6,7 +6,7 @@ type: Standards Track category: ERC status: Draft created: 2018-03-12 -dependencies: 165 +requires: 165 --- ## Abstract diff --git a/EIPS/eip-927.md b/EIPS/eip-927.md index 4087813b..b3691009 100644 --- a/EIPS/eip-927.md +++ b/EIPS/eip-927.md @@ -6,7 +6,7 @@ type: Standards Track category: ERC status: Draft created: 2018-03-12 -dependencies: 926 +requires: 926 --- ## Abstract From cac8a33f7f0cada488afd85d3ab8fa5d195642af Mon Sep 17 00:00:00 2001 From: Leo Arias Date: Sat, 2 Mar 2019 01:51:49 -0600 Subject: [PATCH 048/431] Fix typo (#1770) --- EIPS/eip-1014.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1014.md b/EIPS/eip-1014.md index 5b667bfa..0aa0aaea 100644 --- a/EIPS/eip-1014.md +++ b/EIPS/eip-1014.md @@ -52,7 +52,7 @@ With [EIP 161](https://eips.ethereum.org/EIPS/eip-161) > Account creation transactions and the CREATE operation SHALL, prior to the execution of the initialisation code, increment the nonce over and above its normal starting value by one -This means that if a contract is created in a transaction, the `nonce` is immediately non-zero, with the side-effect that a collision within the same transaction will always fail -- even if it's carried out from the `init_code` itself/ +This means that if a contract is created in a transaction, the `nonce` is immediately non-zero, with the side-effect that a collision within the same transaction will always fail -- even if it's carried out from the `init_code` itself. It should also be noted that `SELFDESTRUCT` has no immediate effect on `nonce` or `code`, thus a contract cannot be destroyed and recreated within one transaction. From 55ff244e4a3067a1bb77d34e5b603ee1b91f1de5 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Sat, 2 Mar 2019 08:44:31 -0700 Subject: [PATCH 049/431] Bring over current copy of IfDefElse spec. (#1804) --- EIPS/eip-1057.md | 532 +++++++++++++++++++------------- assets/eip-1057/test-vectors.md | 457 +++++++++++++++++++++++++++ 2 files changed, 776 insertions(+), 213 deletions(-) create mode 100644 assets/eip-1057/test-vectors.md diff --git a/EIPS/eip-1057.md b/EIPS/eip-1057.md index e85d218e..2fc96e34 100644 --- a/EIPS/eip-1057.md +++ b/EIPS/eip-1057.md @@ -11,55 +11,100 @@ created: 2018-05-02 ## Simple Summary -The following is a proposal for an alternate proof-of-work algorithm - **“ProgPoW”** - tuned for commodity hardware in order to close the efficiency gap available to specialized ASICs. +A new Proof-of-Work algorithm to replace Ethash that utilizes almost all parts of commodity GPUs. ## Abstract -The security of proof-of-work is built on a fair, randomized lottery where miners with similar resources have a similar chance of generating the next block. - -For Ethereum - a community based on widely distributed commodity hardware - specialized ASICs enable certain participants to gain a much greater chance of generating the next block, and undermine the distributed security. - -ASIC-resistance is a misunderstood problem. FPGAs, GPUs and CPUs can themselves be considered ASICs. Any algorithm that executes on a commodity ASIC can have a specialized ASIC made for it; most existing algorithms provide opportunities that reduce power usage and cost. Thus, the proper question to ask when solving ASIC-resistance is “how much more efficient will a specialized ASIC be, in comparison with commodity hardware?” - -EIP presents an algorithm that is tuned for commodity GPUs where there is minimal opportunity for ASIC specialization. This prevents specialized ASICs without resorting to a game of whack-a-mole where the network changes algorithms every few months. +ProgPoW is a proof-of-work algorithm designed to close the efficency gap available to specialized ASICs. It utilizes almost all parts of commodity hardware (GPUs), and comes pre-tuned for the most common hardware utilized in the Ethereum network. ## Motivation -Until Ethereum transitions to a pure proof-of-stake model, proof-of-work will continue to be a part of the security of the network - whether it’s adapted into a hybrid model (as is the case of Casper FFG), or adopted by a hard fork. +Ever since the first bitcoin mining ASIC was released, many new Proof of Work algorithms have been created with the intention of being “ASIC-resistant”. The goal of “ASIC-resistance” is to resist the centralization of PoW mining power such that these coins couldn’t be so easily manipulated by a few players. -Ethash allows for the creation of an ASIC that is roughly twice as efficient as a commodity GPU. Ethash’s memory accesses are paired with a very small amount of fixed compute. Most of a GPU’s capacity and complexity sits idle, wasting power, while waiting for DRAM accesses. A specialized ASIC can implement a much smaller (and cheaper) compute engine that burns much less power. +This document presents an overview of the algorithm and examines what it means to be “ASIC-resistant.” Next, we compare existing PoW designs by analyzing how each algorithm executes in hardware. Finally, we present the detailed implementation by walking through the code. -As miner rewards are reduced with Casper FFG, it will remain profitable to mine on a specialized ASIC long after GPUs have exited the network. This will make it easier for an entity that has access to private ASICs to stage a 51% attack on the Ethereum network. +### ProgPoW Overview +The design goal of ProgPoW is to have the algorithm’s requirements match what is available on commodity GPUs: If the algorithm were to be implemented on a custom ASIC there should be little opportunity for efficiency gains compared to a commodity GPU. + +The main elements of the algorithm are: +* Changes keccak_f1600 (with 64-bit words) to keccak_f800 (with 32-bit words) to reduce impact on total power +* Increases mix state. +* Adds a random sequence of math in the main loop. +* Adds reads from a small, low-latency cache that supports random addresses. +* Increases the DRAM read from 128 bytes to 256 bytes. + +The random sequence changes every `PROGPOW_PERIOD` (50 blocks or about 12.5 minutes). When mining source code is generated for the random sequence and compiled on the host CPU. The GPU will execute the compiled code where what math to perform and what mix state to use are already resolved. + +While a custom ASIC to implement this algorithm is still possible, the efficiency gains available are minimal. The majority of a commodity GPU is required to support the above elements. The only optimizations available are: +* Remove the graphics pipeline (displays, geometry engines, texturing, etc) +* Remove floating point math +* A few ISA tweaks, like instructions that exactly match the merge() function + +These would result in minimal, roughly 1.1-1.2x, efficiency gains. This is much less than the 2x for Ethash or 50x for Cryptonight. + +### Rationale for PoW on Commodity Hardware +With the growth of large mining pools, the control of hashing power has been delegated to the top few pools to provide a steadier economic return for small miners. While some have made the argument that large centralized pools defeats the purpose of “ASIC resistance,” it’s important to note that ASIC based coins are even more centralized for several reasons. + +1. No natural distribution: There isn’t an economic purpose for ultra-specialized hardware outside of mining and thus no reason for most people to have it. +2. No reserve group: Thus, there’s no reserve pool of hardware or reserve pool of interested parties to jump in when coin price is volatile and attractive for manipulation. +3. High barrier to entry: Initial miners are those rich enough to invest capital and ecological resources on the unknown experiment a new coin may be. Thus, initial coin distribution through mining will be very limited causing centralized economic bias. +4. Delegated centralization vs implementation centralization: While pool centralization is delegated, hardware monoculture is not: only the limiter buyers of this hardware can participate so there isn’t even the possibility of divesting control on short notice. +5. No obvious decentralization of control even with decentralized mining: Once large custom ASIC makers get into the game, designing back-doored hardware is trivial. ASIC makers have no incentive to be transparent or fair in market participation. + +While the goal of “ASIC resistance” is valuable, the entire concept of “ASIC resistance” is a bit of a fallacy. CPUs and GPUs are themselves ASICs. Any algorithm that can run on a commodity ASIC (a CPU or GPU) by definition can have a customized ASIC created for it with slightly less functionality. Some algorithms are intentionally made to be “ASIC friendly” - where an ASIC implementation is drastically more efficient than the same algorithm running on general purpose hardware. The protection that this offers when the coin is unknown also makes it an attractive target for a dedicate mining ASIC company as soon as it becomes useful. + +Therefore, ASIC resistance is: the efficiency difference of specilized hardware versus hardware that has a wider adoption and applicability. A smaller efficiency difference between custom vs general hardware mean higher resistance and a better algorithm. This efficiency difference is the proper metric to use when comparing the quality of PoW algorithms. Efficiency could mean absolute performance, performance per watt, or performance per dollar - they are all highly correlated. If a single entity creates and controls an ASIC that is drastically more efficient, they can gain 51% of the network hashrate and possibly stage an attack. + +### Review of Existing PoW Algorithms + +#### SHA256 +* Potential ASIC efficiency gain ~ 1000X + +The SHA algorithm is a sequence of simple math operations - additions, logical ops, and rotates. + +To process a single op on a CPU or GPU requires fetching and decoding an instruction, reading data from a register file, executing the instruction, and then writing the result back to a register file. This takes significant time and power. + +A single op implemented in an ASIC takes a handful of transistors and wires. This means every individual op takes negligible power, area, or time. A hashing core is built by laying out the sequence of required ops. + +The hashing core can execute the required sequence of ops in much less time, and using less power or area, than doing the same sequence on a CPU or GPU. A bitcoin ASIC consists of a number of identical hashing cores and some minimal off-chip communication. + +#### Scrypt and NeoScrypt +* Potential ASIC efficiency gain ~ 1000X + +Scrypt and NeoScrypt are similar to SHA in the arithmetic and bitwise operations used. Unfortunately, popular coins such as Litecoin only use a scratchpad size between 32kb and 128kb for their PoW mining algorithm. This scratch pad is small enough to trivially fit on an ASIC next to the math core. The implementation of the math core would be very similar to SHA, with similar efficiency gains. + +#### X11 and X16R +* Potential ASIC efficiency gain ~ 1000X + +X11 (and similar X##) require an ASIC that has 11 unique hashing cores pipelined in a fixed sequence. Each individual hashing core would have similar efficiency to an individual SHA core, so the overall design will have the same efficiency gains. + +X16R requires the multiple hashing cores to interact through a simple sequencing state machine. Each individual core will have similar efficiency gains and the sequencing logic will take minimal power, area, or time. + +The Baikal BK-X is an existing ASIC with multiple hashing cores and a programmable sequencer. It has been upgraded to enable new algorithms that sequence the hashes in different orders. + +#### Equihash +* Potential ASIC efficiency gain ~ 100X + +The ~150mb of state is large but possible on an ASIC. The binning, sorting, and comparing of bit strings could be implemented on an ASIC at extremely high speed. + +#### Cuckoo Cycle +* Potential ASIC efficiency gain ~ 100X + +The amount of state required on-chip is not clear as there are Time/Memory Tradeoff attacks. A specialized graph traversal core would have similar efficiency gains to a SHA compute core. + +#### CryptoNight +* Potential ASIC efficiency gain ~ 50X + +Compared to Scrypt, CryptoNight does much less compute and requires a full 2mb of scratch pad (there is no known Time/Memory Tradeoff attack). The large scratch pad will dominate the ASIC implementation and limit the number of hashing cores, limiting the absolute performance of the ASIC. An ASIC will consist almost entirely of just on-die SRAM. + +#### Ethash +* Potential ASIC efficiency gain ~ 2X + +Ethash requires external memory due to the large size of the DAG. However that is all that it requires - there is minimal compute that is done on the result loaded from memory. As a result a custom ASIC could remove most of the complexity, and power, of a GPU and be just a memory interface connected to a small compute engine. ## Specification -ProgPoW is based on Ethash and follows the same general structure. The algorithm has five main changes from Ethash, each tuned for commodity GPUs while minimizing the possible advantage of a specialized ASIC. - -The name of the algorithm comes from the fact that the inner loop between global memory accesses is a randomly generated program based on the block number. The random program is designed to both run efficiently on commodity GPUs and also cover most of the GPU's functionality. The random program sequence prevents the creation of a fixed pipeline implementation as seen in a specialized ASIC. The access size has also been tweaked to match contemporary GPUs. - -In contrast to Ethash, the changes detailed below make ProgPoW dependent on the core compute capabilities in addition to memory bandwidth and size. - -**Changes keccak_f1600 (with 64-bit words) to keccak_f800 (with 32-bit words).** - -*On 64-bit architectures f1600 processes twice as many bits as f800 in roughly the same time. As GPUs are natively 32-bit architectures, f1600 takes twice as long as f800. ProgPow doesn’t require all the bits f1600 can consume, thus reducing the size reduces the optimization opportunity for a specialized ASIC.* - -**Increases mix state.** - -*A significant part of a GPU’s area, power, and complexity is the large register file. A large mix state ensures that a specialized ASIC would need to implement similar state storage, limiting any advantage.* - -**Adds a random sequence of math in the main loop.** - -*The random math changes every 50 blocks to amortize compilation overhead. Having a random sequence of math that reads and writes random locations within the state ensures that the ASIC executing the algorithm is fully programmable. There is no possibility to create an ASIC with a fixed pipeline that is much faster or lower power.* - -**Adds reads from a small, low-latency cache that supports random addresses.** - -*Another significant part of a GPU’s area, power, and complexity is the memory hierarchy. Adding cached reads makes use of this hierarchy and ensures that a specialized ASIC also implements a similar hierarchy, preventing power or area savings.* - -**Increases the DRAM read from 128 bytes to 256 bytes.** - -*The DRAM read from the DAG is the same as Ethash’s, but with the size increased to `256 bytes`. This better matches the workloads seen on commodity GPUs, preventing a specialized ASIC from being able to gain performance by optimizing the memory controller for abnormally small accesses.* - -The DAG file is generated according to traditional Ethash specifications. +The DAG is generated exactly as in Ethash. All the parameters (ephoch length, DAG size, etc) are unchanged. See the original [Ethash](https://github.com/ethereum/wiki/wiki/Ethash) spec for details on generating the DAG. ProgPoW can be tuned using the following parameters. The proposed settings have been tuned for a range of existing, commodity GPUs: @@ -74,17 +119,29 @@ ProgPoW can be tuned using the following parameters. The proposed settings have The random program changes every `PROGPOW_PERIOD` blocks (default `50`, roughly 12.5 minutes) to ensure the hardware executing the algorithm is fully programmable. If the program only changed every DAG epoch (roughly 5 days) certain miners could have time to develop hand-optimized versions of the random sequence, giving them an undue advantage. -ProgPoW uses **FNV1a** for merging data. The existing Ethash uses FNV1 for merging, but FNV1a provides better distribution properties. +Sample code is written in C++, this should be kept in mind when evaluating the code in the specification. + +All numerics are computed using unsinged 32 bit integers. Any overflows are trimmed off before proceeding to the next computation. Languages that use numerics not fixed to bit lenghts (such as Python and JavaScript) or that only use signed integers (such as Java) will need to keep their languages' quirks in mind. The extensive use of 32 bit data values aligns with modern GPUs internal data architectures. + +ProgPoW uses a 32-bit variant of **FNV1a** for merging data. The existing Ethash uses a similar vaiant of FNV1 for merging, but FNV1a provides better distribution properties. + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#fnv1a). + +```cpp +const uint32_t FNV_PRIME = 0x1000193; +const uint32_t FNV_OFFSET_BASIS = 0x811c9dc5; + +uint32_t fnv1a(uint32_t h, uint32_t d) +{ + return (h ^ d) * FNV_PRIME; +} +``` ProgPow uses [KISS99](https://en.wikipedia.org/wiki/KISS_(algorithm)) for random number generation. This is the simplest (fewest instruction) random generator that passes the TestU01 statistical test suite. A more complex random number generator like Mersenne Twister can be efficiently implemented on a specialized ASIC, providing an opportunity for efficiency gains. +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#kiss99). + ```cpp - -uint32_t fnv1a(uint32_t &h, uint32_t d) -{ - return h = (h ^ d) * 0x1000193; -} - typedef struct { uint32_t z, w, jsr, jcong; } kiss99_t; @@ -105,7 +162,9 @@ uint32_t kiss99(kiss99_t &st) } ``` -The `LANES*REGS` of mix data is initialized from the hash’s seed. +The `fill_mix` function populates an array of `int32` values used by each lane in the hash calculations. + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#fill_mix). ```cpp void fill_mix( @@ -116,26 +175,32 @@ void fill_mix( { // Use FNV to expand the per-warp seed to per-lane // Use KISS to expand the per-lane seed to fill mix - uint32_t fnv_hash = 0x811c9dc5; kiss99_t st; - st.z = fnv1a(fnv_hash, seed); - st.w = fnv1a(fnv_hash, seed >> 32); - st.jsr = fnv1a(fnv_hash, lane_id); - st.jcong = fnv1a(fnv_hash, lane_id); + st.z = fnv1a(FNV_OFFSET_BASIS, seed); + st.w = fnv1a(st.z, seed >> 32); + st.jsr = fnv1a(st.w, lane_id); + st.jcong = fnv1a(st.jsr, lane_id); for (int i = 0; i < PROGPOW_REGS; i++) mix[i] = kiss99(st); } ``` -Like ethash Keccak is used to seed the sequence per-nonce and to produce the final result. The keccak-f800 variant is used as the 32-bit word size matches the native word size of modern GPUs. The implementation is a variant of SHAKE with width=800, bitrate=576, capacity=224, output=256, and no padding. The result of keccak is treated as a 256-bit big-endian number - that is result byte 0 is the MSB of the value. +Like Ethash Keccak is used to seed the sequence per-nonce and to produce the final result. The keccak-f800 variant is used as the 32-bit word size matches the native word size of modern GPUs. The implementation is a variant of SHAKE with width=800, bitrate=576, capacity=224, output=256, and no padding. The result of keccak is treated as a 256-bit big-endian number - that is result byte 0 is the MSB of the value. + +As with Ethash the input and output of the keccak function are fixed and relatively small. This means only a single "absorb" and "squeeze" phase are required. For a pseudo-code imenentation of the `keccak_f800_round` function see the `Round[b](A,RC)` function in the "Pseudo-code description of the permutations" section of the [official Keccak specs](https://keccak.team/keccak_specs_summary.html). + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#keccak_f800_progpow). ```cpp hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest) { uint32_t st[25]; + // Initialization for (int i = 0; i < 25; i++) st[i] = 0; + + // Absorb phase for fixed 18 words of input for (int i = 0; i < 8; i++) st[i] = header.uint32s[i]; st[8] = seed; @@ -143,29 +208,206 @@ hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest) for (int i = 0; i < 8; i++) st[10+i] = digest.uint32s[i]; + // keccak_f800 call for the single absorb pass for (int r = 0; r < 22; r++) keccak_f800_round(st, r); + // Squeeze phase for fixed 8 words of output hash32_t ret; for (int i=0; i<8; i++) ret.uint32s[i] = st[i]; + return ret; } ``` +The inner loop uses FNV and KISS99 to generate a random sequence from the `prog_seed`. This random sequence determines which mix state is accessed and what random math is performed. + +Since the `prog_seed` changes only once per `PROGPOW_PERIOD` (50 blocks or about 12.5 minutes) it is expected that while mining `progPowLoop` will be evaluated on the CPU to generate source code for that period's sequence. The source code will be compiled on the CPU before running on the GPU. + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowInit). + +```cpp +kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_seq_src[PROGPOW_REGS]) +{ + kiss99_t prog_rnd; + prog_rnd.z = fnv1a(FNV_OFFSET_BASIS, prog_seed); + prog_rnd.w = fnv1a(prog_rnd.z, prog_seed >> 32); + prog_rnd.jsr = fnv1a(prog_rnd.w, prog_seed); + prog_rnd.jcong = fnv1a(prog_rnd.jsr, prog_seed >> 32); + // Create a random sequence of mix destinations for merge() and mix sources for cache reads + // guarantees every destination merged once + // guarantees no duplicate cache reads, which could be optimized away + // Uses Fisher-Yates shuffle + for (int i = 0; i < PROGPOW_REGS; i++) + { + mix_seq_dst[i] = i; + mix_seq_src[i] = i; + } + for (int i = PROGPOW_REGS - 1; i > 0; i--) + { + int j; + j = kiss99(prog_rnd) % (i + 1); + swap(mix_seq_dst[i], mix_seq_dst[j]); + j = kiss99(prog_rnd) % (i + 1); + swap(mix_seq_src[i], mix_seq_src[j]); + } + return prog_rnd; +} +``` + +The math operations that merges values into the mix data are ones chosen to maintain entropy. + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#math). + +```cpp +// Merge new data from b into the value in a +// Assuming A has high entropy only do ops that retain entropy +// even if B is low entropy +// (IE don't do A&B) +uint32_t merge(uint32_t a, uint32_t b, uint32_t r) +{ + switch (r % 4) + { + case 0: return (a * 33) + b; + case 1: return (a ^ b) * 33; + // prevent rotate by 0 which is a NOP + case 2: return ROTL32(a, ((r >> 16) % 31) + 1) ^ b; + case 3: return ROTR32(a, ((r >> 16) % 31) + 1) ^ b; + } +} +``` + +The math operations chosen for the random math are ones that are easy to implement in CUDA and OpenCL, the two main programming languages for commodity GPUs. The [mul_hi](https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/mul_hi.html), [min](https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/integerMax.html), [clz](https://www.khronos.org/registry/OpenCL/sdk/1.1/docs/man/xhtml/clz.html), and [popcount](https://www.khronos.org/registry/OpenCL/sdk/2.0/docs/man/xhtml/popcount.html) functions match the corresponding OpenCL functions. ROTL32 matches the OpenCL [rotate](https://www.khronos.org/registry/OpenCL/sdk/1.0/docs/man/xhtml/rotate.html) function. ROTR32 is rotate right, which is equivalent to `rotate(i, 32-v)`. + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#math). + +```cpp +// Random math between two input values +uint32_t math(uint32_t a, uint32_t b, uint32_t r) +{ + switch (r % 11) + { + case 0: return a + b; + case 1: return a * b; + case 2: return mul_hi(a, b); + case 3: return min(a, b); + case 4: return ROTL32(a, b); + case 5: return ROTR32(a, b); + case 6: return a & b; + case 7: return a | b; + case 8: return a ^ b; + case 9: return clz(a) + clz(b); + case 10: return popcount(a) + popcount(b); + } +} +``` + + +The flow of the inner loop is: +* Lane `(loop % LANES)` is chosen as the leader for that loop iteration +* The leader's `mix[0]` value modulo the number of 256-byte DAG entries is is used to select where to read from the full DAG +* Each lane reads `DAG_LOADS` sequential words, using `(lane ^ loop) % LANES` as the starting offset within the entry. +* The random sequence of math and cache accesses is performed +* The DAG data read at the start of the loop is merged at the end of the loop + +`prog_seed` and `loop` come from the outer loop, corresponding to the current program seed (which is block_number/PROGPOW_PERIOD) and the loop iteration number. `mix` is the state array, initially filled by `fill_mix`. `dag` is the bytes of the Ethash DAG grouped into 32 bit unsigned ints in litte-endian format. On little-endian architectures this is just a normal int32 pointer to the existing DAG. + +`DAG_BYTES` is set to the number of bytes in the current DAG, which is generated identically to the existing Ethash algorithm. + +Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowLoop). + +```cpp +void progPowLoop( + const uint64_t prog_seed, + const uint32_t loop, + uint32_t mix[PROGPOW_LANES][PROGPOW_REGS], + const uint32_t *dag) +{ + // dag_entry holds the 256 bytes of data loaded from the DAG + uint32_t dag_entry[PROGPOW_LANES][PROGPOW_DAG_LOADS]; + // On each loop iteration rotate which lane is the source of the DAG address. + // The source lane's mix[0] value is used to ensure the last loop's DAG data feeds into this loop's address. + // dag_addr_base is which 256-byte entry within the DAG will be accessed + uint32_t dag_addr_base = mix[loop%PROGPOW_LANES][0] % + (DAG_BYTES / (PROGPOW_LANES*PROGPOW_DAG_LOADS*sizeof(uint32_t))); + for (int l = 0; l < PROGPOW_LANES; l++) + { + // Lanes access DAG_LOADS sequential words from the dag entry + // Shuffle which portion of the entry each lane accesses each iteration by XORing lane and loop. + // This prevents multi-chip ASICs from each storing just a portion of the DAG + size_t dag_addr_lane = dag_addr_base * PROGPOW_LANES + (l ^ loop) % PROGPOW_LANES; + for (int i = 0; i < PROGPOW_DAG_LOADS; i++) + dag_entry[l][i] = dag[dag_addr_lane * PROGPOW_DAG_LOADS + i]; + } + + // Initialize the program seed and sequences + // When mining these are evaluated on the CPU and compiled away + int mix_seq_dst[PROGPOW_REGS]; + int mix_seq_src[PROGPOW_REGS]; + int mix_seq_dst_cnt = 0; + int mix_seq_src_cnt = 0; + kiss99_t prog_rnd = progPowInit(prog_seed, mix_seq_dst, mix_seq_src); + + int max_i = max(PROGPOW_CNT_CACHE, PROGPOW_CNT_MATH); + for (int i = 0; i < max_i; i++) + { + if (i < PROGPOW_CNT_CACHE) + { + // Cached memory access + // lanes access random 32-bit locations within the first portion of the DAG + int src = mix_seq_src[(mix_seq_src_cnt++)%PROGPOW_REGS]; + int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS]; + int sel = kiss99(prog_rnd); + for (int l = 0; l < PROGPOW_LANES; l++) + { + uint32_t offset = mix[l][src] % (PROGPOW_CACHE_BYTES/sizeof(uint32_t)); + mix[l][dst] = merge(mix[l][dst], dag[offset], sel); + } + } + if (i < PROGPOW_CNT_MATH) + { + // Random Math + // Generate 2 unique sources + int src_rnd = kiss99(prog_rnd) % (PROGPOW_REGS * (PROGPOW_REGS-1)); + int src1 = src_rnd % PROGPOW_REGS; // 0 <= src1 < PROGPOW_REGS + int src2 = src_rnd / PROGPOW_REGS; // 0 <= src2 < PROGPOW_REGS - 1 + if (src2 >= src1) ++src2; // src2 is now any reg other than src1 + int sel1 = kiss99(prog_rnd); + int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS]; + int sel2 = kiss99(prog_rnd); + for (int l = 0; l < PROGPOW_LANES; l++) + { + uint32_t data = math(mix[l][src1], mix[l][src2], sel1); + mix[l][dst] = merge(mix[l][dst], data, sel2); + } + } + } + // Consume the global load data at the very end of the loop to allow full latency hiding + // Always merge into mix[0] to feed the offset calculation + for (int i = 0; i < PROGPOW_DAG_LOADS; i++) + { + int dst = (i==0) ? 0 : mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS]; + int sel = kiss99(prog_rnd); + for (int l = 0; l < PROGPOW_LANES; l++) + mix[l][dst] = merge(mix[l][dst], dag_entry[l][i], sel); + } +} +``` + The flow of the overall algorithm is: * A keccak hash of the header + nonce to create a seed * Use the seed to generate initial mix data * Loop multiple times, each time hashing random loads and random math into the mix data * Hash all the mix data into a single 256-bit value -* A final keccak hash that is compared against the target +* A final keccak hash is computed +* When mining this final value is compared against a `hash32_t` target ```cpp -bool progpow_search( +hash32_t progPowHash( const uint64_t prog_seed, // value is (block_number/PROGPOW_PERIOD) const uint64_t nonce, const hash32_t header, - const hash32_t target, // miner can use a uint64_t target, doesn't need the full 256 bit target const uint32_t *dag // gigabyte DAG located in framebuffer - the first portion gets cached ) { @@ -191,171 +433,21 @@ bool progpow_search( uint32_t digest_lane[PROGPOW_LANES]; for (int l = 0; l < PROGPOW_LANES; l++) { - digest_lane[l] = 0x811c9dc5 + digest_lane[l] = FNV_OFFSET_BASIS for (int i = 0; i < PROGPOW_REGS; i++) - fnv1a(digest_lane[l], mix[l][i]); + digest_lane[l] = fnv1a(digest_lane[l], mix[l][i]); } // Reduce all lanes to a single 256-bit digest for (int i = 0; i < 8; i++) - digest.uint32s[i] = 0x811c9dc5; + digest.uint32s[i] = FNV_OFFSET_BASIS; for (int l = 0; l < PROGPOW_LANES; l++) - fnv1a(digest.uint32s[l%8], digest_lane[l]) + digest.uint32s[l%8] = fnv1a(digest.uint32s[l%8], digest_lane[l]) // keccak(header .. keccak(header..nonce) .. digest); - return (keccak_f800_progpow(header, seed, digest) <= target); + keccak_f800_progpow(header, seed, digest); } ``` -The inner loop uses FNV and KISS99 to generate a random sequence from the `prog_seed`. This random sequence determines which mix state is accessed and what random math is performed. Since the `prog_seed` changes relatively infrequently it is expected that `progPowLoop` will be compiled while mining instead of interpreted on the fly. - -```cpp -kiss99_t progPowInit(uint64_t prog_seed, int mix_seq_dst[PROGPOW_REGS], int mix_seq_cache[PROGPOW_REGS]) -{ - kiss99_t prog_rnd; - uint32_t fnv_hash = 0x811c9dc5; - prog_rnd.z = fnv1a(fnv_hash, prog_seed); - prog_rnd.w = fnv1a(fnv_hash, prog_seed >> 32); - prog_rnd.jsr = fnv1a(fnv_hash, prog_seed); - prog_rnd.jcong = fnv1a(fnv_hash, prog_seed >> 32); - // Create a random sequence of mix destinations for merge() and mix sources for cache reads - // guarantees every destination merged once - // guarantees no duplicate cache reads, which could be optimized away - // Uses Fisher-Yates shuffle - for (int i = 0; i < PROGPOW_REGS; i++) - { - mix_seq_dst[i] = i; - mix_seq_cache[i] = i; - } - for (int i = PROGPOW_REGS - 1; i > 0; i--) - { - int j; - j = kiss99(prog_rnd) % (i + 1); - swap(mix_seq_dst[i], mix_seq_dst[j]); - j = kiss99(prog_rnd) % (i + 1); - swap(mix_seq_cache[i], mix_seq_cache[j]); - } - return prog_rnd; -} -``` - -The math operations that merge values into the mix data are ones chosen to maintain entropy. - -```cpp -// Merge new data from b into the value in a -// Assuming A has high entropy only do ops that retain entropy -// even if B is low entropy -// (IE don't do A&B) -void merge(uint32_t &a, uint32_t b, uint32_t r) -{ - switch (r % 4) - { - case 0: a = (a * 33) + b; break; - case 1: a = (a ^ b) * 33; break; - // prevent rotate by 0 which is a NOP - case 2: a = ROTL32(a, ((r >> 16) % 31) + 1) ^ b; break; - case 3: a = ROTR32(a, ((r >> 16) % 31) + 1) ^ b; break; - } -} -``` - -The math operations chosen for the random math are ones that are easy to implement in CUDA and OpenCL, the two main programming languages for commodity GPUs. - -```cpp -// Random math between two input values -uint32_t math(uint32_t a, uint32_t b, uint32_t r) -{ - switch (r % 11) - { - case 0: return a + b; - case 1: return a * b; - case 2: return mul_hi(a, b); - case 3: return min(a, b); - case 4: return ROTL32(a, b); - case 5: return ROTR32(a, b); - case 6: return a & b; - case 7: return a | b; - case 8: return a ^ b; - case 9: return clz(a) + clz(b); - case 10: return popcount(a) + popcount(b); - } -} -``` - -The main loop: - -```cpp -void progPowLoop( - const uint64_t prog_seed, - const uint32_t loop, - uint32_t mix[PROGPOW_LANES][PROGPOW_REGS], - const uint32_t *dag) -{ - // All lanes share a base address for the global load - // Global offset uses mix[0] to guarantee it depends on the load result - uint32_t data_g[PROGPOW_LANES][PROGPOW_DAG_LOADS]; - uint32_t offset_g = mix[loop%PROGPOW_LANES][0] % (DAG_BYTES / (PROGPOW_LANES*PROGPOW_DAG_LOADS*sizeof(uint32_t))); - for (int l = 0; l < PROGPOW_LANES; l++) - { - // global load to the 256 byte DAG entry - // every lane can access every part of the entry - uint32_t offset_l = offset_g * PROGPOW_LANES + (l ^ loop) % PROGPOW_LANES; - for (int i = 0; i < PROGPOW_DAG_LOADS; i++) - data_g[l][i] = dag[offset_l * PROGPOW_DAG_LOADS + i]; - } - - // Initialize the program seed and sequences - // When mining these are evaluated on the CPU and compiled away - int mix_seq_dst[PROGPOW_REGS]; - int mix_seq_src[PROGPOW_REGS]; - int mix_seq_dst_cnt = 0; - int mix_seq_src_cnt = 0; - kiss99_t prog_rnd = progPowInit(prog_seed, mix_seq_dst, mix_seq_src); - - int max_i = max(PROGPOW_CNT_CACHE, PROGPOW_CNT_MATH); - for (int i = 0; i < max_i; i++) - { - if (i < PROGPOW_CNT_CACHE) - { - // Cached memory access - // lanes access random 32-bit locations within the first portion of the DAG - int src = mix_seq_src[(mix_seq_src_cnt++)%PROGPOW_REGS]; - int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS]; - int sel = kiss99(prog_rnd); - for (int l = 0; l < PROGPOW_LANES; l++) - { - uint32_t offset = mix[l][src] % (PROGPOW_CACHE_BYTES/sizeof(uint32_t)); - merge(mix[l][dst], dag[offset], sel); - } - } - if (i < PROGPOW_CNT_MATH) - { - // Random Math - // Generate 2 unique sources - int src_rnd = kiss99(prog_rnd) % (PROGPOW_REGS * (PROGPOW_REGS-1)); - int src1 = src_rnd % PROGPOW_REGS; // 0 <= src1 < PROGPOW_REGS - int src2 = src_rnd / PROGPOW_REGS; // 0 <= src2 < PROGPOW_REGS - 1 - if (src2 >= src1) ++src2; // src2 is now any reg other than src - int sel1 = kiss99(prog_rnd); - int dst = mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS]; - int sel2 = kiss99(prog_rnd); - for (int l = 0; l < PROGPOW_LANES; l++) - { - uint32_t data = math(mix[l][src1], mix[l][src2], sel1); - merge(mix[l][dst], data, sel2); - } - } - } - // Consume the global load data at the very end of the loop to allow full latency hiding - // Always merge into mix[0] to feed the offset calculation - for (int i = 0; i < PROGPOW_DAG_LOADS; i++) - { - int dst = (i==0) ? 0 : mix_seq_dst[(mix_seq_dst_cnt++)%PROGPOW_REGS]; - int sel = kiss99(prog_rnd); - for (int l = 0; l < PROGPOW_LANES; l++) - merge(mix[l][dst], data_g[l][i], sel); - } -} -``` ## Rationale ProgPoW utilizes almost all parts of a commodity GPU, excluding: @@ -371,10 +463,24 @@ Since the GPU is almost fully utilized, there’s little opportunity for specia This algorithm is not backwards compatible with the existing Ethash, and will require a fork for adoption. Furthermore, the network hashrate will halve since twice as much memory is loaded per hash. +## Test Cases + +The algorithm run on block 30,000 produces the following digest and result: +``` +header ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff +nonce 123456789abcdef0 + +digest: 11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d +result: 5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece +``` + +Additional test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowHash). + ## Implementation -Please refer to the official code located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) for the full code, implemented in the standard ethminer. +The reference ProgPoW mining implementation located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) is a derivative of ethminer so retains the GPL license. +## License and Copyright -## Copyright +The ProgPoW algorithm and this specification are a new work. Copyright and related rights are waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). +The reference ProgPoW mining implementation located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) is a derivative of ethminer so retains the GPL license. \ No newline at end of file diff --git a/assets/eip-1057/test-vectors.md b/assets/eip-1057/test-vectors.md new file mode 100644 index 00000000..a47c7e89 --- /dev/null +++ b/assets/eip-1057/test-vectors.md @@ -0,0 +1,457 @@ +# Test Vectors for EIP-1057 - ProgPow + +Many of these vectors are dervived from [chfast/ethash](https://github.com/chfast/ethash) + +## fnv1a + +| `h` | `d` | _result_ | +| -----------: | -----------: | -----------: | +| `0X811C9DC5` | `0XDDD0A47B` | `0XD37EE61A` | +| `0XD37EE61A` | `0XEE304846` | `0XDEDC7AD4` | +| `0XDEDC7AD4` | `0X00000000` | `0XA9155BBC` | + +## kiss99 + +For `z`=`362436069`, `w`=`521288629`, `jsr`=`123456789`, and `jcong`=`380116160` the result of each iterative call to `kiss99` is as follows: + +| _iteration_ | _result_ |kernel +| ----------: | -----------: | +| `1` | `769445856` | +| `2` | `742012328` | +| `3` | `2121196314` | +| `4` | `2805620942` | +| `100000` | `941074834` | + +## fill_mix + +For `hash_seed`=`0xEE304846DDD0A47B` and `lane_id`=`0` the values stored in the `mix` array will be + +> ``` +> 0x10C02F0D, 0x99891C9E, 0xC59649A0, 0x43F0394D, +> 0x24D2BAE4, 0xC4E89D4C, 0x398AD25C, 0xF5C0E467, +> 0x7A3302D6, 0xE6245C6C, 0x760726D3, 0x1F322EE7, +> 0x85405811, 0xC2F1E765, 0xA0EB7045, 0xDA39E821, +> 0x79FC6A48, 0x089E401F, 0x8488779F, 0xD79E414F, +> 0x041A826B, 0x313C0D79, 0x10125A3C, 0x3F4BDFAC, +> 0xA7352F36, 0x7E70CB54, 0x3B0BB37D, 0x74A3E24A, +> 0xCC37236A, 0xA442B311, 0x955AB27A, 0x6D175B7E +> ``` + +For the same hash and `lane_id`=`13` the value in the `mix` array will be + +> ``` +> 0x4E46D05D, 0x2E77E734, 0x2C479399, 0x70712177, +> 0xA75D7FF5, 0xBEF18D17, 0x8D42252E, 0x35B4FA0E, +> 0x462C850A, 0x2DD2B5D5, 0x5F32B5EC, 0xED5D9EED, +> 0xF9E2685E, 0x1F29DC8E, 0xA78F098B, 0x86A8687B, +> 0xEA7A10E7, 0xBE732B9D, 0x4EEBCB60, 0x94DD7D97, +> 0x39A425E9, 0xC0E782BF, 0xBA7B870F, 0x4823FF60, +> 0xF97A5A1C, 0xB00BCAF4, 0x02D0F8C4, 0x28399214, +> 0xB4CCB32D, 0x83A09132, 0x27EA8279, 0x3837DDA3 +> ``` + +## keccak_f800_progpow + +Test case 1: + +| | | +| -------- | ----------------------------------------------------------------------------------------------------------------- | +| header | `0xCCDDEEFF`, `0x8899AABB`, `0x44556677`, `0x00112233`,
`0x33221100`, `0x77665544`, `0xBBAA9988`, `0xFFEEDDCC` | +| seed | `0x123456789ABCDEF0` | +| digest | `0x00000000`, `0x00000000`, `0x00000000`, `0x00000000`,
`0x00000000`, `0x00000000`, `0x00000000`, `0x00000000` | +| _result_ | `0x464830EE`, `0x7BA4D0DD`, `0x969E1798`, `0xCEC50EB6`,
`0x7872E2EA`, `0x597E3634`, `0xE380E73D`, `0x2F89D1E6` | + +Test case 2: + +| | | +| -------- | ----------------------------------------------------------------------------------------------------------------- | +| header | `0xCCDDEEFF`, `0x8899AABB`, `0x44556677`, `0x00112233`,
`0x33221100`, `0x77665544`, `0xBBAA9988`, `0xFFEEDDCC` | +| seed | `0xEE304846DDD0A47B` | +| digest | `0x0598F111`, `0x66B48AC5`, `0x719CFF10`, `0x5F0ACF9D`,
`0x162FFA18`, `0xEF8E7905`, `0x21470C77`, `0x7D767492` | +| _result_ | `0x47CD7C5B`, `0xD9FDBE2D`, `0xAC5C895B`, `0xFF67CE8E`,
`0x6B5AEB0D`, `0xE1C6ECD2`, `0x003D3862`, `0xCE8E72C3` | + +## progPowInit + +For ProgPow period 600 (block 30,000) the configurations should be + +src array: + +> `0x1A`, `0x1E`, `0x01`, `0x13`, `0x0B`, `0x15`, `0x0F`, `0x12`, +> `0x03`, `0x11`, `0x1F`, `0x10`, `0x1C`, `0x04`, `0x16`, `0x17`, +> `0x02`, `0x0D`, `0x1D`, `0x18`, `0x0A`, `0x0C`, `0x05`, `0x14`, +> `0x07`, `0x08`, `0x0E`, `0x1B`, `0x06`, `0x19`, `0x09`, `0x00` + +dst array + +> `0x00`, `0x04`, `0x1B`, `0x1A`, `0x0D`, `0x0F`, `0x11`, `0x07`, +> `0x0E`, `0x08`, `0x09`, `0x0C`, `0x03`, `0x0A`, `0x01`, `0x0B`, +> `0x06`, `0x10`, `0x1C`, `0x1F`, `0x02`, `0x13`, `0x1E`, `0x16`, +> `0x1D`, `0x05`, `0x18`, `0x12`, `0x19`, `0x17`, `0x15`, `0x14` + +Kiss 99 state: +`z`=`0x6535921C` `w`=`0x29345B16`, `jsr`=`0xC0DD7F78`, `jcong`=`0x1165D7EB` + +## merge + +| `a` | `b` | `r` | _result_ | _path exercised_ | +| ------------ | ------------ | ------------ | ------------ | ---------------- | +| `0x3B0BB37D` | `0xA0212004` | `0x9BD26AB0` | `0x3CA34321` | mul/add | +| `0x10C02F0D` | `0x870FA227` | `0xD4F45515` | `0x91C1326A` | xor/mul | +| `0x24D2BAE4` | `0x0FFB4C9B` | `0x7FDBC2F2` | `0x2EDDD94C` | rotl/xor | +| `0xDA39E821` | `0x089C4008` | `0x8B6CD8C3` | `0x8A81E396` | rotr/xor | + +## math + +| `a` | `b` | `r` | _result_ | _operation exercised_ | +| ------------ | ------------ | ------------ | ------------ | ----------------------- | +| `0x8626BB1F` | `0xBBDFBC4E` | `0x883E5B49` | `0x4206776D` | add | +| `0x3F4BDFAC` | `0xD79E414F` | `0x36B71236` | `0x4C5CB214` | mul | +| `0x6D175B7E` | `0xC4E89D4C` | `0x944ECABB` | `0x53E9023F` | mul_hi32 | +| `0x2EDDD94C` | `0x7E70CB54` | `0x3F472A85` | `0x2EDDD94C` | min | +| `0x61AE0E62` | `0xe0596b32` | `0x3F472A85` | `0x61AE0E62` | min again (unsigned) | +| `0x8A81E396` | `0x3F4BDFAC` | `0xCEC46E67` | `0x1E3968A8` | rotl32 | +| `0x8A81E396` | `0x7E70CB54` | `0xDBE71FF7` | `0x1E3968A8` | rotr32 | +| `0xA7352F36` | `0xA0EB7045` | `0x59E7B9D8` | `0xA0212004` | bitwise and | +| `0xC89805AF` | `0x64291E2F` | `0x1BDC84A9` | `0xECB91FAF` | bitwise or | +| `0x760726D3` | `0x79FC6A48` | `0xC675CAC5` | `0x0FFB4C9B` | bitwise xor | +| `0x75551D43` | `0x3383BA34` | `0x2863AD31` | `0x00000003` | clz (leading zeros) | +| `0xEA260841` | `0xE92C44B7` | `0xF83FFE7D` | `0x0000001B` | popcount (number of 1s) | + +## progPowLoop + +For the first loop iteration of block 30,000 the seed to use for `fill_mix` +would be `0xEE304846DDD0A47B`. A two dimensional `mix` array should be created +passing the rows into `fill_mix` witht he column number as the loop argument. + +The state of the mix array after the call to `progPowLoop` for block 30,000, +loop 1 are as follows. + +`mix[0]` - + +> ``` +> 0x40E09E9C, 0x967A7DF0, 0x8626BB1F, 0x12C2392F, +> 0xA21D8305, 0x44C2702E, 0x94C93945, 0x6B66B158, +> 0x0CF00FAA, 0x26F5E6B5, 0x36EC0134, 0xC89805AF, +> 0x58118540, 0x8617DC4D, 0xC759F486, 0x8A81E396, +> 0x22443D4D, 0x64291E2F, 0x1998AB7F, 0x11C0FBBB, +> 0xBEA9C139, 0x82D1E47E, 0x7ED3E850, 0x2F81531A, +> 0xBBDFBC4E, 0xF58AEE4D, 0x3CA34321, 0x357BD48A, +> 0x2F9C8B5D, 0x2319B193, 0x2856BB38, 0x2E3C33E6 +> ``` + +`mix[1]` - + +> ``` +> 0x4EB8A8F9, 0xD978BF17, 0x7D5074D4, 0x7A092D5D, +> 0x8682D1BE, 0xC3D2941C, 0xF1A1A38B, 0x54BB6D34, +> 0x2F0FB257, 0xB5464B50, 0x40927B67, 0xBB92A7E1, +> 0x1305A517, 0xE06C6765, 0xA75FD647, 0x9F232D6E, +> 0x0D9213ED, 0x8884671D, 0x54352B96, 0x6772E58E, +> 0x1B8120C9, 0x179F3CFB, 0x116FFC82, 0x6D019BCE, +> 0x1C26A750, 0x89716638, 0x02BEB948, 0x2E0AD5CE, +> 0x7FA915B2, 0x93024F2F, 0x2F58032E, 0xF02E550C +> ``` + +`mix[2]` - + +> ``` +> 0x008FF9BD, 0xC41F9802, 0x2E36FDC8, 0x9FBA2A91, +> 0x0A921670, 0x231308E6, 0xEF09A56E, 0x9657A64A, +> 0xF67723FE, 0x963DCD40, 0x354CBFDB, 0x57C07B9A, +> 0x06AF5B40, 0xBA5DE5A6, 0xDA5AAE7B, 0x9F8A5E4B, +> 0x7D6AFC9A, 0xE4783F78, 0x89B24946, 0x5EE94228, +> 0xA209DAAA, 0xDCC27C64, 0x3366FBED, 0x0FEFB673, +> 0x0FC205E3, 0xB61515B2, 0x70A45E9B, 0xBB225E5D, +> 0xB8C38EA0, 0xE01DE9B4, 0x866FAA5B, 0x1A125220 +> ``` + +`mix[3]` - + +> ``` +> 0xE5F9C5CC, 0x6F75CFA2, 0xE0F50924, 0xE7B4F5EF, +> 0x779B903D, 0x5F068253, 0x05FF68E5, 0x39348653, +> 0x654B89E4, 0x0559769E, 0xA3D46B93, 0xD084454D, +> 0xCFC5CF7D, 0x8C11D8E4, 0x795BDB59, 0xD9E03113, +> 0xBAE8C355, 0x12B63814, 0x4046A018, 0xA269A32E, +> 0x54A57C4B, 0x2ED1065B, 0xB69A2C76, 0x4AEF0950, +> 0x6C2D187B, 0x8252FAE7, 0x3E9C0ED2, 0x26E47B15, +> 0xFEFB48E3, 0xDA088C7F, 0xA82B0379, 0xA49C6D86 +> ``` + +`mix[4]` - + +> ``` +> 0xB926334C, 0x686A29AF, 0xD9E2EF15, 0x1C8A2D39, +> 0x307ED4F4, 0x2ABB1DB6, 0xD6F95128, 0xDFCA05F8, +> 0x904D9472, 0xEC09E200, 0x7143F47F, 0xEE488438, +> 0xFCA48DA8, 0xA64C7DD4, 0xC4AE9A30, 0xEBA30BC9, +> 0xB02630BF, 0xD1DF40CC, 0x4DFE8B7B, 0x205C97B3, +> 0xE40376F8, 0x2491117E, 0x34984321, 0xA01546A7, +> 0xB254F2F9, 0xC78A7C25, 0xFFC615E2, 0x5839FC88, +> 0x2A04DF6C, 0xC02A9A8A, 0x39238EAD, 0x7139060C +> ``` + +`mix[5]` - + +> ``` +> 0xC416E54B, 0x64AD1C57, 0xBF7CBA55, 0x176F714E, +> 0xBE733426, 0x995C4132, 0x5F50F779, 0x0F76FDF3, +> 0x526F7870, 0xE56A1A8A, 0xDCEB677E, 0xD471CC19, +> 0xA9ED60E4, 0x145E807F, 0x8D652E92, 0x80E8116F, +> 0xFF1A37EB, 0x1E0C49A1, 0x59D756DA, 0x39A8E761, +> 0x2F0F646F, 0x43F41278, 0x88CC48DA, 0x8FDFF7A4, +> 0x9AEACA2E, 0x59E7808C, 0x7F72E46B, 0xCA572333, +> 0xC6029C88, 0x7736E592, 0xF1338231, 0x262B2C7F +> ``` + +`mix[6]` - + +> ``` +> 0x3C554151, 0x70999423, 0x64BB49A8, 0xF9EBE9E9, +> 0x7D9C28CF, 0x23EE7659, 0xD6504FCF, 0x1C58C2A1, +> 0x62B9C627, 0x680AE248, 0xF196A153, 0x2A3C345A, +> 0x860E6EB2, 0x266D2652, 0x3C9F2420, 0xF790A538, +> 0x710A5523, 0xBEA2603A, 0x1C1CC272, 0xF91D482A, +> 0x1CA19931, 0x7A80ED37, 0x9572513D, 0x376F1CFE, +> 0xE57C1264, 0xE47BF931, 0xC7310E05, 0x7866CC9E, +> 0xC676BBD5, 0x4C167FEB, 0x0FE03D2B, 0x46C6D26C +> ``` + +`mix[7]` - + +> ``` +> 0x3395F65A, 0x7142A5B1, 0x97780661, 0xE5EE45B8, +> 0xCD9FDC42, 0x25BF044C, 0x0350F81B, 0x55D50703, +> 0xA8CB893E, 0xEE795201, 0xC2D6E598, 0xC2AC2D7A, +> 0xD2E81716, 0xAD876790, 0x0F3339C7, 0xEEC31E01, +> 0xA293ABF6, 0x28AE317D, 0x44A7AC05, 0xBEBA1C5E, +> 0x325ED29E, 0x4344131E, 0x921CD8DD, 0x08AB9E0B, +> 0xC18E66A6, 0x87E6BCA3, 0x24CE82AE, 0xC910B4F1, +> 0x9E513EC0, 0xA1B8CB76, 0xF0455815, 0x36BC0DCF +> ``` + +`mix[8]` - + +> ``` +> 0x0117C85F, 0xE018F2C6, 0x416C897D, 0x9D288A0F, +> 0x2AA9EA93, 0x5A6D3CEA, 0xAA99B726, 0x0A42DAB7, +> 0x72F6EA4A, 0x1DB074E6, 0x2E2A606C, 0xAC5D509B, +> 0x53F13E85, 0x1D44B521, 0x24234C42, 0xAD5BAD70, +> 0xAB2DA791, 0x6479546A, 0xD27B3771, 0xBB0A09DD, +> 0x6D3C8056, 0x96572D4B, 0x52DB6535, 0x3D242BC1, +> 0xF37D7C7A, 0xA60F7111, 0x59B59667, 0xF28635B0, +> 0xC2A8F9F5, 0x7CFB9CCB, 0xDF8697AA, 0xA3260D94 +> ``` + +`mix[9]` - + +> ``` +> 0xA387FC4B, 0xC757D3A0, 0xA584E879, 0xB0A1EC29, +> 0x82CB2EC3, 0x6BF33664, 0x41FECC42, 0xF60C2AC5, +> 0xEA250BE5, 0x42BE9F33, 0x9227B0B3, 0x9080A6AB, +> 0xAF193598, 0xC708BC8A, 0x020CDEDB, 0x7FA2F773, +> 0x4338E670, 0x069E0242, 0x5AD87326, 0xD7A87124, +> 0x220D5C46, 0x26D3400D, 0x4899D1EE, 0x90EAD2F6, +> 0xFA3F1F74, 0x9C5A5D58, 0xAE20567C, 0x424B690D, +> 0xC9A4057A, 0x9F2A5CD1, 0xAA33CD5F, 0x18F58C00 +> ``` + +`mix[10]` - + +> ``` +> 0xEAFE893C, 0x1ABB2971, 0x29803BB3, 0x5BC2F71F, +> 0x619DAFAD, 0xD9CFEFB6, 0xB4FEFAB5, 0x5EB249EC, +> 0x1A6E2B3A, 0xFB05DD28, 0xDCB33C2E, 0x630BB8AE, +> 0x43463B39, 0x3BD2F552, 0xFB20C0A2, 0x3383BA34, +> 0x2E9C1A99, 0x60A949B2, 0x861372AB, 0xC149D929, +> 0xA77A0A93, 0xE0CEE0D9, 0x791E7E82, 0x66A8D75A, +> 0x44D1845F, 0xE534DC4A, 0x2C7DD20C, 0xEEDAB329, +> 0x3209FE2A, 0x0C0406BC, 0xD6D4BD2A, 0x5FDB13CC +> ``` + +`mix[11]` - + +> ``` +> 0x2520ABB3, 0xCD942485, 0x9A2929BC, 0x0E10F18C, +> 0xDFB1815E, 0x8BEF05A3, 0x531A8837, 0x668838E4, +> 0xBACCE200, 0x003F85C2, 0x56226F05, 0xC2233173, +> 0x2F39A0D9, 0xF4466D0D, 0x0B9E686C, 0x82C69BDA, +> 0x0C8A8CD6, 0xA93F3001, 0x36A65EC1, 0x40CCFD7A, +> 0x84484E23, 0xF0896D45, 0x06D9F760, 0x6559142C, +> 0x9FFE2E88, 0x9593DC89, 0x89C9E3B9, 0x33285F41, +> 0x16F636C8, 0xA08169C7, 0xA5E1C956, 0xC22CCF52 +> ``` + +`mix[12]` - + +> ``` +> 0xDC3B8CAA, 0xC6941197, 0x9969D596, 0x46453D3E, +> 0x568EAFEA, 0x5B823345, 0xDE606E8E, 0x7523C86D, +> 0x0EDAF441, 0x00C3D848, 0xAE5BAB99, 0xD705B9EE, +> 0x54B49E3D, 0xF364A6A4, 0x42C55975, 0xFE41EED5, +> 0xAD46170F, 0xAABE4868, 0x270379F9, 0xD33D0D7C, +> 0xF39C476C, 0xA449118E, 0x71BCC1E4, 0x5E300E77, +> 0x1CACD489, 0x4D82FABD, 0x090F9F80, 0xB2DB9626, +> 0xE12A973B, 0x1B77460C, 0xD25F89F5, 0x5753612E +> ``` + +`mix[13]` - + +> ``` +> 0x042D951C, 0x38833AA7, 0xBEA9894D, 0x7AE7F381, +> 0x42DB6723, 0x1FB0294F, 0x41452A28, 0xA7A97B9C, +> 0x228AA7EA, 0x781A7420, 0x4589736D, 0xB3C19349, +> 0x685EF9E6, 0xB4987DF6, 0xC9C3B188, 0x2DCA6A03, +> 0xE89A6D3D, 0x50EF7CF5, 0xF6274868, 0x8AA22824, +> 0x980FFDE3, 0xD4A6CB4E, 0x06FF9E1A, 0xBADB6DF5, +> 0xEDE3ADF3, 0xC9CF45F6, 0xFDFA194C, 0xAF076AA8, +> 0x7B876CEA, 0xB0C89575, 0x35A72155, 0x6CFDFC06 +> ``` + +`mix[14]` - + +> ``` +> 0x0E3E28C8, 0xEC329DEC, 0x06D0A1D1, 0xF95ABEF8, +> 0x168DCF28, 0xDD7714C1, 0x769C119E, 0xA5530A7D, +> 0x1EEACB59, 0x30FD21BB, 0x082A3691, 0x1C4C9BCA, +> 0x420F27DE, 0xA8FDA3AE, 0xE182142E, 0x5102F0FF, +> 0x15B82277, 0x120C3217, 0x7BE714ED, 0xA251DCD5, +> 0x6FB4F831, 0xB71D7B32, 0xD5F7A04A, 0x763E1A20, +> 0x38E68B0C, 0xBB5A4121, 0x9340BF06, 0x948B03F8, +> 0xE71BF17B, 0x1BB5F06B, 0x26F2A200, 0x5F28C415 +> ``` + +`mix[15]` - + +> ``` +> 0xC818CD64, 0xBC910343, 0xB18B7776, 0x7182DEBA, +> 0x9DB319EE, 0x9AE7F32F, 0x3CA9F8B5, 0xC63F48ED, +> 0x8321533A, 0x059C96B1, 0x8DCDA60A, 0x75B6C1D1, +> 0xC3406B57, 0x3DFE9E9B, 0xC01E1FD7, 0xC4643218, +> 0x6873F0BA, 0x8ABD36B9, 0xA74D0CBD, 0x8A637118, +> 0x6916416C, 0xB6E3A8DD, 0xB68DD4FA, 0xFBD543EE, +> 0x56F05592, 0x33D6DB82, 0x58D0A7DD, 0x18630C6E, +> 0xB33749CA, 0x5D2E87F7, 0x0F3C39DB, 0x3CAE9895 +> ``` + +## progPowHash + +Block 30000: + +- `prog_seed` - 600 +- `nonce` - `123456789abcdef0` +- `header` - `ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff` +- _digest_ - `11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d` +- _result_ - `5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece` + +Block 0: + +- `prog_seed` - 0 +- `nonce` - `0000000000000000` +- `header` - `0000000000000000000000000000000000000000000000000000000000000000` +- _digest_ - `faeb1be51075b03a4ff44b335067951ead07a3b078539ace76fd56fc410557a3` +- _result_ - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12` + +Block 49: + +- `prog_seed` - 0 +- `nonce` - `0000000006ff2c47` +- `header` - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b` +- _digest_ - `c789c1180f890ec555ff42042913465481e8e6bc512cb981e1c1108dc3f2227d` +- _result_ - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd92` + +Block 50: + +- `prog_seed` - 1 +- `nonce` - `00000000076e482e` +- `header` - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922` +- _digest_ - `c7340542c2a06b3a7dc7222635f7cd402abf8b528ae971ddac6bbe2b0c7cb518` +- _result_ - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188` + +Block 99: + +- `prog_seed` - 1 +- `nonce` - `000000003917afab` +- `header` - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d` +- _digest_ - `f5e60b2c5bfddd136167a30cbc3c8dbdbd15a512257dee7964e0bc6daa9f8ba7` +- _result_ - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcc` + +Block 29,950: + +- `prog_seed` - 599 +- `nonce` - `005d409dbc23a62a` +- `header` - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce` +- _digest_ - `07393d15805eb08ee6fc6cb3ad4ad1010533bd0ff92d6006850246829f18fd6e` +- _result_ - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f` + +Block 29,999: + +- `prog_seed` - 599 +- `nonce` - `005db5fa4c2a3d03` +- `header` - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5` +- _digest_ - `7551bddf977491da2f6cfc1679299544b23483e8f8ee0931c4c16a796558a0b8` +- _result_ - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c645` + +Block 30,000: + +- `prog_seed` - 600 +- `nonce` - `005db8607994ff30` +- `header` - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454` +- _digest_ - `f1c2c7c32266af9635462e6ce1c98ebe4e7e3ecab7a38aaabfbf2e731e0fbff4` +- _result_ - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef6` + +Block 30,049: + +- `prog_seed` - 600 +- `nonce` - `005e2e215a8ca2e7` +- `header` - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64` +- _digest_ - `57fe6a9fbf920b4e91deeb66cb0efa971e08229d1a160330e08da54af0689add` +- _result_ - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe0904` + +Block 30,050: + +- `prog_seed` - 601 +- `nonce` - `005e30899481055e` +- `header` - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047` +- _digest_ - `ba30c61cc5a2c74a5ecaf505965140a08f24a296d687e78720f0b48baf712f2d` +- _result_ - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc7` + +Block 30,099: + +- `prog_seed` - 601 +- `nonce` - `005ea6aef136f88b` +- `header` - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71` +- _digest_ - `cfd5e46048cd133d40f261fe8704e51d3f497fc14203ac6a9ef6a0841780b1cd` +- _result_ - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd` + +Block 59,950: + +- `prog_seed` - 1,199 +- `nonce` - `02ebe0503bd7b1da` +- `header` - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6` +- _digest_ - `21511fbaa31fb9f5fc4998a754e97b3083a866f4de86fa7500a633346f56d773` +- _result_ - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19c` + +Block 59,999: + +- `prog_seed` - 1,199 +- `nonce` - `02edb6275bd221e3` +- `header` - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf` +- _digest_ - `653eda37d337e39d311d22be9bbd3458d3abee4e643bee4a7280a6d08106ef98` +- _result_ - `341562d10d4afb706ec2c8d5537cb0c810de02b4ebb0a0eea5ae335af6fb2e8` + +Block 10,000,000: + +- `prog_seed` - 200,000 +- `nonce` - `005e30899481055e` +- `header` - `efda178de857b2b1703d8d5403bd0f848e19cff5c50ba5c0d6210ddb16250ec3` +- _digest_ - `b2403f56c426177856eaf0eedd707c86ae78a432b9169c3689a67058fcf2a848` +- _result_ - `206aee640c0fd21473d5cc3654d63c80442d9e2dfa676d2801d3ec1fbab38a6d` + +Block 100,000,000: + +- `prog_seed` - 2,000,000 +- `nonce` - `02abe0589481055e` +- `header` - `49e15ba4bf501ce8fe88765403bd0f848e19cff5c50ba5c0d6210ddb16250ec3` +- _digest_ - `ac452084d6f4e6eacf4282ad58dbd4ce7ef2653fb5e6b5c877f56928c907432a` +- _result_ - `b879f84923e71b812ef5a42ece0b5b9366c31cab218f40afe65f8a2cae448a6f` \ No newline at end of file From 8c31a9b78b5017a51957a2bfd3459f5d175080fc Mon Sep 17 00:00:00 2001 From: Fabian Vogelsteller Date: Sun, 3 Mar 2019 14:14:33 +0100 Subject: [PATCH 050/431] Automatically merged updates to draft EIP(s) 1193 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1193.md | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/EIPS/eip-1193.md b/EIPS/eip-1193.md index 4302426f..26fd23fb 100644 --- a/EIPS/eip-1193.md +++ b/EIPS/eip-1193.md @@ -1,13 +1,12 @@ --- eip: 1193 title: Ethereum Provider JavaScript API -author: Ryan Ghods (@ryanio), Marc Garreau (@marcgarreau), Fabian Vogelsteller (@frozeman), Victor Maia (@MaiaVictor) +author: Fabian Vogelsteller (@frozeman), Ryan Ghods (@ryanio), Marc Garreau (@marcgarreau), Victor Maia (@MaiaVictor) discussions-to: https://ethereum-magicians.org/t/eip-1193-ethereum-provider-javascript-api/640 status: Draft type: Standards Track category: Interface created: 2018-06-30 -requires: 1102 --- ## Summary @@ -42,13 +41,22 @@ Events are emitted using [EventEmitter](https://nodejs.org/api/events.html). #### notification -All subscriptions from the node emit on `notification`. Attach listeners with: +All subscriptions from the node emit on "subscription type" (e.g. `eth_subscription`, or `ssh_subscription`). Attach listeners with: ```js -ethereum.on('notification', listener: (result: any) => void): this; +ethereum.on('eth_subscription', listener: (result: any) => void): this; ``` -To create a subscription, call `ethereum.send('eth_subscribe')` or `ethereum.send('shh_subscribe')`. The subscription `result` object will emit through `notification`. +To create a subscription, call `ethereum.send('eth_subscribe')` or `ethereum.send('shh_subscribe')`. The subscription object will emit through the specifc subscription type. + +The result object will look as follows: + +```js +{ + "subscription":"0xc3b33aa549fb9a60e95d21862596617c", + "result": {...} +} +``` See the [eth subscription methods](https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB#supported-subscriptions) and [shh subscription methods](https://github.com/ethereum/go-ethereum/wiki/Whisper-v6-RPC-API#shh_subscribe). @@ -102,10 +110,11 @@ The event emits with `accounts`, an array of the accounts' addresses. ```js const ethereum = window.ethereum; -// A) Primary use case - set provider in web3.js -web3.setProvider(ethereum); +// A) Set provider in web3.js +var web3 = new Web3(ethereum); -// B) Secondary use case - use provider object directly + +// B) Use provider object directly // Example 1: Log last block ethereum .send('eth_getBlockByNumber', ['latest', 'true']) @@ -119,6 +128,7 @@ ethereum ); }); + // Example 2: Request accounts ethereum .send('eth_requestAccounts') @@ -136,6 +146,7 @@ ethereum ); }); + // Example 3: Log available accounts ethereum .send('eth_accounts') @@ -149,13 +160,14 @@ ethereum ); }); + // Example 4: Log new blocks let subId; ethereum .send('eth_subscribe', ['newHeads']) .then(subscriptionId => { subId = subscriptionId; - ethereum.on('notification', result => { + ethereum.on('eth_subscription', result => { if (result.subscription === subscriptionId) { if (result.result instanceof Error) { const error = result.result; @@ -176,6 +188,7 @@ ethereum Code: ${error.code}. Data: ${error.data}` ); }); + // to unsubscribe ethereum .send('eth_unsubscribe', [subId]) @@ -189,6 +202,7 @@ ethereum ); }); + // Example 5: Log when accounts change const logAccounts = accounts => { console.log(`Accounts:\n${accounts.join('\n')}`); @@ -205,19 +219,13 @@ ethereum.on('close', (code, reason) => { ## Specification -### Send +### Errors -The `send` method **MUST** send a properly formatted [JSON-RPC request](https://www.jsonrpc.org/specification#request_object). - -If the Ethereum JSON-RPC API returns a response object with no error, then the Promise **MUST** resolve with the `response.result` object untouched by the implementing Ethereum Provider. - -If the Ethereum JSON-RPC API returns response object that contains an error property then the Promise **MUST** reject with an Error object containing the `response.error.message` as the Error message, `response.error.code` as a code property on the error and `response.error.data` as a data property on the error. +If the Ethereum Provider request returns an error property then the Promise **MUST** reject with an Error object containing the `error.message` as the Error message, `error.code` as a code property on the error and `error.data` as a data property on the error. If an error occurs during processing, such as an HTTP error or internal parsing error, then the Promise **MUST** reject with an `Error` object. -If the implementing Ethereum Provider is not talking to an external Ethereum JSON-RPC API provider then it **MUST** resolve with an object that matches the JSON-RPC API object as specified in the [Ethereum JSON-RPC documentation](https://github.com/ethereum/wiki/wiki/JSON-RPC). - -If the JSON-RPC request requires an account that is not yet authenticated, the Promise **MUST** reject with Error code 4100. +If the request requires an account that is not yet authenticated, the Promise **MUST** reject with Error code 4100. #### eth_requestAccounts @@ -237,7 +245,7 @@ The provider **SHOULD** extend from `EventEmitter` to provide dapps flexibility #### notification -All subscriptions received from the node **MUST** emit the `message.params` to the eventName `notification` without modification. +All subscriptions received from the node **MUST** emit the `subscription` property with the subscription ID and a `results` property. #### connect From 6f0667ffadc89271831b720c509ea26de767de0f Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Sun, 3 Mar 2019 16:42:45 +0100 Subject: [PATCH 051/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 49ccbecc..f491c429 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -1,7 +1,7 @@ --- eip: 777 title: A New Advanced Token Standard -author: Jacques Dafflon , Jordi Baylina , Thomas Shababi +author: Jacques Dafflon , Jordi Baylina , Thomas Shababi discussions-to: https://github.com/ethereum/EIPs/issues/777 status: Draft type: Standards Track From 6838caf5ab1104e8d66374da0d467eea4dbf44ee Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 4 Mar 2019 01:31:32 +0100 Subject: [PATCH 052/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index f491c429..6d772c6c 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -624,7 +624,7 @@ Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` ad > `data`: Extra information provided by the *token holder* for a send and nothing (empty bytes) for a mint. > `operatorData`: Extra information provided by the address which triggered the balance increase. -The following rules apply when calling the `tokensToSend` hook: +The following rules apply when calling the `tokensReceived` hook: - The `tokensReceived` hook MUST be called every time the balance is incremented. - The `tokensReceived` hook MUST be called *after* the state is updated—i.e. *after* the balance is incremented. From 567ba3ba123a3ebf1ed24122420fe57d9aaa1eea Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 4 Mar 2019 01:37:12 +0100 Subject: [PATCH 053/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 6d772c6c..60cf4791 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -493,7 +493,7 @@ Token contracts MAY implement other functions to burn tokens. **`burn` function** ``` solidity -function burn(uint256 amount) public; +function burn(uint256 amount, bytes data) public; ``` Burn the `amount` of tokens from the address `msg.sender`. @@ -502,11 +502,12 @@ The *operator* and the *token holder* MUST both be the `msg.sender`. > **parameters** > `amount`: Number of tokens to burn. +> `data`: Information provided by the *token holder*. **`operatorBurn` function** ``` solidity -function operatorBurn(address from, uint256 amount, bytes operatorData) public; +function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public; ``` Burn the `amount` of tokens on behalf of the address `from`. From 215f3417069024df3411ca74bc5e4836b6ecd35a Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 4 Mar 2019 01:45:51 +0100 Subject: [PATCH 054/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 60cf4791..3fbbe635 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -66,7 +66,7 @@ interface ERC777Token { bytes operatorData ); event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); - event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData); + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); event AuthorizedOperator(address indexed operator, address indexed tokenHolder); event RevokedOperator(address indexed operator, address indexed tokenHolder); } @@ -471,10 +471,17 @@ The token contract MAY burn tokens for multiple *token holders* at once. In this *NOTE*: Burning an amount of zero (`0`) tokens is valid and MUST be treated as a regular burn. +*NOTE*: The `data` field contains information provided by the token holder—similar +to the data field in a regular ether send transaction. +The `tokensToSend()` hook, the `tokensReceived()`, or both +MAY use the information to decide if they wish to reject the transaction. + +*NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*. + **`Burned` event** ``` solidity -event Burned(address indexed operator, address indexed from, uint256 amount, bytes operatorData) +event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); ``` Indicate the burning of `amount` of tokens from the `from` address by the `operator` address. From f26347110c6c6104afa88fde63741a22b32071b5 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 4 Mar 2019 01:59:50 +0100 Subject: [PATCH 055/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 51 ++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 3fbbe635..42924448 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -31,7 +31,7 @@ This standard tries to improve the widely used [ERC20] token standard. The main 3. Both contracts and regular addresses can control and reject which token they receive by registering a `tokensReceived` hook. (Rejection is done by `revert`ing in the hook function.) 4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. 5. The token holder can "authorize" and "revoke" operators which can send tokens on their behalf. These operators are intended to be verified contracts such as an exchange, a cheque processor or an automatic charging system. -6. Every token transaction contains a `data` bytes field and a similar `operatorData` to be used freely to pass data to the recipient. +6. Every token transaction contains `data` and `operatorData` bytes fields to be used freely to pass data from the token holder and the operator, respectively. 7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function by deploying a proxy contract implementing the `tokensReceived` hook for the wallet. ## Specification @@ -291,7 +291,7 @@ When an *operator* sends an `amount` of tokens from a *token holder* to a *recip - The balance of the *recipient* MUST be increased by the `amount`. - The balance of the *token holder* MUST be greater or equal to the `amount`—such that its resulting balance is greater or equal to zero (`0`) after the send. - The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent]. -- The *operator* MAY communicate any information in the `operatorData`. +- The *operator* MAY include information in the `operatorData`. - The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820]. - The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820]. - The `data` and `operatorData` MUST be immutable during the entire send process—hence the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event. @@ -322,7 +322,14 @@ The token contract MAY send tokens from many *token holders*, to many *recipient - The token contract MUST call the `tokensReceived` hook *after* updating the state. I.e., `tokensToSend` MUST be called first, then the balances MUST be updated to reflect the send, and finally `tokensReceived` MUST be called *afterward*. Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send. -*NOTE*: The `data` field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically, `data` is used to describe the intent behind the send. The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. +*NOTE*: The `data` field contains information provided by the token holder—similar +to the data field in a regular ether send transaction. +The `tokensToSend()` hook, the `tokensReceived()`, or both +MAY use the information to decide if they wish to reject the transaction. + +*NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*. + +Typically, `data` is used to describe the intent behind the send. The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. **`Sent` event** @@ -339,8 +346,8 @@ Indicate a send of `amount` of tokens from the `from` address to the `to` addres > `from`: Token holder. > `to`: Token recipient. > `amount`: Number of tokens to send. -> `data`: Information attached to the send, and intended for the recipient (`to`). -> `operatorData`: Information attached to the send by the `operator`. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. The `send` and `operatorSend` functions described below MUST be implemented to send tokens. Token contracts MAY implement other functions to send tokens. @@ -360,7 +367,7 @@ The *operator* and the *token holder* MUST both be the `msg.sender`. > **parameters** > `to`: Token recipient. > `amount`: Number of tokens to send. -> `data`: Information attached to the send, and intended for the recipient (`to`). +> `data`: Information provided by the *token holder*. **`operatorSend` function** @@ -380,8 +387,8 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the > `from`: Token holder (or `0x0` to set `from` to `msg.sender`). > `to`: Token recipient. > `amount`: Number of tokens to send. -> `data`: Information attached to the send, and intended for the recipient (`to`). -> `operatorData`: Information attached to the send by the `operator`. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. #### **Minting Tokens** @@ -396,6 +403,7 @@ Nonetheless, the rules below MUST be respected when minting for a *recipient*: - The token contract MUST emit a `Minted` event with the correct values as defined in the [`Minted` Event][minted]. - The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820]. - The `data` and `operatorData` MUST be immutable during the entire mint process—hence the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. +- The `data` field MUST be empty. The token contract MUST `revert` when minting in any of the following cases: @@ -418,7 +426,10 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca *NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint. -*NOTE*: The `data` field contains extra information intended for, and defined by the recipient— similar to the data field in a regular ether send transaction. Typically, `data` is used to describe the intent behind the mint. The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. +*NOTE*: The `operatorData` field contains information provided by the *operator*—similar +to the data field in a regular ether send transaction. +The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction. + **`Minted` event** @@ -434,8 +445,8 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` > `operator`: Address which triggered the mint. > `to`: Token recipient. > `amount`: Number of tokens minted. -> `data`: Information attached to the minting, and intended for the recipient (`to`). -> `operatorData`: Information attached to the minting by the `operator`. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. #### **Burning Tokens** @@ -450,7 +461,6 @@ The rules below MUST be respected when burning the tokens of a *token holder*: - The token contract MUST emit a `Burned` event with the correct values as defined in the [`Burned` Event][burned]. - The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820]. - The `operatorData` MUST be immutable during the entire burn process—hence the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. -- The `data` field of the `tokensToSend` hook MUST be empty. The token contract MUST `revert` when burning in any of the following cases: @@ -491,8 +501,9 @@ Indicate the burning of `amount` of tokens from the `from` address by the `opera > **parameters** > `operator`: Address which triggered the burn. > `from`: Token holder whose tokens are burned. -> `amount`: Number of tokens burned. -> `operatorData`: Information attached to the burn by the `operator`. +> `amount`: Number of tokens burned. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. The `burn` and `operatorBurn` functions described below MUST be implemented to burn tokens. Token contracts MAY implement other functions to burn tokens. @@ -526,7 +537,8 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the > **parameters** > `from`: Token holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`). > `amount`: Number of tokens to burn. -> `operatorData`: Information attached to the burn by the *operator*. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. *NOTE*: The *operator* MAY pass any information via `operatorData`. The `operatorData` MUST only be provided by the *operator*. @@ -566,8 +578,8 @@ Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` addr > `from`: *token holder*. > `to`: *token recipient* for a send and `0x` for a burn. > `amount`: Number of tokens the *token holder* balance is decreased by. -> `data`: Extra information provided by the *token holder*. -> `operatorData`: Extra information provided by the address which triggered the balance decrease. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. The following rules apply when calling the `tokensToSend` hook: @@ -579,7 +591,6 @@ The following rules apply when calling the `tokensToSend` hook: - `to` MUST be `0x0` for a burn. - `amount` MUST be the number of tokens the *token holder* balance is decreased by. - `data` MUST contain the extra information provided by the *token holder* (if any) for a send. -- `data` MUST be empty for a burn. - `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any). - The *token holder* MAY block a decrease of its balance by `revert`ing. (I.e., reject the withdrawal of tokens from its account.) @@ -629,8 +640,8 @@ Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` ad > `from`: *token holder* for a send and `0x` for a mint. > `to`: *token recipient*. > `amount`: Number of tokens the *recipient* balance is increased by. -> `data`: Extra information provided by the *token holder* for a send and nothing (empty bytes) for a mint. -> `operatorData`: Extra information provided by the address which triggered the balance increase. +> `data`: Information provided by the *token holder*. +> `operatorData`: Information provided by the *operator*. The following rules apply when calling the `tokensReceived` hook: From de6663563efc536beb8ea9eb96c03fd398294b49 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 4 Mar 2019 02:12:53 +0100 Subject: [PATCH 056/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 42924448..70152727 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -40,22 +40,22 @@ This standard tries to improve the widely used [ERC20] token standard. The main ``` solidity interface ERC777Token { - function name() public view returns (string); - function symbol() public view returns (string); - function totalSupply() public view returns (uint256); - function balanceOf(address owner) public view returns (uint256); - function granularity() public view returns (uint256); + function name() external view returns (string); + function symbol() external view returns (string); + function totalSupply() external view returns (uint256); + function balanceOf(address owner) external view returns (uint256); + function granularity() external view returns (uint256); - function defaultOperators() public view returns (address[]); - function authorizeOperator(address operator) public; - function revokeOperator(address operator) public; - function isOperatorFor(address operator, address tokenHolder) public view returns (bool); + function defaultOperators() external view returns (address[]); + function authorizeOperator(address operator) external; + function revokeOperator(address operator) external; + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); - function send(address to, uint256 amount, bytes data) public; - function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public; + function send(address to, uint256 amount, bytes data) external; + function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external; - function burn(uint256 amount, bytes data) public; - function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public; + function burn(uint256 amount, bytes data) external; + function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external; event Sent( address indexed operator, @@ -86,7 +86,7 @@ The `view` functions detailed below MUST be implemented. **`name` function** ``` solidity - function name() public view returns (string) + function name() external view returns (string) ``` Returns the name of the token, e.g., `"MyToken"`. @@ -96,7 +96,7 @@ Returns the name of the token, e.g., `"MyToken"`. **`symbol` function** ``` solidity -function symbol() public view returns (string) +function symbol() external view returns (string) ``` Returns the symbol of the token, e.g., `"MYT"`. @@ -106,7 +106,7 @@ Returns the symbol of the token, e.g., `"MYT"`. **`totalSupply` function** ``` solidity -function totalSupply() public view returns (uint256) +function totalSupply() external view returns (uint256) ``` Get the total number of minted tokens. @@ -121,7 +121,7 @@ Get the total number of minted tokens. **`balanceOf` function** ``` solidity -function balanceOf(address tokenHolder) public view returns (uint256) +function balanceOf(address tokenHolder) external view returns (uint256) ``` Get the balance of the account with address `tokenHolder`. @@ -136,7 +136,7 @@ The balance MUST be zero (`0`) or higher. **`granularity` function** ``` solidity -function granularity() public view returns (uint256) +function granularity() external view returns (uint256) ``` Get the smallest part of the token that's not divisible. @@ -231,7 +231,7 @@ Token contracts MAY implement other functions to manage *operators*. **`defaultOperators` function** ``` solidity -function defaultOperators() public view returns (address[]) +function defaultOperators() external view returns (address[]) ``` Get the list of *default operators* as defined by the token contract. @@ -243,7 +243,7 @@ Get the list of *default operators* as defined by the token contract. **`authorizeOperator` function** ``` solidity -function authorizeOperator(address operator) public +function authorizeOperator(address operator) external ``` Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf. @@ -256,7 +256,7 @@ Set a third party `operator` address as an *operator* of `msg.sender` to send an **`revokeOperator` function** ``` solidity -function revokeOperator(address operator) public +function revokeOperator(address operator) external ``` Remove the right of the `operator` address to be an *operator* for `msg.sender` and to send and burn tokens on its behalf. @@ -269,7 +269,7 @@ Remove the right of the `operator` address to be an *operator* for `msg.sender` **`isOperatorFor` function** ``` solidity -function isOperatorFor(address operator, address tokenHolder) public view returns (bool) +function isOperatorFor(address operator, address tokenHolder) external view returns (bool) ``` Indicate whether the `operator` address is an *operator* of the `tokenHolder` address. @@ -357,7 +357,7 @@ Token contracts MAY implement other functions to send tokens. **`send` function** ``` solidity -function send(address to, uint256 amount, bytes data) public +function send(address to, uint256 amount, bytes data) external ``` Send the `amount` of tokens from the address `msg.sender` to the address `to`. @@ -372,7 +372,7 @@ The *operator* and the *token holder* MUST both be the `msg.sender`. **`operatorSend` function** ``` solidity -function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) public +function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external ``` Send the `amount` of tokens on behalf of the address `from` to the address `to`. @@ -511,7 +511,7 @@ Token contracts MAY implement other functions to burn tokens. **`burn` function** ``` solidity -function burn(uint256 amount, bytes data) public; +function burn(uint256 amount, bytes data) external; ``` Burn the `amount` of tokens from the address `msg.sender`. @@ -525,7 +525,7 @@ The *operator* and the *token holder* MUST both be the `msg.sender`. **`operatorBurn` function** ``` solidity -function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) public; +function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external; ``` Burn the `amount` of tokens on behalf of the address `from`. From 63977eaf35b961a5b6eff5dd75537053deb23d7d Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 4 Mar 2019 02:21:09 +0100 Subject: [PATCH 057/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 70152727..256fb981 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -557,7 +557,7 @@ interface ERC777TokensSender { uint256 amount, bytes data, bytes operatorData - ) public; + ) external; } ``` @@ -566,7 +566,7 @@ interface ERC777TokensSender { **`tokensToSend`** ``` solidity -function tokensToSend(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) public +function tokensToSend(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) external ``` Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. @@ -614,7 +614,7 @@ interface ERC777TokensRecipient { uint256 amount, bytes data, bytes operatorData - ) public; + ) external; } ``` @@ -628,7 +628,7 @@ If the *recipient* is a contract, which has not registered an `ERC777TokensRecip **`tokensReceived`** ``` solidity -function tokensReceived(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) public +function tokensReceived(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) external ``` Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. From f4a5765102d67fb49b59ed8c98fdea4d018f8735 Mon Sep 17 00:00:00 2001 From: Gabriel Barros Date: Mon, 4 Mar 2019 15:00:49 -0500 Subject: [PATCH 058/431] Universal Upgradeable Proxy standard --- EIPS/eip-xxxx.md | 350 +++++++++++++++++++++++++++++++++ assets/eip-x/proxy-diagram.png | Bin 0 -> 21986 bytes 2 files changed, 350 insertions(+) create mode 100644 EIPS/eip-xxxx.md create mode 100644 assets/eip-x/proxy-diagram.png diff --git a/EIPS/eip-xxxx.md b/EIPS/eip-xxxx.md new file mode 100644 index 00000000..e6e83680 --- /dev/null +++ b/EIPS/eip-xxxx.md @@ -0,0 +1,350 @@ +--- +eip: TBA +title: Universal Upgradeable Proxy Standard (UUPS) +authors: Gabriel Barros , Patrick Gallagher +discussions-to: [Ethereum Magicians Forum](https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups) +status: Draft +type: Standards Track +category: ERC +created: 2019-02-12 +requires: nothing +--- + +## Table of contents + + + +- [Table of contents](#table-of-contents) +- [Simple Summary](#simple-summary) +- [Abstract](#abstract) +- [Motivation](#motivation) +- [Terminology](#terminology) +- [Specification](#specification) + - [Proxy Contract](#proxy-contract) + - [Functions](#functions) + - [`fallback`](#fallback) + - [`constructor`](#constructor) + - [Proxiable Contract](#proxiable-contract) + - [Functions](#functions-1) + - [`proxiable`](#proxiable) + - [`updateCodeAddress`](#updatecodeaddress) +- [Pitfalls when using a proxy](#pitfalls-when-using-a-proxy) + - [Separating Variables from Logic](#separating-variables-from-logic) + - [Restricting dangerous functions](#restricting-dangerous-functions) +- [Examples](#examples) + - [Owned](#owned) + - [ERC-20 Token](#erc-20-token) + - [Proxy Contract](#proxy-contract-1) + - [Token Logic Contract](#token-logic-contract) +- [References](#references) +- [Copyright](#copyright) + + +## Simple Summary + +Standard upgradeable proxy contract. + +## Abstract + +The following describes a standard for proxy contracts which is universally compatible with all contracts, and does not create incompatibility between the proxy and business-logic contracts. This is achieved by utilizing a unique storage position in the proxy contract to store the Logic Contract's address. A compatibility check ensures successful upgrades. Upgrading can be performed unlimited times, or as determined by custom logic. In addition, a method for selecting from multiple constructors is provided, which does not inhibit the ability to verify bytecode. + +## Motivation + +- Improve upon existing proxy implementations to improve developer experience for deploying and maintaining Proxy and Logic Contracts. + +- Standardize and improve the methods for verifying the bytecode used by the Proxy Contract. + +## Terminology + +- `delegatecall()` - Function in contract **A** which allows an external contract **B** (delegating) to modify **A**'s storage (see diagram below, [Solidity docs](https://solidity.readthedocs.io/en/v0.5.3/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries)) +- **Proxy Contract** - The contract **A** which stores data, but uses the logic of external contract **B** by way of `delegatecall()`. +- **Logic Contract** - The contract **B** which contains the logic used by Proxy Contract **A** +- **Proxiable Contract** - Inherited in Logic Contract **B** to provide the upgrade functionality + +

diagram

+ +## Specification + +The Proxy Contract proposed here should be deployed _as is_, and used as a drop-in replacement for any existing methods of lifecycle management of contracts. In addition to the Proxy Contract, we propose the Proxiable Contract interface/base which establishes a pattern for the upgrade which does not interfere with existing business rules. The logic for allowing upgrades can be implemented as needed. + +### Proxy Contract + +#### Functions + +##### `fallback` + +The proposed fallback function follows the common pattern seen in other Proxy Contract implementations such as [Zeppelin][1] or [Gnosis][2]. + +However, rather than forcing use of a variable, the address of the Logic Contract is stored at the defined storage position `keccak256("PROXIABLE")`. This eliminates the possibility of collision between variables in the Proxy and Logic Contracts, thus providing "universal" compatibility with any Logic Contract. + +```javascript +function() external payable { + assembly { // solium-disable-line + let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) + calldatacopy(0x0, 0x0, calldatasize) + let success := delegatecall(sub(gas, 10000), contractLogic, 0x0, calldatasize, 0, 0) + let retSz := returndatasize + returndatacopy(0, 0, retSz) + switch success + case 0 { + revert(0, retSz) + } + default { + return(0, retSz) + } + } +} +``` + +#### `constructor` + +The proposed constructor accepts any number of arguments of any type, and thus is compatible with any Logic Contract constructor function. + +In addition, the arbitrary nature of the Proxy Contract's constructor provides the ability to select from one or more constructor functions available in the Logic Contract source code (e.g., `constructor1`, `constructor2`, ... etc. ). Note that if multiple constructors are included in the Logic Contract, a check should be included to prohibit calling a constructor again post-initialization. + +It's worth noting that the added functionality of supporting multiple constructors does not inhibit verification of the Proxy Contract's bytecode, since the initialization tx call data (input) can be decoded by first using the Proxy Contract ABI, and then using the Logic Contract ABI. + +The contract below shows the proposed implementation of the Proxy Contract. + +```javascript +contract Proxy { + // Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7" + constructor(bytes memory constructData, address contractLogic) public { + // save the code address + assembly { // solium-disable-line + sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, contractLogic) + } + (bool success, bytes memory _ ) = contractLogic.delegatecall(constructData); // solium-disable-line + require(success, "Construction failed"); + } + + function() external payable { + assembly { // solium-disable-line + let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) + calldatacopy(0x0, 0x0, calldatasize) + let success := delegatecall(sub(gas, 10000), contractLogic, 0x0, calldatasize, 0, 0) + let retSz := returndatasize + returndatacopy(0, 0, retSz) + switch success + case 0 { + revert(0, retSz) + } + default { + return(0, retSz) + } + } + } +} +``` + +### Proxiable Contract + +The Proxiable Contract is included in the Logic Contract, and provides the functions needed to perform an upgrade. The compatibility check `proxiable` prevents irreparable updates during an upgrade. + +> :warning: Warning: `updateCodeAddress` and `proxiable` must be present in the Logic Contract. Failure to include these may prevent upgrades, and could allow the Proxy Contract to become entirely unusable. See below [Restricting dangerous functions](#restricting-dangerous-functions) + +#### Functions + +##### `proxiable` + +Compatibility check to ensure the new Logic Contract implements the Universal Upgradeable Proxy Standard. Note that in order to support future implementations, the `bytes32` comparison could be changed e.g., `keccak256("PROXIABLE-ERCXXX-v1")`. + +##### `updateCodeAddress` + +Stores the Logic Contract's address at storage `keccak256("PROXIABLE")` in the Proxy Contract. + +The contract below shows the proposed implementation of the Proxiable Contract. + +```javascript +contract Proxiable { + // Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7" + + function updateCodeAddress(address newAddress) internal { + require( + bytes32(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) == Proxiable(newAddress).proxiableUUID(), + "Not compatible" + ); + assembly { // solium-disable-line + sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, newAddress) + } + } + function proxiableUUID() public pure returns (bytes32) { + return 0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7; + } +} +``` + +## Pitfalls when using a proxy + +The following common best practices should be employed for all Logic Contracts when using a proxy contract. + +### Separating Variables from Logic + +Careful consideration should be made when designing a new Logic Contract to prevent incompatibility with the existing storage of the Proxy Contract after an upgrade. Specifically, the order in which variables are instantiated in the new contract should not be modified, and any new variables should be added after all existing variables from the previous Logic Contract + +To facilitate this practice, we recommend utilizing a single "base" contract which holds all variables, and which is inherited in subsequent logic contract(s). This practice greatly reduces the chances of accidentally reordering variables or overwriting them in storage. + +### Restricting dangerous functions + +The compatibility check in the Proxiable Contract is a safety mechanism to prevent upgrading to a Logic Contract which does not implement the Universal Upgradeable Proxy Standard. However, as occurred in the parity wallet hack, it is still possible to perform irreparable damage to the Logic Contract itself. + +In order to prevent damage to the Logic Contract, we recommend restricting permissions for any potentially damaging functions to `onlyOwner`, and giving away ownership of the Logic Contract immediately upon deployment to a null address (e.g., address(1)). Potentially damaging functions include native functions such as `SELFDESTRUCT`, as well functions whose code may originate externally such as `CALLCODE`, and `delegatecall()`. In the [ERC-20 Token](#erc20-token) example below, a `LibraryLock` contract is used to prevent destruction of the logic contract. + +## Examples + +### Owned + +In this example, we show the standard ownership example, and restrict the `updateCodeAddress` to only the owner. + +```javascript +contract Owned is Proxiable { + // ensures no one can manipulate this contract once it is deployed + address public owner = address(1); + + function constructor1() public{ + // ensures this can be called only once per *proxy* contract deployed + require(owner == address(0)); + owner = msg.sender; + } + + function updateCode(address newCode) onlyOwner public { + updateCodeAddress(newCode); + } + + modifier onlyOwner() { + require(msg.sender == owner, "Only owner is allowed to perform this action"); + _; + } +} +``` + +### ERC-20 Token + +#### Proxy Contract + +```javascript +pragma solidity ^0.5.1; + +contract Proxy { + // Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7" + constructor(bytes memory constructData, address contractLogic) public { + // save the code address + assembly { // solium-disable-line + sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, contractLogic) + } + (bool success, bytes memory _ ) = contractLogic.delegatecall(constructData); // solium-disable-line + require(success, "Construction failed"); + } + + function() external payable { + assembly { // solium-disable-line + let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) + calldatacopy(0x0, 0x0, calldatasize) + let success := delegatecall(sub(gas, 10000), contractLogic, 0x0, calldatasize, 0, 0) + let retSz := returndatasize + returndatacopy(0, 0, retSz) + switch success + case 0 { + revert(0, retSz) + } + default { + return(0, retSz) + } + } + } +} +``` + +#### Token Logic Contract + +``` javascript + +contract Proxiable { + // Code position in storage is keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7" + + function updateCodeAddress(address newAddress) internal { + require( + bytes32(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) == Proxiable(newAddress).proxiableUUID(), + "Not compatible" + ); + assembly { // solium-disable-line + sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, newAddress) + } + } + function proxiableUUID() public pure returns (bytes32) { + return 0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7; + } +} + + +contract Owned { + + address owner; + + function setOwner(address _owner) internal { + owner = _owner; + } + modifier onlyOwner() { + require(msg.sender == owner, "Only owner is allowed to perform this action"); + _; + } +} + +contract LibraryLockDataLayout { + bool public initialized = false; +} + +contract LibraryLock is LibraryLockDataLayout { + // Ensures no one can manipulate the Logic Contract once it is deployed. + // PARITY WALLET HACK PREVENTION + + modifier delegatedOnly() { + require(initialized == true, "The library is locked. No direct 'call' is allowed"); + _; + } + function initialize() internal { + initialized = true; + } +} + +contact ERC20DataLayout is LibraryLockDataLayout { + uint256 public totalSupply; + mapping(address=>uint256) public tokens; +} + +contract ERC20 { + // ... + function transfer(address to, uint256 amount) public { + require(tokens[msg.sender] >= amount, "Not enough funds for transfer"); + tokens[to] += amount; + tokens[msg.sender] -= amount; + } +} + +contract MyToken is ERC20DataLayout, ERC20, Owned, Proxiable, LibraryLock { + + function constructor1(uint256 _initialSupply) public { + totalSupply = _initialSupply; + tokens[msg.sender] = _initialSupply; + initialize(); + setOwner(msg.sender); + } + function updateCode(address newCode) public onlyOwner delegatedOnly { + updateCodeAddress(newCode); + } + function transfer(address to, uint256 amount) public delegatedOnly { + ERC20.transfer(to, amount); + } +} +``` + +## References + +- "Escape-hatch" proxy Medium Post (TBA) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +[1]: https://github.com/maraoz/solidity-proxy/blob/master/contracts/Dispatcher.sol +[2]: https://blog.gnosis.pm/solidity-delegateproxy-contracts-e09957d0f201 diff --git a/assets/eip-x/proxy-diagram.png b/assets/eip-x/proxy-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..26747b2b31b3c90e046ecf27cb6b718bb05b18b0 GIT binary patch literal 21986 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 literal 0 HcmV?d00001 From ce4bd0ca5f3fd7c81ad8c1017a52cc50d0e149a0 Mon Sep 17 00:00:00 2001 From: Gabriel Barros Date: Mon, 4 Mar 2019 15:27:45 -0500 Subject: [PATCH 059/431] Updates with eip number to pass travis build --- EIPS/{eip-xxxx.md => eip-1822.md} | 8 ++++---- assets/{eip-x => eip-1822}/proxy-diagram.png | Bin 2 files changed, 4 insertions(+), 4 deletions(-) rename EIPS/{eip-xxxx.md => eip-1822.md} (98%) rename assets/{eip-x => eip-1822}/proxy-diagram.png (100%) diff --git a/EIPS/eip-xxxx.md b/EIPS/eip-1822.md similarity index 98% rename from EIPS/eip-xxxx.md rename to EIPS/eip-1822.md index e6e83680..3dfb9888 100644 --- a/EIPS/eip-xxxx.md +++ b/EIPS/eip-1822.md @@ -1,12 +1,12 @@ --- -eip: TBA +eip: 1822 title: Universal Upgradeable Proxy Standard (UUPS) authors: Gabriel Barros , Patrick Gallagher discussions-to: [Ethereum Magicians Forum](https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups) status: Draft type: Standards Track category: ERC -created: 2019-02-12 +created: 2019-03-04 requires: nothing --- @@ -61,7 +61,7 @@ The following describes a standard for proxy contracts which is universally comp - **Logic Contract** - The contract **B** which contains the logic used by Proxy Contract **A** - **Proxiable Contract** - Inherited in Logic Contract **B** to provide the upgrade functionality -

diagram

+

diagram

## Specification @@ -147,7 +147,7 @@ The Proxiable Contract is included in the Logic Contract, and provides the funct ##### `proxiable` -Compatibility check to ensure the new Logic Contract implements the Universal Upgradeable Proxy Standard. Note that in order to support future implementations, the `bytes32` comparison could be changed e.g., `keccak256("PROXIABLE-ERCXXX-v1")`. +Compatibility check to ensure the new Logic Contract implements the Universal Upgradeable Proxy Standard. Note that in order to support future implementations, the `bytes32` comparison could be changed e.g., `keccak256("PROXIABLE-ERC1822-v1")`. ##### `updateCodeAddress` diff --git a/assets/eip-x/proxy-diagram.png b/assets/eip-1822/proxy-diagram.png similarity index 100% rename from assets/eip-x/proxy-diagram.png rename to assets/eip-1822/proxy-diagram.png From 63feeb7bea3e1953cfa4c023da7ff8079d04dfe4 Mon Sep 17 00:00:00 2001 From: Gabriel Barros Date: Mon, 4 Mar 2019 15:41:32 -0500 Subject: [PATCH 060/431] Simplifies title field --- EIPS/eip-1822.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1822.md b/EIPS/eip-1822.md index 3dfb9888..f83293bf 100644 --- a/EIPS/eip-1822.md +++ b/EIPS/eip-1822.md @@ -1,6 +1,6 @@ --- eip: 1822 -title: Universal Upgradeable Proxy Standard (UUPS) +title: Universal Upgradeable Proxy Standard authors: Gabriel Barros , Patrick Gallagher discussions-to: [Ethereum Magicians Forum](https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups) status: Draft From 6435654419ba70b73676cd55af534d93d7a1064e Mon Sep 17 00:00:00 2001 From: Gabriel Barros Date: Mon, 4 Mar 2019 15:50:33 -0500 Subject: [PATCH 061/431] Fixes markdown reference --- EIPS/eip-1822.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1822.md b/EIPS/eip-1822.md index f83293bf..d1660f16 100644 --- a/EIPS/eip-1822.md +++ b/EIPS/eip-1822.md @@ -1,6 +1,6 @@ --- eip: 1822 -title: Universal Upgradeable Proxy Standard +title: Universal Upgradeable Proxy Standard (UUPS) authors: Gabriel Barros , Patrick Gallagher discussions-to: [Ethereum Magicians Forum](https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups) status: Draft @@ -188,7 +188,7 @@ To facilitate this practice, we recommend utilizing a single "base" contract whi The compatibility check in the Proxiable Contract is a safety mechanism to prevent upgrading to a Logic Contract which does not implement the Universal Upgradeable Proxy Standard. However, as occurred in the parity wallet hack, it is still possible to perform irreparable damage to the Logic Contract itself. -In order to prevent damage to the Logic Contract, we recommend restricting permissions for any potentially damaging functions to `onlyOwner`, and giving away ownership of the Logic Contract immediately upon deployment to a null address (e.g., address(1)). Potentially damaging functions include native functions such as `SELFDESTRUCT`, as well functions whose code may originate externally such as `CALLCODE`, and `delegatecall()`. In the [ERC-20 Token](#erc20-token) example below, a `LibraryLock` contract is used to prevent destruction of the logic contract. +In order to prevent damage to the Logic Contract, we recommend restricting permissions for any potentially damaging functions to `onlyOwner`, and giving away ownership of the Logic Contract immediately upon deployment to a null address (e.g., address(1)). Potentially damaging functions include native functions such as `SELFDESTRUCT`, as well functions whose code may originate externally such as `CALLCODE`, and `delegatecall()`. In the [ERC-20 Token](#erc-20-token) example below, a `LibraryLock` contract is used to prevent destruction of the logic contract. ## Examples From f6622e2cf3a31d0205a7110eb1d0ce174fee4757 Mon Sep 17 00:00:00 2001 From: Gabriel Barros Date: Mon, 4 Mar 2019 16:19:26 -0500 Subject: [PATCH 062/431] Fixes eip-validator erros with hyperlink and authors --- EIPS/eip-1822.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1822.md b/EIPS/eip-1822.md index d1660f16..41bc7682 100644 --- a/EIPS/eip-1822.md +++ b/EIPS/eip-1822.md @@ -1,8 +1,8 @@ --- eip: 1822 title: Universal Upgradeable Proxy Standard (UUPS) -authors: Gabriel Barros , Patrick Gallagher -discussions-to: [Ethereum Magicians Forum](https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups) +author: Gabriel Barros , Patrick Gallagher +discussions-to: https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups status: Draft type: Standards Track category: ERC From 1aca10b82f4cbe2daef7cb7dae32af926e41b781 Mon Sep 17 00:00:00 2001 From: Gabriel Barros Date: Mon, 4 Mar 2019 16:31:48 -0500 Subject: [PATCH 063/431] Removes 'require' key from the table --- EIPS/eip-1822.md | 1 - 1 file changed, 1 deletion(-) diff --git a/EIPS/eip-1822.md b/EIPS/eip-1822.md index 41bc7682..e9b10f68 100644 --- a/EIPS/eip-1822.md +++ b/EIPS/eip-1822.md @@ -7,7 +7,6 @@ status: Draft type: Standards Track category: ERC created: 2019-03-04 -requires: nothing --- ## Table of contents From bde078d52ecf0cbb537072f43400331dd333d75c Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Mon, 4 Mar 2019 16:46:57 -0500 Subject: [PATCH 064/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index a6906ede..5e98aebf 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -63,9 +63,9 @@ Especially important is efficient translation to and from eWasm. To that end we These forms > *`INSTRUCTION`* > -> *`INSTRUCTION x`* +> *`INSTRUCTION x`* > -> *`INSTRUCTION x, y`* +> *`INSTRUCTION x, y`* name an *`INSTRUCTION`* with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) @@ -96,7 +96,7 @@ To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Br #### Switches, Callbacks, and Virtual Functions -Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. +Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. @@ -181,7 +181,7 @@ frame | 21 ______|___________ 22 <- SP ``` -and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` +and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` ``` PUSH 10 PUSH 11 @@ -244,7 +244,7 @@ _Execution_ is as defined in the [Yellow Paper](https://ethereum.github.io/yello >**5** Invalid instruction -We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. +We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. To handle the return stack we expand the conditions on stack size: >**2a** The size of the data stack does not exceed 1024. @@ -301,7 +301,7 @@ These changes would need to be implemented in phases at decent intervals: >**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely. -If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult. +If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult. ## Rationale @@ -330,7 +330,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_sub[code_size] // is there a BEGINSUB at PC? is_dest[code_size] // is there a JUMPDEST at PC? sub_for_pc[code_size] // which BEGINSUB is PC in? - + bool validate_jumps(PC) { current_sub = PC @@ -350,7 +350,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_dest[PC] = true sub_for_pc[PC] = current_sub } - + // check that targets are in subroutine for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC)) { @@ -374,7 +374,7 @@ Note that code like this is already run by EVMs to check dynamic jumps, includin #### Subroutine Validation -This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|): The sum of the number of edges and number of verticies in the graph. +This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`: The sum of the number of edges and number of verticies in the graph. The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. @@ -424,7 +424,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t return false if instruction is STOP, RETURN, or SUICIDE - return true + return true // violates single entry if instruction is BEGINSUB @@ -447,10 +447,10 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t if instruction is JUMPTO { PC = jump_target(PC) - continue + continue } - // recurse to jump to code to validate + // recurse to jump to code to validate if instruction is JUMPIF { if not validate_subroutine(jump_target(PC), return_pc, SP) From 643ed3fc00607f5dee063a3d679510c1e8967aef Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 4 Mar 2019 18:19:59 -0700 Subject: [PATCH 065/431] Automatically merged updates to draft EIP(s) 1057 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1057.md | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/EIPS/eip-1057.md b/EIPS/eip-1057.md index 2fc96e34..41a27c9d 100644 --- a/EIPS/eip-1057.md +++ b/EIPS/eip-1057.md @@ -33,7 +33,7 @@ The main elements of the algorithm are: * Adds reads from a small, low-latency cache that supports random addresses. * Increases the DRAM read from 128 bytes to 256 bytes. -The random sequence changes every `PROGPOW_PERIOD` (50 blocks or about 12.5 minutes). When mining source code is generated for the random sequence and compiled on the host CPU. The GPU will execute the compiled code where what math to perform and what mix state to use are already resolved. +The random sequence changes every `PROGPOW_PERIOD` (about 2 to 12 minutes depending on the configured value). When mining source code is generated for the random sequence and compiled on the host CPU. The GPU will execute the compiled code where what math to perform and what mix state to use are already resolved. While a custom ASIC to implement this algorithm is still possible, the efficiency gains available are minimal. The majority of a commodity GPU is required to support the above elements. The only optimizations available are: * Remove the graphics pipeline (displays, geometry engines, texturing, etc) @@ -107,17 +107,30 @@ Ethash requires external memory due to the large size of the DAG. However that The DAG is generated exactly as in Ethash. All the parameters (ephoch length, DAG size, etc) are unchanged. See the original [Ethash](https://github.com/ethereum/wiki/wiki/Ethash) spec for details on generating the DAG. ProgPoW can be tuned using the following parameters. The proposed settings have been tuned for a range of existing, commodity GPUs: +* `PROGPOW_PERIOD`: Number of blocks before changing the random program +* `PROGPOW_LANES`: The number of parallel lanes that coordinate to calculate a single hash instance +* `PROGPOW_REGS`: The register file usage size +* `PROGPOW_DAG_LOADS`: Number of uint32 loads from the DAG per lane +* `PROGPOW_CACHE_BYTES`: The size of the cache +* `PROGPOW_CNT_DAG`: The number of DAG accesses, defined as the outer loop of the algorithm (64 is the same as ethash) +* `PROGPOW_CNT_CACHE`: The number of cache accesses per loop +* `PROGPOW_CNT_MATH`: The number of math operations per loop -* `PROGPOW_PERIOD`: Number of blocks before changing the random program; default is `50`. -* `PROGPOW_LANES`: The number of parallel lanes that coordinate to calculate a single hash instance; default is `16`. -* `PROGPOW_REGS`: The register file usage size; default is `32`. -* `PROGPOW_DAG_LOADS`: Number of uint32 loads from the DAG per lane; default is `4`; -* `PROGPOW_CACHE_BYTES`: The size of the cache; default is `16 x 1024`. -* `PROGPOW_CNT_DAG`: The number of DAG accesses, defined as the outer loop of the algorithm; default is `64` (same as Ethash). -* `PROGPOW_CNT_CACHE`: The number of cache accesses per loop; default is `12`. -* `PROGPOW_CNT_MATH`: The number of math operations per loop; default is `20`. +The value of these parameters has been tweaked between version 0.9.2 (live on the gangnum testnet) and 0.9.3 (proposed for Ethereum adoption). See [this medium post](https://medium.com/@ifdefelse/progpow-progress-da5bb31a651b) for details. -The random program changes every `PROGPOW_PERIOD` blocks (default `50`, roughly 12.5 minutes) to ensure the hardware executing the algorithm is fully programmable. If the program only changed every DAG epoch (roughly 5 days) certain miners could have time to develop hand-optimized versions of the random sequence, giving them an undue advantage. +| Parameter | 0.9.2 | 0.9.3 | +|-----------------------|-----------|-----------| +| `PROGPOW_PERIOD` | `50` | `10` | +| `PROGPOW_LANES` | `16` | `16` | +| `PROGPOW_REGS` | `32` | `32` | +| `PROGPOW_DAG_LOADS` | `4` | `4` | +| `PROGPOW_CACHE_BYTES` | `16x1024` | `16x1024` | +| `PROGPOW_CNT_DAG` | `64` | `64` | +| `PROGPOW_CNT_CACHE` | `12` | `11` | +| `PROGPOW_CNT_MATH` | `20` | `18` | + + +The random program changes every `PROGPOW_PERIOD` blocks to ensure the hardware executing the algorithm is fully programmable. If the program only changed every DAG epoch (roughly 5 days) certain miners could have time to develop hand-optimized versions of the random sequence, giving them an undue advantage. Sample code is written in C++, this should be kept in mind when evaluating the code in the specification. @@ -223,7 +236,7 @@ hash32_t keccak_f800_progpow(hash32_t header, uint64_t seed, hash32_t digest) The inner loop uses FNV and KISS99 to generate a random sequence from the `prog_seed`. This random sequence determines which mix state is accessed and what random math is performed. -Since the `prog_seed` changes only once per `PROGPOW_PERIOD` (50 blocks or about 12.5 minutes) it is expected that while mining `progPowLoop` will be evaluated on the CPU to generate source code for that period's sequence. The source code will be compiled on the CPU before running on the GPU. +Since the `prog_seed` changes only once per `PROGPOW_PERIOD` it is expected that while mining `progPowLoop` will be evaluated on the CPU to generate source code for that period's sequence. The source code will be compiled on the CPU before running on the GPU. Test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowInit). From 7c671086530006d18db90de69a00356356a1fd14 Mon Sep 17 00:00:00 2001 From: Witek Date: Tue, 5 Mar 2019 15:48:22 -0800 Subject: [PATCH 066/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 144 ++--------------------------------------------- 1 file changed, 4 insertions(+), 140 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index ae372b93..ea28760a 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -366,134 +366,7 @@ fr.json: ## Approval -The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval on a subset of tokens, standardized scoped approval is available as an extension. More complex approval schemes will require the use of an external contract enforcing custom rules. - -### Scoped Approval Extension - -This extension enables restrictions on approval's reach using a standardized method. When considering a smart contract -managing tokens from multiple different domains, it makes sense to limit approvals to those domains. Scoped approval is a -generalization of this idea. ERC-1155 implementors can define scopes as needed. - -
-Interface - -```solidity -pragma solidity ^0.5.2; - -/** - Note: The ERC-165 identifier for this interface is 0x30168307. -*/ -interface ERC1155ScopedApproval { - /** - @dev MUST emit when approval changes for scope. - */ - event ApprovalForScope(address indexed _owner, address indexed _operator, bytes32 indexed _scope, bool _approved); - - /** - @dev MUST emit when the token IDs are added to the scope. - By default, IDs are in no scope. - The range is inclusive: _idStart, _idEnd, and all IDs in between have been added to the scope. - _idStart must be lower than or equal to _idEnd. - */ - event AddIdsToScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); - - /** - @dev MUST emit when the token IDs are removed from the scope. - The range is inclusive: _idStart, _idEnd, and all IDs in between have been removed from the scope. - _idStart must be lower than or equal to _idEnd. - */ - event RemoveIdsFromScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); - - /** @dev MUST emit when a scope URI is set or changes. - URIs are defined in RFC 3986. - The URI MUST point a JSON file that conforms to the "Scope Metadata JSON Schema". - */ - event ScopeURI(string _value, bytes32 indexed _scope); - - /** - @notice Returns the number of scopes that contain _id. - @param _id The token ID - @return The number of scopes containing the ID - */ - function scopeCountForId(uint256 _id) public view returns (uint32); - - /** - @notice Returns a scope that contains _id. - @param _id The token ID - @param _scopeIndex The scope index to query (valid values are 0 to scopeCountForId(_id)-1) - @return The Nth scope containing the ID - */ - function scopeForId(uint256 _id, uint32 _scopeIndex) public view returns (bytes32); - - /** - @notice Returns a URI that can be queried to get scope metadata. This URI should return a JSON document containing, at least the scope name and description. Although supplying a URI for every scope is recommended, returning an empty string "" is accepted for scopes without a URI. - @param _scope The queried scope - @return The URI describing this scope. - */ - function scopeUri(bytes32 _scope) public view returns (string memory); - - /** - @notice Enable or disable approval for a third party ("operator") to manage the caller's tokens in the specified scope. - @dev MUST emit the ApprovalForScope event on success. - @param _operator Address to add to the set of authorized operators - @param _scope Approval scope (can be identified by calling scopeForId) - @param _approved True if the operator is approved, false to revoke approval - */ - function setApprovalForScope(address _operator, bytes32 _scope, bool _approved) external; - - /** - @notice Queries the approval status of an operator for a given owner, within the specified scope. - @param _owner The owner of the Tokens - @param _operator Address of authorized operator - @param _scope Scope to test for approval (can be identified by calling scopeForId) - @return True if the operator is approved, false otherwise - */ - function isApprovedForScope(address _owner, address _operator, bytes32 _scope) public view returns (bool); -} -``` -
- -
-Scope Metadata JSON Schema - -This shema is similar to the token metadata schema and also allows localization. `{id}` and `{locale}` should be replaced with the proper values. - -```json -{ - "title": "Scope Metadata", - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "description": "Identifies the scope in a human-readable way.", - }, - "description": { - "type": "string", - "description": "Describes the scope to allow users to make informed approval decisions.", - }, - "localization": { - "type": "object", - "required": ["uri", "default", "locales"], - "properties": { - "uri": { - "type": "string", - "description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request." - }, - "default": { - "type": "string", - "description": "The locale of the default data within the base JSON" - }, - "locales": { - "type": "array", - "description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)." - } - } - } - } -} -``` -
+The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface](https://github.com/ethereum/EIPs/issues/1761) is suggested. ## Rationale @@ -545,19 +418,9 @@ Approval ### Approval -The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It -enables frictionless interaction with exchange and trade contracts. However, it may be desired to restrict approval in -some applications. Restricted approval can prevent losses in cases where users do not audit the contracts they're -approving. No standard API is supplied to manage scopes as this is implementation specific. Some implementations may -opt to offer a fixed number of scopes, or assign a specific set of scopes to certain types. Other implementations may -open up scope configuration to its users and offer methods to create scopes and assign IDs to them. +The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It enables frictionless interaction with exchange and trade contracts. -Sample use cases for scopes: - -* A company may represent it's fleet of vehicles on the blockchain and it could create a scope for each regional office. -* Game developers could share an ERC-1155 contract where each developer manages tokens under a specified scope. -* Tokens of different value magnitude could be split in separate scopes. 0.01Ξ tokens would be kept separate from -10,000.00Ξ tokens. +Restricting approval to a certain set of Token IDs, quantities or other rules may be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface](https://github.com/ethereum/EIPs/issues/1761) which is compatible with ERC-1155.
@@ -630,6 +493,7 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok - [ERC-1155 Reference Implementation](https://github.com/enjin/erc-1155) - [Horizon Games - Multi-Token Standard](https://github.com/horizon-games/multi-token-standard) - [Enjin Coin](https://enjincoin.io) ([github](https://github.com/enjin)) +- [The Sandbox - Dual ERC-1155/721 Contract](https://github.com/pixowl/thesandbox-contracts/tree/master/src/Asset) **Articles & Discussions** - [Github - Original Discussion Thread](https://github.com/ethereum/EIPs/issues/1155) From a54545159c5d167dfb39a1b6f070f3c8bc3246c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 6 Mar 2019 17:22:42 +0200 Subject: [PATCH 067/431] Define a `consensus` track and spec Clique (EIP-225). (#1570) --- EIPS/eip-225.md | 474 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 EIPS/eip-225.md diff --git a/EIPS/eip-225.md b/EIPS/eip-225.md new file mode 100644 index 00000000..cf7d64c6 --- /dev/null +++ b/EIPS/eip-225.md @@ -0,0 +1,474 @@ +--- +eip: 225 +title: Clique proof-of-authority consensus protocol +author: Péter Szilágyi +discussions-to: https://github.com/ethereum/EIPs/issues/225 +status: Draft +type: Standards Track +category: Core +created: 2017-03-06 +--- + +## Abstract + +Clique is a proof-of-authority consensus protocol. It shadows the design of Ethereum mainnet, so it can be added to any client with minimal effort. + +## Motivation + +Ethereum's first official testnet was Morden. It ran from July 2015 to about November 2016, when due to the accumulated junk and some testnet consensus issues between Geth and Parity, it was finally laid to rest in favor of a testnet reboot. + +Ropsten was thus born, clearing out all the junk and starting with a clean slate. This ran well until the end of February 2017, when malicious actors decided to abuse the low PoW and gradually inflate the block gas limits to 9 billion (from the normal 4.7 million), at which point sending in gigantic transactions crippling the entire network. Even before that, attackers attempted multiple extremely long reorgs, causing network splits between different clients, and even different versions. + +The root cause of these attacks is that a PoW network is only as secure as the computing capacity placed behind it. Restarting a new testnet from zero wouldn't solve anything, since the attacker can mount the same attack over and over again. The Parity team decided to go with an emergency solution of rolling back a significant number of blocks, and enacting a soft-fork rule that disallows gas limits above a certain threshold. + +While this solution may work in the short term: + +* It's not elegant: Ethereum supposed to have dynamic block limits +* It's not portable: other clients need to implement new fork logic themselves +* It's not compatible with sync modes: fast and light clients are both out of luck +* It's just prolonging the attacks: junk can still be steadily pushed in ad infinitum + +Parity's solution although not perfect, is nonetheless workable. I'd like to propose a longer term alternative solution, which is more involved, yet should be simple enough to allow rolling out in a reasonable amount of time. + +### Standardized proof-of-authority + +As reasoned above, proof-of-work cannot work securely in a network with no value. Ethereum has its long term goal of proof-of-stake based on Casper, but that is heavy research so we cannot rely on that any time soon to fix today's problems. One solution however is easy enough to implement, yet effective enough to fix the testnet properly, namely a proof-of-authority scheme. + +The main design goals of the PoA protocol described here is that it should be very simple to implement and embed into any existing Ethereum client, while at the same time allow using existing sync technologies (fast, light, warp) without needing client developers to add custom logic to critical software. + +## Design constraints + +There are two approaches to syncing a blockchain in general: + + * The classical approach is to take the genesis block and crunch through all the transactions one by one. This is tried and proven, but in Ethereum complexity networks quickly turns out to be very costly computationally. + * The other is to only download the chain of block headers and verify their validity, after which point an arbitrary recent state may be downloaded from the network and checked against recent headers. + +A PoA scheme is based on the idea that blocks may only be minted by trusted signers. As such, every block (or header) that a client sees can be matched against the list of trusted signers. The challenge here is how to maintain a list of authorized signers that can change in time? The obvious answer (store it in an Ethereum contract) is also the wrong answer: fast, light and warp sync don't have access to the state during syncing. + +**The protocol of maintaining the list of authorized signers must be fully contained in the block headers.** + +The next obvious idea would be to change the structure of the block headers so it drops the notions of PoW, and introduces new fields to cater for voting mechanisms. This is also the wrong answer: changing such a core data structure in multiple implementations would be a nightmare development, maintenance and security wise. + +**The protocol of maintaining the list of authorized signers must fit fully into the current data models.** + +So, according to the above, we can't use the EVM for voting, rather have to resort to headers. And we can't change header fields, rather have to resort to the currently available ones. Not much wiggle room. + +### Repurposing header fields for signing and voting + +The most obvious field that currently is used solely as *fun metadata* is the 32 byte **extra-data** section in block headers. Miners usually place their client and version in there, but some fill it with alternative "messages". The protocol would extend this field ~~to~~ with 65 bytes with the purpose of a secp256k1 miner signature. This would allow anyone obtaining a block to verify it against a list of authorized signers. It also makes the **miner** section in block headers obsolete (since the address can be derived from the signature). + +*Note, changing the length of a header field is a non invasive operation as all code (such as RLP encoding, hashing) is agnostic to that, so clients wouldn't need custom logic.* + +The above is enough to validate a chain, but how can we update a dynamic list of signers. The answer is that we can repurpose the newly obsoleted **miner** field and the PoA obsoleted **nonce** field to create a voting protocol: + + * During regular blocks, both of these fields would be set to zero. + * If a signer wishes to enact a change to the list of authorized signers, it will: + * Set the **miner** to the signer it wishes to vote about + * Set the **nonce** to `0` or `0xff...f` to vote in favor of adding or kicking out + +Any clients syncing the chain can "tally" up the votes during block processing, and maintain a dynamically changing list of authorized signers by popular vote. + +To avoid having an infinite window to tally up votes in, and also to allow periodically flushing stale proposals, we can reuse the concept of an epoch from ethash, where every epoch transition flushes all pending votes. Furthermore, these epoch transitions can also act as stateless checkpoints containing the list of current authorized signers within the header extra-data. This permits clients to sync up based only on a checkpoint hash without having to replay all the voting that was done on the chain up to that point. It also allows the genesis header to fully define the chain, containing the list of initial signers. + +### Attack vector: Malicious signer + +It may happen that a malicious user gets added to the list of signers, or that a signer key/machine is compromised. In such a scenario the protocol needs to be able to defend itself against reorganizations and spamming. The proposed solution is that given a list of N authorized signers, any signer may only mint 1 block out of every K. This ensures that damage is limited, and the remainder of the miners can vote out the malicious user. + +### Attack vector: Censoring signer + +Another interesting attack vector is if a signer (or group of signers) attempts to censor out blocks that vote on removing them from the authorization list. To work around this, we restrict the allowed minting frequency of signers to 1 out of N/2. This ensures that malicious signers need to control at least 51% of signing accounts, at which case it's game over anyway. + +### Attack vector: Spamming signer + +A final small attack vector is that of malicious signers injecting new vote proposals inside every block they mint. Since nodes need to tally up all votes to create the actual list of authorized signers, they need to track all votes through time. Without placing a limit on the vote window, this could grow slowly, yet unbounded. The solution is to place a ~~moving~~ window of W blocks after which votes are considered stale. ~~A sane window might be 1-2 epochs.~~ We'll call this an epoch. + +### Attack vector: Concurrent blocks + +If the number of authorized signers are N, and we allow each signer to mint 1 block out of K, then at any point in time N-K+1 miners are allowed to mint. To avoid these racing for blocks, every signer would add a small random "offset" to the time it releases a new block. This ensures that small forks are rare, but occasionally still happen (as on the main net). If a signer is caught abusing it's authority and causing chaos, it can be voted out. + +## Specification + +We define the following constants: + + * **`EPOCH_LENGTH`**: Number of blocks after which to checkpoint and reset the pending votes. + * Suggested `30000` for the testnet to remain analogous to the mainnet `ethash` epoch. + * **`BLOCK_PERIOD`**: Minimum difference between two consecutive block's timestamps. + * Suggested `15s` for the testnet to remain analogous to the mainnet `ethash` target. + * **`EXTRA_VANITY`**: Fixed number of extra-data prefix bytes reserved for signer *vanity*. + * Suggested `32 bytes` to retain the current extra-data allowance and/or use. + * **`EXTRA_SEAL`**: Fixed number of extra-data suffix bytes reserved for signer seal. + * `65 bytes` fixed as signatures are based on the standard `secp256k1` curve. + * **`NONCE_AUTH`**: Magic nonce number `0xffffffffffffffff` to vote on adding a new signer. + * **`NONCE_DROP`**: Magic nonce number `0x0000000000000000` to vote on removing a signer. + * **`UNCLE_HASH`**: Always `Keccak256(RLP([]))` as uncles are meaningless outside of PoW. + * **`DIFF_NOTURN`**: Block score (difficulty) for blocks containing out-of-turn signatures. + * Suggested `1` since it just needs to be an arbitrary baseline constant. + * **`DIFF_INTURN`**: Block score (difficulty) for blocks containing in-turn signatures. + * Suggested `2` to show a slight preference over out-of-turn signatures. + +We also define the following per-block constants: + + * **`BLOCK_NUMBER`**: Block height in the chain, where the height of the genesis is block `0`. + * **`SIGNER_COUNT`**: Number of authorized signers valid at a particular instance in the chain. + * **`SIGNER_INDEX`**: Index of the block signer in the sorted list of current authorized signers. + * **`SIGNER_LIMIT`**: Number of consecutive blocks out of which a signer may only sign one. + * Must be `floor(SIGNER_COUNT / 2) + 1` to enforce majority consensus on a chain. + +We repurpose the `ethash` header fields as follows: + + * **`beneficiary`**: Address to propose modifying the list of authorized signers with. + * Should be filled with zeroes normally, modified only while voting. + * Arbitrary values are permitted nonetheless (even meaningless ones such as voting out non signers) to avoid extra complexity in implementations around voting mechanics. + * **Must** be filled with zeroes on checkpoint (i.e. epoch transition) blocks. + * **`nonce`**: Signer proposal regarding the account defined by the `beneficiary` field. + * Should be **`NONCE_DROP`** to propose deauthorizing `beneficiary` as a existing signer. + * Should be **`NONCE_AUTH`** to propose authorizing `beneficiary` as a new signer. + * **Must** be filled with zeroes on checkpoint (i.e. epoch transition) blocks. + * **Must** not take up any other value apart from the two above (for now). + * **`extraData`**: Combined field for signer vanity, checkpointing and signer signatures. + * First **`EXTRA_VANITY`** bytes (fixed) may contain arbitrary signer vanity data. + * Last **`EXTRA_SEAL`** bytes (fixed) is the signer's signature sealing the header. + * Checkpoint blocks **must** contain a list of signers (`N*20 bytes`) in between, **omitted** otherwise. + * The list of signers in checkpoint block extra-data sections **must** be sorted in ascending order. + * **`mixHash`**: Reserved for fork protection logic, similar to the extra-data during the DAO. + * **Must** be filled with zeroes during normal operation. + * **`ommersHash`**: **Must** be **`UNCLE_HASH`** as uncles are meaningless outside of PoW. + * **`timestamp`**: **Must** be at least the parent timestamp + **`BLOCK_PERIOD`**. + * **`difficulty`**: Contains the standalone score of the block to derive the quality of a chain. + * **Must** be **`DIFF_NOTURN`** if `BLOCK_NUMBER % SIGNER_COUNT != SIGNER_INDEX` + * **Must** be **`DIFF_INTURN`** if `BLOCK_NUMBER % SIGNER_COUNT == SIGNER_INDEX` + +### Authorizing a block + +To authorize a block for the network, the signer needs to sign the block's hash containing **everything except the signature itself**. The means that the hash contains every field of the header (`nonce` and `mixDigest` included), and also the `extraData` with the exception of the 65 byte signature suffix. The fields are hashed in the order of their definition in the yellow paper. + +This hash is signed using the standard `secp256k1` curve, and the resulting 65 byte signature (`R`, `S`, `V`, where `V` is `0` or `1`) is embedded into the `extraData` as the trailing 65 byte suffix. + +To ensure malicious signers (loss of signing key) cannot wreck havoc in the network, each singer is allowed to sign **maximum one** out of **`SIGNER_LIMIT`** consecutive blocks. The order is not fixed, but in-turn signing weighs more (**`DIFF_INTURN`**) than out of turn one (**`DIFF_NOTURN`**). + +#### Authorization strategies + +As long as signers conform to the above specs, they can authorize and distribute blocks as they see fit. The following suggested strategy will however reduce network traffic and small forks, so it's a suggested feature: + + * If a signer is allowed to sign a block (is on the authorized list and didn't sign recently). + * Calculate the optimal signing time of the next block (parent + **`BLOCK_PERIOD`**). + * If the signer is in-turn, wait for the exact time to arrive, sign and broadcast immediately. + * If the signer is out-of-turn, delay signing by `rand(SIGNER_COUNT * 500ms)`. + +This small strategy will ensure that the in-turn signer (who's block weighs more) has a slight advantage to sign and propagate versus the out-of-turn signers. Also the scheme allows a bit of scale with the increase of the number of signers. + +### Voting on signers + +Every epoch transition (genesis block included) acts as a stateless checkpoint, from which capable clients should be able to sync without requiring any previous state. This means epoch headers **must not** contain votes, all non settled votes are discarded, and tallying starts from scratch. + +For all non-epoch transition blocks: + + * Signers may cast one vote per own block to propose a change to the authorization list. + * Only the latest proposal per target beneficiary is kept from a single signer. + * Votes are tallied live as the chain progresses (concurrent proposals allowed). + * Proposals reaching majority consensus **`SIGNER_LIMIT`** come into effect immediately. + * Invalid proposals are **not** to be penalized for client implementation simplicity. + +**A proposal coming into effect entails discarding all pending votes for that proposal (both for and against) and starting with a clean slate.** + +#### Cascading votes + +A complex corner case may arise during signer deauthorization. When a previously authorized signer is dropped, the number of signers required to approve a proposal might decrease by one. This might cause one or more pending proposals to reach majority consensus, the execution of which might further cascade into new proposals passing. + +Handling this scenario is non obvious when multiple conflicting proposals pass simultaneously (e.g. add a new signer vs. drop an existing one), where the evaluation order might drastically change the outcome of the final authorization list. Since signers may invert their own votes in every block they mint, it's not so obvious which proposal would be "first". + +To avoid the pitfalls cascading executions would entail, the Clique proposal explicitly forbids cascading effects. In other words: **Only the `beneficiary` of the current header/vote may be added to/dropped from the authorization list. If that causes other proposals to reach consensus, those will be executed when their respective beneficiaries are "touched" again (given that majority consensus still holds at that point).** + +#### Voting strategies + +Since the blockchain can have small reorgs, a naive voting mechanism of "cast-and-forget" may not be optimal, since a block containing a singleton vote may not end up on the final chain. + +A simplistic but working strategy is to allow users to configure "proposals" on the signers (e.g. "add 0x...", "drop 0x..."). The signing code can then pick a random proposal for every block it signs and inject it. This ensures that multiple concurrent proposals as well as reorgs get eventually noted on the chain. + +This list may be expired after a certain number of blocks / epochs, but it's important to realize that "seeing" a proposal pass doesn't mean it won't get reorged, so it should not be immediately dropped when the proposal passes. + +## Test Cases + +```go +// block represents a single block signed by a parcitular account, where +// the account may or may not have cast a Clique vote. +type block struct { + signer string // Account that signed this particular block + voted string // Optional value if the signer voted on adding/removing someone + auth bool // Whether the vote was to authorize (or deauthorize) + checkpoint []string // List of authorized signers if this is an epoch block +} + +// Define the various voting scenarios to test +tests := []struct { + epoch uint64 // Number of blocks in an epoch (unset = 30000) + signers []string // Initial list of authorized signers in the genesis + blocks []block // Chain of signed blocks, potentially influencing auths + results []string // Final list of authorized signers after all blocks + failure error // Failure if some block is invalid according to the rules +}{ + { + // Single signer, no votes cast + signers: []string{"A"}, + blocks: []block{{signer: "A"}}, + results: []string{"A"}, + }, { + // Single signer, voting to add two others (only accept first, second needs 2 votes) + signers: []string{"A"}, + blocks: []block{ + {signer: "A", voted: "B", auth: true}, + {signer: "B"}, + {signer: "A", voted: "C", auth: true}, + }, + results: []string{"A", "B"}, + }, { + // Two signers, voting to add three others (only accept first two, third needs 3 votes already) + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "C", auth: true}, + {signer: "B", voted: "C", auth: true}, + {signer: "A", voted: "D", auth: true}, + {signer: "B", voted: "D", auth: true}, + {signer: "C"}, + {signer: "A", voted: "E", auth: true}, + {signer: "B", voted: "E", auth: true}, + }, + results: []string{"A", "B", "C", "D"}, + }, { + // Single signer, dropping itself (weird, but one less cornercase by explicitly allowing this) + signers: []string{"A"}, + blocks: []block{ + {signer: "A", voted: "A", auth: false}, + }, + results: []string{}, + }, { + // Two signers, actually needing mutual consent to drop either of them (not fulfilled) + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "B", auth: false}, + }, + results: []string{"A", "B"}, + }, { + // Two signers, actually needing mutual consent to drop either of them (fulfilled) + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "B", auth: false}, + {signer: "B", voted: "B", auth: false}, + }, + results: []string{"A"}, + }, { + // Three signers, two of them deciding to drop the third + signers: []string{"A", "B", "C"}, + blocks: []block{ + {signer: "A", voted: "C", auth: false}, + {signer: "B", voted: "C", auth: false}, + }, + results: []string{"A", "B"}, + }, { + // Four signers, consensus of two not being enough to drop anyone + signers: []string{"A", "B", "C", "D"}, + blocks: []block{ + {signer: "A", voted: "C", auth: false}, + {signer: "B", voted: "C", auth: false}, + }, + results: []string{"A", "B", "C", "D"}, + }, { + // Four signers, consensus of three already being enough to drop someone + signers: []string{"A", "B", "C", "D"}, + blocks: []block{ + {signer: "A", voted: "D", auth: false}, + {signer: "B", voted: "D", auth: false}, + {signer: "C", voted: "D", auth: false}, + }, + results: []string{"A", "B", "C"}, + }, { + // Authorizations are counted once per signer per target + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "C", auth: true}, + {signer: "B"}, + {signer: "A", voted: "C", auth: true}, + {signer: "B"}, + {signer: "A", voted: "C", auth: true}, + }, + results: []string{"A", "B"}, + }, { + // Authorizing multiple accounts concurrently is permitted + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "C", auth: true}, + {signer: "B"}, + {signer: "A", voted: "D", auth: true}, + {signer: "B"}, + {signer: "A"}, + {signer: "B", voted: "D", auth: true}, + {signer: "A"}, + {signer: "B", voted: "C", auth: true}, + }, + results: []string{"A", "B", "C", "D"}, + }, { + // Deauthorizations are counted once per signer per target + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "B", auth: false}, + {signer: "B"}, + {signer: "A", voted: "B", auth: false}, + {signer: "B"}, + {signer: "A", voted: "B", auth: false}, + }, + results: []string{"A", "B"}, + }, { + // Deauthorizing multiple accounts concurrently is permitted + signers: []string{"A", "B", "C", "D"}, + blocks: []block{ + {signer: "A", voted: "C", auth: false}, + {signer: "B"}, + {signer: "C"}, + {signer: "A", voted: "D", auth: false}, + {signer: "B"}, + {signer: "C"}, + {signer: "A"}, + {signer: "B", voted: "D", auth: false}, + {signer: "C", voted: "D", auth: false}, + {signer: "A"}, + {signer: "B", voted: "C", auth: false}, + }, + results: []string{"A", "B"}, + }, { + // Votes from deauthorized signers are discarded immediately (deauth votes) + signers: []string{"A", "B", "C"}, + blocks: []block{ + {signer: "C", voted: "B", auth: false}, + {signer: "A", voted: "C", auth: false}, + {signer: "B", voted: "C", auth: false}, + {signer: "A", voted: "B", auth: false}, + }, + results: []string{"A", "B"}, + }, { + // Votes from deauthorized signers are discarded immediately (auth votes) + signers: []string{"A", "B", "C"}, + blocks: []block{ + {signer: "C", voted: "D", auth: true}, + {signer: "A", voted: "C", auth: false}, + {signer: "B", voted: "C", auth: false}, + {signer: "A", voted: "D", auth: true}, + }, + results: []string{"A", "B"}, + }, { + // Cascading changes are not allowed, only the account being voted on may change + signers: []string{"A", "B", "C", "D"}, + blocks: []block{ + {signer: "A", voted: "C", auth: false}, + {signer: "B"}, + {signer: "C"}, + {signer: "A", voted: "D", auth: false}, + {signer: "B", voted: "C", auth: false}, + {signer: "C"}, + {signer: "A"}, + {signer: "B", voted: "D", auth: false}, + {signer: "C", voted: "D", auth: false}, + }, + results: []string{"A", "B", "C"}, + }, { + // Changes reaching consensus out of bounds (via a deauth) execute on touch + signers: []string{"A", "B", "C", "D"}, + blocks: []block{ + {signer: "A", voted: "C", auth: false}, + {signer: "B"}, + {signer: "C"}, + {signer: "A", voted: "D", auth: false}, + {signer: "B", voted: "C", auth: false}, + {signer: "C"}, + {signer: "A"}, + {signer: "B", voted: "D", auth: false}, + {signer: "C", voted: "D", auth: false}, + {signer: "A"}, + {signer: "C", voted: "C", auth: true}, + }, + results: []string{"A", "B"}, + }, { + // Changes reaching consensus out of bounds (via a deauth) may go out of consensus on first touch + signers: []string{"A", "B", "C", "D"}, + blocks: []block{ + {signer: "A", voted: "C", auth: false}, + {signer: "B"}, + {signer: "C"}, + {signer: "A", voted: "D", auth: false}, + {signer: "B", voted: "C", auth: false}, + {signer: "C"}, + {signer: "A"}, + {signer: "B", voted: "D", auth: false}, + {signer: "C", voted: "D", auth: false}, + {signer: "A"}, + {signer: "B", voted: "C", auth: true}, + }, + results: []string{"A", "B", "C"}, + }, { + // Ensure that pending votes don't survive authorization status changes. This + // corner case can only appear if a signer is quickly added, removed and then + // readded (or the inverse), while one of the original voters dropped. If a + // past vote is left cached in the system somewhere, this will interfere with + // the final signer outcome. + signers: []string{"A", "B", "C", "D", "E"}, + blocks: []block{ + {signer: "A", voted: "F", auth: true}, // Authorize F, 3 votes needed + {signer: "B", voted: "F", auth: true}, + {signer: "C", voted: "F", auth: true}, + {signer: "D", voted: "F", auth: false}, // Deauthorize F, 4 votes needed (leave A's previous vote "unchanged") + {signer: "E", voted: "F", auth: false}, + {signer: "B", voted: "F", auth: false}, + {signer: "C", voted: "F", auth: false}, + {signer: "D", voted: "F", auth: true}, // Almost authorize F, 2/3 votes needed + {signer: "E", voted: "F", auth: true}, + {signer: "B", voted: "A", auth: false}, // Deauthorize A, 3 votes needed + {signer: "C", voted: "A", auth: false}, + {signer: "D", voted: "A", auth: false}, + {signer: "B", voted: "F", auth: true}, // Finish authorizing F, 3/3 votes needed + }, + results: []string{"B", "C", "D", "E", "F"}, + }, { + // Epoch transitions reset all votes to allow chain checkpointing + epoch: 3, + signers: []string{"A", "B"}, + blocks: []block{ + {signer: "A", voted: "C", auth: true}, + {signer: "B"}, + {signer: "A", checkpoint: []string{"A", "B"}}, + {signer: "B", voted: "C", auth: true}, + }, + results: []string{"A", "B"}, + }, { + // An unauthorized signer should not be able to sign blocks + signers: []string{"A"}, + blocks: []block{ + {signer: "B"}, + }, + failure: errUnauthorizedSigner, + }, { + // An authorized signer that signed recenty should not be able to sign again + signers: []string{"A", "B"}, + blocks []block{ + {signer: "A"}, + {signer: "A"}, + }, + failure: errRecentlySigned, + }, { + // Recent signatures should not reset on checkpoint blocks imported in a batch + epoch: 3, + signers: []string{"A", "B", "C"}, + blocks: []block{ + {signer: "A"}, + {signer: "B"}, + {signer: "A", checkpoint: []string{"A", "B", "C"}}, + {signer: "A"}, + }, + failure: errRecentlySigned, + },, +} +``` + +## Implementation + +A reference implementation is part of [go-ethereum](https://github.com/ethereum/go-ethereum/tree/master/consensus/clique) and has been functioning as the consensus engine behind the [Rinkeby](https://www.rinkeby.io) testnet since April, 2017. +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From e2a489a73ff0b427896176221e4099d0d6f29cd0 Mon Sep 17 00:00:00 2001 From: Paul Bouchon Date: Thu, 7 Mar 2019 08:48:49 -0500 Subject: [PATCH 068/431] EIP: Remote procedure call specification (#1474) --- EIPS/eip-1474.md | 2314 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2314 insertions(+) create mode 100644 EIPS/eip-1474.md diff --git a/EIPS/eip-1474.md b/EIPS/eip-1474.md new file mode 100644 index 00000000..8eefc1bf --- /dev/null +++ b/EIPS/eip-1474.md @@ -0,0 +1,2314 @@ +--- +eip: 1474 +title: Remote procedure call specification +author: Paul Bouchon +discussions-to: https://ethereum-magicians.org/t/eip-remote-procedure-call-specification/1537 +status: Draft +type: Standards Track +category: Interface +created: 2018-10-02 +--- + +## Simple Summary + +This proposal defines a standard set of remote procedure call methods that an Ethereum node should implement. + +## Abstract + +Nodes created by the current generation of Ethereum clients expose inconsistent and incompatible remote procedure call (RPC) methods because no formal Ethereum RPC specification exists. This proposal standardizes such a specification to provide developers with a predictable Ethereum RPC interface regardless of underlying node implementation. + +## Specification + +### Concepts + +#### RFC-2119 + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt). + +#### JSON-RPC + +Communication with Ethereum nodes is accomplished using [JSON-RPC](https://www.jsonrpc.org/specification), a stateless, lightweight [remote procedure call](https://en.wikipedia.org/wiki/Remote_procedure_call) protocol that uses [JSON](http://www.json.org/) as its data format. Ethereum RPC methods **MUST** be called using [JSON-RPC request objects](https://www.jsonrpc.org/specification#request_object) and **MUST** respond with [JSON-RPC response objects](https://www.jsonrpc.org/specification#response_object). + +#### Error codes + +If an Ethereum RPC method encounters an error, the `error` member included on the response object **MUST** be an object containing a `code` member and descriptive `message` member. The following list contains all possible error codes and associated messages: + +|Code|Message|Meaning|Category| +|-|-|-|-| +|-32700|Parse error|Invalid JSON|standard| +|-32600|Invalid request|JSON is not a valid request object|standard| +|-32601|Method not found|Method does not exist|standard| +|-32602|Invalid params|Invalid method parameters|standard| +|-32603|Internal error|Internal JSON-RPC error|standard| +|-32000|Invalid input|Missing or invalid parameters|non-standard| +|-32001|Resource not found|Requested resource not found|non-standard| +|-32002|Resource unavailable|Requested resource not available|non-standard| +|-32003|Transaction rejected|Transaction creation failed|non-standard| +|-32004|Method not supported|Method is not implemented|non-standard| + +Example error response: + +```sh +{ + "id": 1337 + "jsonrpc": "2.0", + "error": { + "code": -32003, + "message": "Transaction rejected" + } +} +``` + +#### Value encoding + +Specific types of values passed to and returned from Ethereum RPC methods require special encoding: + +##### `Quantity` + +- A `Quantity` value **MUST** be hex-encoded. +- A `Quantity` value **MUST** be "0x"-prefixed. +- A `Quantity` value **MUST** be expressed using the fewest possible hex digits per byte. +- A `Quantity` value **MUST** express zero as "0x0". + +Examples `Quantity` values: + +|Value|Valid|Reason| +|-|-|-| +|0x|`invalid`|empty not a valid quantity| +|0x0|`valid`|interpreted as a quantity of zero| +|0x00|`invalid`|leading zeroes not allowed| +|0x41|`valid`|interpreted as a quantity of 65| +|0x400|`valid`|interpreted as a quantity of 1024| +|0x0400|`invalid`|leading zeroes not allowed| +|ff|`invalid`|values must be prefixed| + + +##### `Data` + +- A `Data` value **MUST** be hex-encoded. +- A `Data` value **MUST** be "0x"-prefixed. +- A `Data` value **MUST** be expressed using two hex digits per byte. + +Examples `Data` values: + +|Value|Valid|Reason| +|-|-|-| +|0x|`valid`|interpreted as empty data| +|0x0|`invalid`|each byte must be represented using two hex digits| +|0x00|`valid`|interpreted as a single zero byte| +|0x41|`true`|interpreted as a data value of 65| +|0x004200|`true`|interpreted as a data value of 16896| +|0xf0f0f|`false`|bytes require two hex digits| +|004200|`false`|values must be prefixed| + +##### Proposing changes + +New Ethereum RPC methods and changes to existing methods **MUST** be proposed via the traditional EIP process. This allows for community consensus around new method implementations and proposed method modifications. RPC method proposals **MUST** reach "draft" status before being added to this proposal and the official Ethereum RPC specification defined herein. + +### Methods + +
+web3_clientVersion + +#### Description + +Returns the version of the current client + +#### Parameters + +_(none)_ + +#### Returns + +{`string`} - client version + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "web3_clientVersion", + "params": [], +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "Mist/v0.9.3/darwin/go1.4.1" +} +``` +--- +
+ +
+web3_sha3 + +#### Description + +Hashes data using the Keccak-256 algorithm + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|data to hash| + +#### Returns + +{[`Data`](#data)} - Keccak-256 hash of the given data + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "web3_sha3", + "params": ["0x68656c6c6f20776f726c64"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc94770007dda54cF92009BFF0dE90c06F603a09f" +} +``` +--- +
+ +
+net_listening + +#### Description + +Determines if this client is listening for new network connections + +#### Parameters + +_(none)_ + +#### Returns + +{`boolean`} - `true` if listening is active or `false` if listening is not active + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "net_listening", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +
+net_peerCount + +#### Description + +Returns the number of peers currently connected to this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - number of connected peers + +#### Example +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "net_peerCount", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x2" +} +``` +--- +
+ +
+net_version + +#### Description + +Returns the chain ID associated with the current network + +#### Parameters + +_(none)_ + +#### Returns + +{`string`} - chain ID associated with the current network + +Common chain IDs: + +- `"1"` - Ethereum mainnet +- `"3"` - Ropsten testnet +- `"4"` - Rinkeby testnet +- `"42"` - Kovan testnet + +**Note:** See EIP-155 for a [complete list](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids) of possible chain IDs. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "net_version", + "params": [], +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "3" +} +``` +--- +
+ +
+eth_accounts + +#### Description + +Returns a list of addresses owned by this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Data[]`](#data)} - array of addresses + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_accounts", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] +} +``` +--- +
+ +
+eth_blockNumber + +#### Description + +Returns the number of the most recent block seen by this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - number of the latest block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_blockNumber", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc94" +} +``` +--- +
+ +
+eth_call + +#### Description + +Executes a new message call immediately without submitting a transaction to the network + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `[from]` - transaction sender
@property {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract
@property {[`Quantity`](#quantity)} `[gas]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Data`](#data)} - return value of executed contract + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_call", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x" +} +``` +--- +
+ +
+eth_coinbase + +#### Description + +Returns the coinbase address for this client + +#### Parameters + +_(none)_ + +#### Returns + +{[`Data`](#data)} - coinbase address + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_coinbase", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc94770007dda54cF92009BFF0dE90c06F603a09f" +} +``` +--- +
+ +
+eth_estimateGas + +#### Description + +Estimates the gas necessary to complete a transaction without submitting it to the network + +**Note:** The resulting gas estimation may be significantly more than the amount of gas actually used by the transaction. This is due to a variety of reasons including EVM mechanics and node performance. + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `[from]` - transaction sender
@property {[`Data`](#data)} `[to]` - transaction recipient
@property {[`Quantity`](#quantity)} `[gas]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - amount of gas required by transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_estimateGas", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x5208" +} +``` +--- +
+ +
+eth_gasPrice + +#### Description + +Returns the current price of gas expressed in wei + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - current gas price in wei + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_gasPrice", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x09184e72a000" +} +``` +--- +
+ +
+eth_getBalance + +#### Description + +Returns the balance of an address in wei + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to query for balance| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - balance of the provided account in wei + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x0234c8a3397aab58" +} +``` +--- +
+ +
+eth_getBlockByHash + +#### Description + +Returns information about a block specified by hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| +|2|{`boolean`}|`true` will pull full transaction objects, `false` will pull transaction hashes| + +#### Returns + +{`null|object`} - `null` if no block is found, otherwise a block object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `transactions` - list of transaction objects or hashes +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockByHash", + "params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "difficulty": "0x027f07", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x9f759", + "gasUsed": "0x9f759", + "hash": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "logsBloom": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a", + "nonce": "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2", + "number": "0x1b4", + "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x027f07", + "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff", + "timestamp": "0x54e34e8e" + "totalDifficulty": "0x027f07", + "transactions": [] + "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles": ["0x1606e5...", "0xd5145a9..."] + } +} +``` +--- +
+ +
+eth_getBlockByNumber + +#### Description + +Returns information about a block specified by number + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| +|2|{`boolean`}|`true` will pull full transaction objects, `false` will pull transaction hashes| + +#### Returns + +{`null|object`} - `null` if no block is found, otherwise a block object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `transactions` - list of transaction objects or hashes +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "difficulty": "0x027f07", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x9f759", + "gasUsed": "0x9f759", + "hash": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "logsBloom": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", + "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a", + "nonce": "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2", + "number": "0x1b4", + "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x027f07", + "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff", + "timestamp": "0x54e34e8e" + "totalDifficulty": "0x027f07", + "transactions": [] + "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncles": ["0x1606e5...", "0xd5145a9..."] + } +} +``` +--- +
+ +
+eth_getBlockTransactionCountByHash + +#### Description + +Returns the number of transactions in a block specified by block hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| + +#### Returns + +{[`Quantity`](#quantity)} - number of transactions in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByHash", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc" +} +``` +--- +
+ +
+eth_getBlockTransactionCountByNumber + +#### Description + +Returns the number of transactions in a block specified by block number + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - number of transactions in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": ["0xe8"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xa" +} +``` +--- +
+ +
+eth_getCode + +#### Description + +Returns the contract code stored at a given address + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to query for code| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Data`](#data)} - code from the specified address + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": ["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x2"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056" +} +``` +--- +
+ +
+eth_getFilterChanges + +#### Description + +Returns a list of all logs based on filter ID since the last log retrieval + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)}|ID of the filter| + +#### Returns + +{`Array`} - array of log objects with the following members: + +- {[`Data`](#data)} `address` - address from which this log originated +- {[`Data`](#data)} `blockHash` - hash of block containing this log or `null` if pending +- {[`Data`](#data)} `data` - contains the non-indexed arguments of the log +- {[`Data`](#data)} `transactionHash` - hash of the transaction that created this log or `null` if pending +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this log or `null` if pending +- {[`Quantity`](#quantity)} `logIndex` - index of this log within its block or `null` if pending +- {[`Quantity`](#quantity)} `transactionIndex` - index of the transaction that created this log or `null` if pending +- {[`Data[]`](#data)} `topics` - list of order-dependent topics +- {`boolean`} `removed` - `true` if this filter has been destroyed and is invalid + +**Note:** The return value of `eth_getFilterChanges` when retrieving logs from `eth_newBlockFilter` and `eth_newPendingTransactionFilter` filters will be an array of hashes, not an array of Log objects. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getFilterChanges", + "params": ["0x16"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [{ + "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockNumber":"0x1b4", + "data":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x1", + "topics": [], + "transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf", + "transactionIndex": "0x0" + }] +} +``` +--- +
+ +
+eth_getFilterLogs + +#### Description + +Returns a list of all logs based on filter ID + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)}|ID of the filter| + +#### Returns + +{`Array`} - array of log objects with the following members: + +- {[`Data`](#data)} address - address from which this log originated +- {[`Data`](#data)} blockHash - hash of block containing this log or `null` if pending +- {[`Data`](#data)} data - contains the non-indexed arguments of the log +- {[`Data`](#data)} transactionHash - hash of the transaction that created this log or `null` if pending +- {[`Quantity`](#quantity)} blockNumber - number of block containing this log or `null` if pending +- {[`Quantity`](#quantity)} logIndex - index of this log within its block or `null` if pending +- {[`Quantity`](#quantity)} transactionIndex - index of the transaction that created this log or `null` if pending +- {`Array`} topics - list of order-dependent topics +- {`boolean`} removed - `true` if this filter has been destroyed and is invalid + +**Note:** The return value of `eth_getFilterLogs` when retrieving logs from `eth_newBlockFilter` and `eth_newPendingTransactionFilter` filters will be an array of hashes, not an array of Log objects. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getFilterLogs", + "params": ["0x16"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [{ + "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockNumber":"0x1b4", + "data":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x1", + "topics": [], + "transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf", + "transactionIndex": "0x0" + }] +} +``` +--- +
+ +
+eth_getLogs + +#### Description + +Returns a list of all logs based on a filter object + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Quantity`](#quantity)\|`string`} `[fromBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Quantity`](#quantity)\|`string`} `[toBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Data`](#data)\|[`Data[]`](#data)} `[address]` - contract address or a list of addresses from which logs should originate
@property {[`Data[]`](#data)} `[topics]` - list of order-dependent topics
@property {[`Data`](#data)} `[blockhash]` - restrict logs to a block by hash| + +**Note:** If `blockhash` is passed, neither `fromBlock` nor `toBlock` are allowed or respected. + +#### Returns + +{`Array`} - array of log objects with the following members: + +- {[`Data`](#data)} `address` - address from which this log originated +- {[`Data`](#data)} `blockHash` - hash of block containing this log or `null` if pending +- {[`Data`](#data)} `data` - contains the non-indexed arguments of the log +- {[`Data`](#data)} `transactionHash` - hash of the transaction that created this log or `null` if pending +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this log or `null` if pending +- {[`Quantity`](#quantity)} `logIndex` - index of this log within its block or `null` if pending +- {[`Quantity`](#quantity)} `transactionIndex` - index of the transaction that created this log or `null` if pending +- {[`Data`](#data)} `topics` - list of order-dependent topics +- {`boolean`} `removed` - `true` if this filter has been destroyed and is invalid + +**Note:** The return value of `eth_getLogs` when retrieving logs from `eth_newBlockFilter` and `eth_newPendingTransactionFilter` filters will be an array of hashes, not an array of Log objects. + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": [{ + "topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"] + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [{ + "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d", + "blockNumber":"0x1b4", + "data":"0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": "0x1", + "topics": [], + "transactionHash": "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf", + "transactionIndex": "0x0" + }] +} +``` +--- +
+ +
+eth_getStorageAt + +#### Description + +Returns the value from a storage position at an address + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address of stored data| +|2|{[`Quantity`](#quantity)}|index into stored data| +|3|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Data`](#data)} - value stored at the given address and data index + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getStorageAt", + "params": ["0x295a70b2de5e3953354a6a8344e616ed314d7251", "0x0", "latest"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x00000000000000000000000000000000000000000000000000000000000004d2" +} +``` +--- +
+ +
+eth_getTransactionByBlockHashAndIndex + +#### Description + +Returns information about a transaction specified by block hash and transaction index + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| +|2|{[`Quantity`](#quantity)}|index of a transaction in the specified block| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction object with the following members: + +- {[`Data`](#data)} `r` - ECDSA signature r +- {[`Data`](#data)} `s` - ECDSA signature s +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction or `null` if pending +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `hash` - hash of this transaction +- {[`Data`](#data)} `input` - contract code or a hashed method call +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Quantity`](#quantity)} `v` - ECDSA recovery ID +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction or `null` if pending +- {[`Quantity`](#quantity)} `gas` - gas provided for transaction execution +- {[`Quantity`](#quantity)} `gasPrice` - price in wei of each gas used +- {[`Quantity`](#quantity)} `nonce` - unique number identifying this transaction +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block or `null` if pending +- {[`Quantity`](#quantity)} `value` - value in wei sent with this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionByBlockHashAndIndex", + "params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "blockNumber": "0x5daf3b", + "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", + "gas": "0xc350", + "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", + "input": "0x68656c6c6f21", + "nonce": "0x15", + "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", + "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", + "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", + "transactionIndex": "0x41", + "v": "0x25", + "value": "0xf3dbb76162000" + } +} +``` +--- +
+ +
+eth_getTransactionByBlockNumberAndIndex + +#### Description + +Returns information about a transaction specified by block number and transaction index + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| +|2|{[`Quantity`](#quantity)}|index of a transaction in the specified block| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction object with the following members: + +- {[`Data`](#data)} `r` - ECDSA signature r +- {[`Data`](#data)} `s` - ECDSA signature s +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction or `null` if pending +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `hash` - hash of this transaction +- {[`Data`](#data)} `input` - contract code or a hashed method call +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Quantity`](#quantity)} `v` - ECDSA recovery ID +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction or `null` if pending +- {[`Quantity`](#quantity)} `gas` - gas provided for transaction execution +- {[`Quantity`](#quantity)} `gasPrice` - price in wei of each gas used +- {[`Quantity`](#quantity)} `nonce` - unique number identifying this transaction +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block or `null` if pending +- {[`Quantity`](#quantity)} `value` - value in wei sent with this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionByBlockNumberAndIndex", + "params":["0x29c", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "blockNumber": "0x5daf3b", + "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", + "gas": "0xc350", + "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", + "input": "0x68656c6c6f21", + "nonce": "0x15", + "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", + "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", + "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", + "transactionIndex": "0x41", + "v": "0x25", + "value": "0xf3dbb76162000" + } +} +``` +--- +
+ +
+eth_getTransactionByHash + +#### Description + +Returns information about a transaction specified by hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a transaction| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction object with the following members: + +- {[`Data`](#data)} `r` - ECDSA signature r +- {[`Data`](#data)} `s` - ECDSA signature s +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction or `null` if pending +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `hash` - hash of this transaction +- {[`Data`](#data)} `input` - contract code or a hashed method call +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Quantity`](#quantity)} `v` - ECDSA recovery ID +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction or `null` if pending +- {[`Quantity`](#quantity)} `gas` - gas provided for transaction execution +- {[`Quantity`](#quantity)} `gasPrice` - price in wei of each gas used +- {[`Quantity`](#quantity)} `nonce` - unique number identifying this transaction +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block or `null` if pending +- {[`Quantity`](#quantity)} `value` - value in wei sent with this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionByHash", + "params": ["0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": "0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2", + "blockNumber": "0x5daf3b", + "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d", + "gas": "0xc350", + "gasPrice": "0x4a817c800", + "hash": "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b", + "input": "0x68656c6c6f21", + "nonce": "0x15", + "r": "0x1b5e176d927f8e9ab405058b2d2457392da3e20f328b16ddabcebc33eaac5fea", + "s": "0x4ba69724e8f69de52f0125ad8b3c5c2cef33019bac3249e2c0a2192766d1721c", + "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb", + "transactionIndex": "0x41", + "v": "0x25", + "value": "0xf3dbb76162000" + } +} +``` +--- +
+ +
+eth_getTransactionCount + +#### Description + +Returns the number of transactions sent from an address + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to query for sent transactions| +|2|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - number of transactions sent from the specified address + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_getTransactionReceipt + +#### Description + +Returns the receipt of a transaction specified by hash + +**Note:** Transaction receipts are unavailable for pending transactions. + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a transaction| + +#### Returns + +{`null|object`} - `null` if no transaction is found, otherwise a transaction receipt object with the following members: + +- {[`Data`](#data)} `blockHash` - hash of block containing this transaction +- {[`Data`](#data)} `contractAddress` - address of new contract or `null` if no contract was created +- {[`Data`](#data)} `from` - transaction sender +- {[`Data`](#data)} `logsBloom` - logs bloom filter +- {[`Data`](#data)} `to` - transaction recipient or `null` if deploying a contract +- {[`Data`](#data)} `transactionHash` - hash of this transaction +- {[`Quantity`](#quantity)} `blockNumber` - number of block containing this transaction +- {[`Quantity`](#quantity)} `cumulativeGasUsed` - gas used by this and all preceding transactions in this block +- {[`Quantity`](#quantity)} `gasUsed` - gas used by this transaction +- {[`Quantity`](#quantity)} `status` - `1` if this transaction was successful or `0` if it failed +- {[`Quantity`](#quantity)} `transactionIndex` - index of this transaction in the block +- {`Array`} `logs` - list of log objects generated by this transaction + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', + "blockNumber": '0xb', + "contractAddress": '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + "cumulativeGasUsed": '0x33bc', + "gasUsed": '0x4dc', + "logs": [], + "logsBloom": "0x00...0", + "status": "0x1", + "transactionHash": '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238', + "transactionIndex": '0x1' + } +} +``` +--- +
+ +
+eth_getUncleByBlockHashAndIndex + +#### Description + +Returns information about an uncle specified by block hash and uncle index position + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| +|2|{[`Quantity`](#quantity)}|index of uncle| + +#### Returns + +{`null|object`} - `null` if no block or uncle is found, otherwise an uncle object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleByBlockHashAndIndex", + "params": ["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', + "blockNumber": '0xb', + "contractAddress": '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + "cumulativeGasUsed": '0x33bc', + "gasUsed": '0x4dc', + "logs": [], + "logsBloom": "0x00...0", + "status": "0x1", + "transactionHash": '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238', + "transactionIndex": '0x1' + } +} +``` +--- +
+ +
+eth_getUncleByBlockNumberAndIndex + +#### Description + +Returns information about an uncle specified by block number and uncle index position + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| +|2|{[`Quantity`](#quantity)}|index of uncle| + +#### Returns + +{`null|object`} - `null` if no block or uncle is found, otherwise an uncle object with the following members: + +- {[`Data`](#data)} `extraData` - "extra data" field of this block +- {[`Data`](#data)} `hash` - block hash or `null` if pending +- {[`Data`](#data)} `logsBloom` - logs bloom filter or `null` if pending +- {[`Data`](#data)} `miner` - address that received this block's mining rewards +- {[`Data`](#data)} `nonce` - proof-of-work hash or `null` if pending +- {[`Data`](#data)} `parentHash` - parent block hash +- {[`Data`](#data)} `receiptsRoot` -root of the this block's receipts trie +- {[`Data`](#data)} `sha3Uncles` - SHA3 of the uncles data in this block +- {[`Data`](#data)} `stateRoot` - root of this block's final state trie +- {[`Data`](#data)} `transactionsRoot` - root of this block's transaction trie +- {[`Quantity`](#quantity)} `difficulty` - difficulty for this block +- {[`Quantity`](#quantity)} `gasLimit` - maximum gas allowed in this block +- {[`Quantity`](#quantity)} `gasUsed` - total used gas by all transactions in this block +- {[`Quantity`](#quantity)} `number` - block number or `null` if pending +- {[`Quantity`](#quantity)} `size` - size of this block in bytes +- {[`Quantity`](#quantity)} `timestamp` - unix timestamp of when this block was collated +- {[`Quantity`](#quantity)} `totalDifficulty` - total difficulty of the chain until this block +- {`Array`} `uncles` - list of uncle hashes + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleByBlockNumberAndIndex", + "params": ["0x29c", "0x0"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "blockHash": '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b', + "blockNumber": '0xb', + "contractAddress": '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + "cumulativeGasUsed": '0x33bc', + "gasUsed": '0x4dc', + "logs": [], + "logsBloom": "0x00...0", + "status": "0x1", + "transactionHash": '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238', + "transactionIndex": '0x1' + } +} +``` +--- +
+ +
+eth_getUncleCountByBlockHash + +#### Description + +Returns the number of uncles in a block specified by block hash + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash of a block| + +#### Returns + +{[`Quantity`](#quantity)} - number of uncles in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockHash", + "params": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xc" +} +``` +--- +
+ +
+eth_getUncleCountByBlockNumber + +#### Description + +Returns the number of uncles in a block specified by block number + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)\|`string`}|block number, or one of `"latest"`, `"earliest"` or `"pending"`| + +#### Returns + +{[`Quantity`](#quantity)} - number of uncles in the specified block + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockNumber", + "params": ["0xe8"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_getWork + +#### Description + +Returns a list containing relevant information for proof-of-work + +#### Parameters + +_none_ + +#### Returns + +{[`Data[]`](#data)} - array with the following items: + +1. {[`Data`](#data)} - current block header pow-hash +1. {[`Data`](#data)} - seed hash used for the DAG +1. {[`Data`](#data)} - boundary condition ("target"), 2^256 / difficulty + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_getWork", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": [ + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "0x5EED00000000000000000000000000005EED0000000000000000000000000000", + "0xd1ff1c01710000000000000000000000d1ff1c01710000000000000000000000" + ] +} +``` +--- +
+ +
+eth_hashrate + +#### Description + +Returns the number of hashes-per-second this node is mining at + +#### Parameters + +_(none)_ + +#### Returns + +{[`Quantity`](#quantity)} - number of hashes-per-second + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_hashrate", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x38a" +} +``` +--- +
+ +
+eth_mining + +#### Description + +Determines if this client is mining new blocks + +#### Parameters + +_(none)_ + +#### Returns + +{`boolean`} - `true` if this client is mining or `false` if it is not mining + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_mining", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +
+eth_newBlockFilter + +#### Description + +Creates a filter to listen for new blocks that can be used with `eth_getFilterChanges` + +#### Parameters + +_none_ + +#### Returns + +{[`Quantity`](#quantity)} - ID of the newly-created filter that can be used with `eth_getFilterChanges` + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_newBlockFilter", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_newFilter + +#### Description + +Creates a filter to listen for specific state changes that can then be used with `eth_getFilterChanges` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Quantity`](#quantity)\|`string`} `[fromBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Quantity`](#quantity)\|`string`} `[toBlock]` - block number, or one of `"latest"`, `"earliest"` or `"pending"`
@property {[`Data`](#data)\|[`Data[]`](#data)} `[address]` - contract address or a list of addresses from which logs should originate
@property {[`Data[]`](#data)} `[topics]` - list of order-dependent topics| + +**Note:** Topics are order-dependent. A transaction with a log with topics `[A, B]` will be matched by the following topic filters: +- `[]` - "anything" +- `[A]` - "A in first position (and anything after)" +- `[null, B]` - "anything in first position AND B in second position (and anything after)" +- `[A, B]` - "A in first position AND B in second position (and anything after)" +- `[[A, B], [A, B]]` - "(A OR B) in first position AND (A OR B) in second position (and anything after)" + +#### Returns + +{[`Quantity`](#quantity)} - ID of the newly-created filter that can be used with `eth_getFilterChanges` + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_newFilter", + "params": [{ + "topics": ["0x0000000000000000000000000000000000000000000000000000000012341234"] + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_newPendingTransactionFilter + +#### Description + +Creates a filter to listen for new pending transactions that can be used with `eth_getFilterChanges` + +#### Parameters + +_none_ + +#### Returns + +{[`Quantity`](#quantity)} - ID of the newly-created filter that can be used with `eth_getFilterChanges` + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_newPendingTransactionFilter", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x1" +} +``` +--- +
+ +
+eth_protocolVersion + +#### Description + +Returns the current Ethereum protocol version + +#### Parameters + +_(none)_ + +#### Returns + +{`string`} - current Ethereum protocol version + +#### Example +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_protocolVersion", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "54" +} +``` +--- +
+ +
+eth_sendRawTransaction + +#### Description + +Sends and already-signed transaction to the network + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|signed transaction data| + +#### Returns + +{[`Data`](#data)} - transaction hash, or the zero hash if the transaction is not yet available + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" +} +``` +--- +
+ +
+eth_sendTransaction + +#### Description + +Creates, signs, and sends a new transaction to the network + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `from` - transaction sender
@property {[`Data`](#data)} `[to]` - transaction recipient
@property {[`Quantity`](#quantity)} `[gas="0x15f90"]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args
@property {[`Quantity`](#quantity)} `[nonce]` - unique number identifying this transaction| + +#### Returns + +{[`Data`](#data)} - transaction hash, or the zero hash if the transaction is not yet available + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" +} +``` +--- +
+ +
+eth_sign + +#### Description + +Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to use for signing| +|2|{[`Data`](#data)}|data to sign| + +#### Returns + +{[`Data`](#data)} - signature hash of the provided data + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_sign", + "params": ["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", "0xdeadbeaf"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b" +} +``` +--- +
+ +
+eth_signTransaction + +#### Description + +Signs a transaction that can be submitted to the network at a later time using with `eth_sendRawTransaction` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{`object`}|@property {[`Data`](#data)} `from` - transaction sender
@property {[`Data`](#data)} `[to]` - transaction recipient
@property {[`Quantity`](#quantity)} `[gas="0x15f90"]` - gas provided for transaction execution
@property {[`Quantity`](#quantity)} `[gasPrice]` - price in wei of each gas used
@property {[`Quantity`](#quantity)} `[value]` - value in wei sent with this transaction
@property {[`Data`](#data)} `[data]` - contract code or a hashed method call with encoded args
@property {[`Quantity`](#quantity)} `[nonce]` - unique number identifying this transaction| + +#### Returns + +{[`Data`](#data)} - signature hash of the transaction object + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_signTransaction", + "params": [{ + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "value": "0x9184e72a" + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b" +} +``` +--- +
+ +
+eth_signTypedData + +#### Description + +Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))` + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|address to use for signing| +|2|{[`Data`](#data)}|message to sign containing type information, a domain separator, and data| + +**Note:** Client developers should refer to EIP-712 for complete semantics around [encoding and signing data](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#specification). Dapp developers should refer to EIP-712 for the expected structure of [RPC method input parameters](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#parameters). + +#### Returns + +{[`Data`](#data)} - signature hash of the provided message + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337 + "jsonrpc": "2.0", + "method": "eth_signTypedData", + "params": ["0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", { + "types": { + "EIP712Domain": [{ + "name": "name", + "type": "string" + }, { + "name": "version", + "type": "string" + }, { + "name": "chainId", + "type": "uint256" + }, { + "name": "verifyingContract", + "type": "address" + }], + "Person": [{ + "name": "name", + "type": "string" + }, { + "name": "wallet", + "type": "address" + }], + "Mail": [{ + "name": "from", + "type": "Person" + }, { + "name": "to", + "type": "Person" + }, { + "name": "contents", + "type": "string" + }] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + }] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c" +} +``` +--- +
+ +
+eth_submitHashrate + +#### Description + +Submit a mining hashrate + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|hash rate| +|2|{[`Data`](#data)}|random ID identifying this node| + +#### Returns + +{`boolean`} - `true` if submitting went through successfully, `false` otherwise + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_submitHashrate", + "params": [ + "0x0000000000000000000000000000000000000000000000000000000000500000", + "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c" + ] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +
+eth_submitWork + +#### Description + +Submit a proof-of-work solution + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Data`](#data)}|nonce found| +|2|{[`Data`](#data)}|header's pow-hash| +|3|{[`Data`](#data)}|mix digest| + +#### Returns + +{`boolean`} - `true` if the provided solution is valid, `false` otherwise + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_submitWork", + "params": [ + "0x0000000000000001", + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "0xD1GE5700000000000000000000000000D1GE5700000000000000000000000000" + ] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ + +
+eth_syncing + +#### Description + +Returns information about the status of this client's network synchronization + +#### Parameters + +_(none)_ + +#### Returns + +{`boolean|object`} - `false` if this client is not syncing with the network, otherwise an object with the following members: + +- {[`Quantity`](#quantity)} `currentBlock` - number of the most-recent block synced +- {[`Quantity`](#quantity)} `highestBlock` - number of latest block on the network +- {[`Quantity`](#quantity)} `startingBlock` - block number at which syncing started + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_syncing", + "params": [] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": { + "currentBlock": '0x386', + "highestBlock": '0x454', + "startingBlock": '0x384' + } +} +``` +--- +
+ +
+eth_uninstallFilter + +#### Description + +Destroys a filter based on filter ID + +**Note:** This should only be called if a filter and its notifications are no longer needed. This will also be called automatically on a filter if its notifications are not retrieved using `eth_getFilterChanges` for a period of time. + +#### Parameters + +|#|Type|Description| +|-|-|-| +|1|{[`Quantity`](#quantity)}|ID of the filter to destroy| + +#### Returns + +{`boolean`} - `true` if the filter is found and successfully destroyed or `false` if it is not + +#### Example + +```sh +# Request +curl -X POST --data '{ + "id": 1337, + "jsonrpc": "2.0", + "method": "eth_uninstallFilter", + "params": ["0xb"] +}' + +# Response +{ + "id": 1337, + "jsonrpc": "2.0", + "result": true +} +``` +--- +
+ +## Rationale + +Much of Ethereum's effectiveness as an enterprise-grade application platform depends on its ability to provide a reliable and predictable developer experience. Nodes created by the current generation of Ethereum clients expose RPC endpoints with differing method signatures; this forces applications to work around method inconsistencies to maintain compatibility with various Ethereum RPC implementations. + +Both Ethereum client developers and downstream dapp developers lack a formal Ethereum RPC specification. This proposal standardizes such a specification in a way that's versionable and modifiable through the traditional EIP process. + +## Backwards compatibility + +This proposal impacts Ethereum client developers by requiring that any exposed RPC interface adheres to this specification. This proposal impacts dapp developers by requiring that any RPC calls currently used in applications are made according to this specification. + +## Implementation + +The current generation of Ethereum clients includes several implementations that attempt to expose this RPC specification: + +|Client Name|Language|Homepage| +|-|-|-| +|Geth|Go|[geth.ethereum.org](https://geth.ethereum.org)| +|Parity|Rust|[parity.io/ethereum](https://parity.io/ethereum)| +|Aleth|C++|[cpp-ethereum.org](https://cpp-ethereum.org)| + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From b501ba9c2f5441e4ef2bdbea2fc2ce880fae160b Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 7 Mar 2019 08:10:39 -0800 Subject: [PATCH 069/431] Ecmul Precompile (#1829) --- EIPS/eip-1829.md | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 EIPS/eip-1829.md diff --git a/EIPS/eip-1829.md b/EIPS/eip-1829.md new file mode 100644 index 00000000..c19892e6 --- /dev/null +++ b/EIPS/eip-1829.md @@ -0,0 +1,158 @@ +--- +eip: 1829 +title: Precompile for Elliptic Curve Linear Combinations +author: Remco Bloemen +discussions-to: https://ethereum-magicians.org/t/ewasm-precompile-for-general-elliptic-curve-math/2581 +status: Draft +type: Standards Track +category: Core +created: 2019-03-06 +--- + +# Precompile for Elliptic Curve Linear Combinations + +## Simple Summary + + +Currently the EVM only supports *secp261k1* in a limited way through `ecrecover` and *altbn128* through two pre-compiles. There are draft proposals to add more curves. There are many more elliptic curve that have useful application for integration with existing systems or newly developed curves for zero-knownledge proofs. + +This EIP adds a precompile that allows whole classes of curves to be used. + +## Abstract + + +A precompile that takes a curve and computes a linear combination of curve points. + +## Motivation + + +## Specification + + +Given integers `m, α` and `β`, scalars `s_i`, and curve points `A_i` construct the elliptic curve + +``` +y² = x³ + α ⋅ x + β mod m +``` + +and compute the following + +``` +C = s₀ ⋅ A₀ + s₁ ⋅ A₁ + ⋯ + s_n ⋅ A_n +``` + +aka *linear combination*, *inner product*, *multi-multiplication* or even *multi-exponentiation*. + +``` +(Cx, Cy) := ecmul(m, α, β, s0, Ax0, As0, s1, Ax1, As1, ...) +``` + +### Gas cost + +``` +BASE_GAS = ... +ADD_GAS = ... +MUL_GAS = ... +``` + +The total gas cost is `BASE_GAS` plus `ADD_GAS` for each `s_i` that is `1` and `MUL_GAS` for each `s_i > 1` (`s_i = 0` is free). + +### Encoding of points + +Encode as `(x, y')` where `s` is the indicates the wheter `y` or `-y` is to be taken. It follows SEC 1 v 1.9 2.3.4, except uncompressed points (`y' = 0x04`) are not supported. + +| `y'` | `(x, y)` | +|--------|-----| +| `0x00` | Point at infinity | +| `0x02` | Solution with `y` even | +| `0x03` | Solution with `y` odd | + +Conversion from affine coordinates to compressed coordinates is trivial: `y' = 0x02 | (y & 0x01)`. + +### Special cases + +**Coordinate recovery.** Set `s₀ = 1`. The output will be the recovered coordinates of `A₀`. + +**On-curve checking.** Do coordinate recovery and compare `y` coordinate. + +**Addition.** Set `s₀ = s₁ = 1`, the output will be `A₀ + A₁`. + +**Doubling.** Set `s₀ = 2`. The output will be `2 ⋅ A₀`. (Note: under current gas model this may be more costly than self-addition!) + +**Scalar multiplication.** Set only `s₀` and `A₀`. + +**Modular square root.** Set `α = s₀ = A = 0` the output will have `Cy² = β mod m`. + +### Edge cases + +* Non-prime moduli or too small modulus +* Field elements larger than modulus +* Curve has singular points (`4 α³ + 27 β² = 0`) +* Invalid sign bytes +* x coordinate not on curve +* Returning the point at infinity +* (Please add if you spot more) + +## Rationale + + +**Generic Field and Curve.** Many important optimizations are independent of the field and curve used. Some missed specific optimizations are: + +* Reductions specific to the binary structure of the field prime. +* Precomputation of Montgomery factors. +* Precomputation of multiples of certain popular points like the generator. +* Special point addition/doubling [formulas][formulas] for `α = -3`, `α = -1`, `α = 0`, `β = 0`. + + +[formulas]: http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html + +TODO: The special cases for `α` and `β` might be worth implementing and offered a gas discount. + +**Compressed Coordinates.** Compressed coordinates allow contract to work with only `x` coordinates and sign bytes. It also prevents errors around points not being on-curve. Conversion to compressed coordinates is trivial. + +**Linear Combination.** We could instead have a simple multiply `C = r ⋅ A`. In this case we would need a separate pre-compile for addition. In addtion, a linear combination allows for optimizations that like Shamir's trick that are not available in a single scalar multiplication. ECDSA requires `s₀ ⋅ A₀ + s₁ ⋅ A₁` and would benfit from this. + +The BN254 (aka alt_bn8) multiplication operation introduced by the [EIP-196][eip196] precompile only handles a single scalar multiplication. The missed performance is such that for two or more points it is cheaper to use EVM, as pratically demonstrated by [Weierstrudel][ws]. + +[eip196]: https://eips.ethereum.org/EIPS/eip-196 +[ws]: https://medium.com/aztec-protocol/huffing-for-crypto-with-weierstrudel-9c9568c06901 + +**Variable Time Math.** When called during a transaction, there is no assumption of privacy and no mittigations for side-channel attacks are necessary. + +**Prime Fields.** This EIP is for fields of large characteristic. It does not cover Binary fields and other fields of non-prime characteristic. + +**256-bit modulus.** This EIP is for field moduli less than `2^{256}`. This covers many of the popular curves while still having all parameters fit in a single EVM word. + +TODO: Consider a double-word version. 512 bits would cover all known curves except E-521. In particular it will cover the NIST P-384 curve used by the Estonian e-Identity and the BLS12-381 curve used by [ZCash Sappling][sappling]. + +[sappling]: https://z.cash/blog/new-snark-curve/ + +**Short Weierstrass Curves.** This EIP is for fields specified in short Weierstrass form. While any curve can be converted to short Weierstrass form through a [substitution of variables][cov], this misses out on the performance advantages of those specific forms. + +[cov]: https://safecurves.cr.yp.to/equation.html + +## Backwards Compatibility + + +## Test Cases + + +## Implementation + + +There will be a reference implementation in Rust based on the existing libraries (in particular those by ZCash and The Matter Inc.). + +The reference implementation will be production grade and compile to a native library with a C api and a webassembly version. Node developers are encouraged to use the reference implementation and can use either the rust library, the native C bindings or the webassembly module. Node developers can of course always decide to implement their own. + +## References + +This EIP overlaps in scope with + +* [EIP-196](https://eips.ethereum.org/EIPS/eip-196): ecadd, ecmul for altbn128 +* [EIP issue 603](https://github.com/ethereum/EIPs/issues/603): ecadd, ecmul for SECP256k1. +* [EIP 665](https://eips.ethereum.org/EIPS/eip-665): ECDSA verify for ED25519. +* [EIP 1108](https://eips.ethereum.org/EIPS/eip-1108): Optimize ecadd and ecmul for altbn128. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + From 1176e2fa4ac46113676aee6dfac5fa8ee39c4c29 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 8 Mar 2019 11:30:56 +1300 Subject: [PATCH 070/431] Automatically merged updates to draft EIP(s) 1767 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1767.md | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/EIPS/eip-1767.md b/EIPS/eip-1767.md index 21f5f195..02a9246e 100644 --- a/EIPS/eip-1767.md +++ b/EIPS/eip-1767.md @@ -219,6 +219,13 @@ type Block { transactionAt(index: Int!): Transaction # Logs returns a filtered set of logs from this block. logs(filter: BlockFilterCriteria!): [Log!]! + # Account fetches an Ethereum account at the current block's state. + account(address: Address!): Account! + # Call executes a local call operation at the current block's state. + call(data: CallData!): CallResult + # EstimateGas estimates the amount of gas that will be required for + # successful execution of a transaction at the current block's state. + estimateGas(data: CallData!): Long! } # CallData represents the data associated with a local contract call. @@ -289,25 +296,32 @@ type SyncState{ knownStates: Long } +# Pending represents the current pending state. +type Pending { + # TransactionCount is the number of transactions in the pending state. + transactionCount: Int! + # Transactions is a list of transactions in the current pending state. + transactions: [Transaction!] + # Account fetches an Ethereum account for the pending state. + account(address: Address!): Account! + # Call executes a local call operation for the pending state. + call(data: CallData!): CallResult + # EstimateGas estimates the amount of gas that will be required for + # successful execution of a transaction for the pending state. + estimateGas(data: CallData!): Long! +} + type Query { - # Account fetches an Ethereum account at the specified block number. - # If blockNumber is not provided, it defaults to the most recent block. - account(address: Address!, blockNumber: Long): Account! # Block fetches an Ethereum block by number or by hash. If neither is # supplied, the most recent known block is returned. block(number: Long, hash: Bytes32): Block # Blocks returns all the blocks between two numbers, inclusive. If # to is not supplied, it defaults to the most recent known block. blocks(from: Long!, to: Long): [Block!]! + # Pending returns the current pending state. + pending: Pending! # Transaction returns a transaction specified by its hash. transaction(hash: Bytes32!): Transaction - # Call executes a local call operation. If blockNumber is not specified, - # it defaults to the most recent known block. - call(data: CallData!, blockNumber: Long): CallResult - # EstimateGas estimates the amount of gas that will be required for - # successful execution of a transaction. If blockNumber is not specified, - # it defaults to the most recent known block. - estimateGas(data: CallData!, blockNumber: Long): Long! # Logs returns log entries matching the provided filter. logs(filter: FilterCriteria!): [Log!]! # GasPrice returns the node's estimate of a gas price sufficient to From 2eed68179dc940f112b7e99f4de11e2429ccdc82 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 8 Mar 2019 04:20:48 -0500 Subject: [PATCH 071/431] Use correct Twitter URL (#1807) --- _includes/social.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/social.html b/_includes/social.html index 9783b84a..a4983ccb 100644 --- a/_includes/social.html +++ b/_includes/social.html @@ -7,7 +7,7 @@ {%- if site.linkedin_username -%}
  • {{ site.linkedin_username| escape }}
  • {%- endif -%} {%- if site.pinterest_username -%}
  • {{ site.pinterest_username| escape }}
  • {%- endif -%} {%- for mst in site.mastodon -%}{%- if mst.username and mst.instance -%}
  • {{ mst.username|escape }}
  • {%- endif -%}{%- endfor -%} - {%- if site.twitter_username -%}
  • {{ site.twitter_username| escape }}
  • {%- endif -%} + {%- if site.twitter_username -%}
  • {{ site.twitter_username| escape }}
  • {%- endif -%} {%- if site.youtube_username -%}
  • {{ site.youtube_username| escape }}
  • {%- endif -%} {%- if site.googleplus_username -%}
  • {{ site.googleplus_username| escape }}
  • {%- endif -%} {%- if site.rss -%}
  • {{ site.rss | escape }}
  • {%- endif -%} From 53f107c097ad8f1069b0d219e8b2ab61d877f983 Mon Sep 17 00:00:00 2001 From: Albert Date: Fri, 8 Mar 2019 12:14:39 +0100 Subject: [PATCH 072/431] Remove reference to EIP-59 in EIP-1 (#1743) --- EIPS/eip-1.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 37fa84b0..e9b08abe 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -25,7 +25,7 @@ There are three types of EIP: - A **Standard Track EIP** describes any change that affects most or all Ethereum implementations, such as a change to the 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 Ethereum. Furthermore Standard EIPs can be broken down into the following categories. Standards Track EIPs consist of three parts, a design document, implementation, and finally if warranted an update to the [formal specification]. - **Core** - improvements requiring a consensus fork (e.g. [EIP5], [EIP101]), as well as changes that are not necessarily consensus critical but may be relevant to [“core dev” discussions](https://github.com/ethereum/pm) (for example, [EIP90], and the miner/node strategy changes 2, 3, and 4 of [EIP86]). - **Networking** - includes improvements around [devp2p] ([EIP8]) and [Light Ethereum Subprotocol], as well as proposed improvements to network protocol specifications of [whisper] and [swarm]. - - **Interface** - includes improvements around client [API/RPC] specifications and standards, and also certain language-level standards like method names ([EIP59], [EIP6]) and [contract ABIs]. The label “interface” aligns with the [interfaces repo] and discussion should primarily occur in that repository before an EIP is submitted to the EIPs repository. + - **Interface** - includes improvements around client [API/RPC] specifications and standards, and also certain language-level standards like method names ([EIP6]) and [contract ABIs]. The label “interface” aligns with the [interfaces repo] and discussion should primarily occur in that repository before an EIP is submitted to the EIPs repository. - **ERC** - application-level standards and conventions, including contract standards such as token standards ([ERC20]), name registries ([ERC26], [ERC137]), URI schemes ([ERC67]), library/package formats ([EIP82]), and wallet formats ([EIP75], [EIP85]). - An **Informational EIP** describes an Ethereum design issue, or provides general guidelines or information to the Ethereum community, but does not propose a new feature. Informational EIPs do not necessarily represent Ethereum community consensus or a recommendation, so users and implementers are free to ignore Informational EIPs or follow their advice. - A **Meta EIP** describes a process surrounding Ethereum or proposes a change to (or an event in) a process. Process EIPs are like Standards Track EIPs but apply to areas other than the Ethereum protocol itself. They may propose an implementation, but not to Ethereum's codebase; they often require community consensus; unlike Informational EIPs, 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 Ethereum development. Any meta-EIP is also considered a Process EIP. @@ -246,7 +246,6 @@ See [the revision history for further details](https://github.com/ethereum/EIPs/ [whisper]: https://github.com/ethereum/go-ethereum/wiki/Whisper-Overview [swarm]: https://github.com/ethereum/go-ethereum/pull/2959 [API/RPC]: https://github.com/ethereum/wiki/wiki/JSON-RPC -[EIP59]: https://github.com/ethereum/EIPs/issues/59 [EIP6]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-6.md [contract ABIs]: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI [interfaces repo]: https://github.com/ethereum/interfaces From a27de46e46ac009e4c479ac13ee02217fab7300c Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 8 Mar 2019 06:15:52 -0500 Subject: [PATCH 073/431] Update to use preferred citation format (#1732) --- EIPS/eip-607.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-607.md b/EIPS/eip-607.md index 5c524c37..aee1efa0 100644 --- a/EIPS/eip-607.md +++ b/EIPS/eip-607.md @@ -20,10 +20,10 @@ This specifies the changes included in the hard fork named Spurious Dragon. - Block >= 2,675,000 on Mainnet - Block >= 1,885,000 on Morden - Included EIPs: - - [EIP 155](eip-155.md) (Simple replay attack protection) - - [EIP 160](eip-160.md) (EXP cost increase) - - [EIP 161](eip-161.md) (State trie clearing) - - [EIP 170](eip-170.md) (Contract code size limit) + - [EIP 155](https://eips.ethereum.org/EIPS/eip-155) (Simple replay attack protection) + - [EIP 160](https://eips.ethereum.org/EIPS/eip-160) (EXP cost increase) + - [EIP 161](https://eips.ethereum.org/EIPS/eip-161) (State trie clearing) + - [EIP 170](https://eips.ethereum.org/EIPS/eip-170) (Contract code size limit) ## References From c2c12216223206c8c644686c031d7157401613cb Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 8 Mar 2019 06:16:38 -0500 Subject: [PATCH 074/431] Update to preferred citation format (#1733) --- ISSUE_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 965ebcb1..28fdd587 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -3,10 +3,10 @@ ATTENTION! If you would like to submit an EIP and it has already been written as If you are considering a proposal but would like to get some feedback on the idea before submitting a draft, then continue opening an Issue as a thread for discussion. Note that the more clearly and completely you state your idea the higher the quality of the feedback you are likely to receive. -Keep in mind the following guidelines from [EIP-1](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1.md): +Keep in mind the following guidelines from [EIP-1](https://eips.ethereum.org/EIPS/eip-1): > Each EIP must have a champion - someone who writes the EIP using the style and format described below, shepherds the discussions in the appropriate forums, and attempts to build community consensus around the idea. The EIP champion (a.k.a. Author) should first attempt to ascertain whether the idea is EIP-able. Posting to the the Protocol Discussion forum or opening an Issue is the best way to go about this. > Vetting an idea publicly before going as far as writing a EIP is meant to save the potential author time. Asking the Ethereum community first if an idea is original helps prevent too much time being spent on something that is guaranteed to be rejected based on prior discussions (searching the Internet does not always do the trick). 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 Ethereum is used. -> Once the champion has asked the Ethereum community as to whether an idea has any chance of acceptance, a draft EIP should be presented as a Pull Request. This gives the author a chance to flesh out the draft EIP to make properly formatted, of high quality, and to address initial concerns about the proposal. \ No newline at end of file +> Once the champion has asked the Ethereum community as to whether an idea has any chance of acceptance, a draft EIP should be presented as a Pull Request. This gives the author a chance to flesh out the draft EIP to make properly formatted, of high quality, and to address initial concerns about the proposal. From 8d9e083c6f461ffce395b81442f66be6c804ae30 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Fri, 8 Mar 2019 12:48:24 +0100 Subject: [PATCH 075/431] New EIP: Pseudo-introspection Registry Contract (#1820) This is a replacement for 820. --- EIPS/eip-1820.md | 929 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 929 insertions(+) create mode 100644 EIPS/eip-1820.md diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md new file mode 100644 index 00000000..9e418c5c --- /dev/null +++ b/EIPS/eip-1820.md @@ -0,0 +1,929 @@ +--- +eip: 1820 +title: Pseudo-introspection Registry Contract +author: Jordi Baylina , Jacques Dafflon +discussions-to: https://github.com/ethereum/EIPs/pulls/1820 +status: Draft +type: Standards Track +category: ERC +requires: 165, 214 +created: 2018-03-04 +replaces: 820 +--- + +> :information_source: **[ERC1820] has superseded [ERC820].** :information_source: +> [ERC1820] fixes the incompatibility in the [ERC165] logic which was introduced by the Solidty 0.5 update. +> Have a look at the [official announcement][erc1820-annoucement], and the comments about the [bug][erc820-bug] and the [fix][erc820-fix]. +> Apart from this fix, [ERC1820] is functionally equivalent to [ERC820]. +> +> :warning: [ERC1820] MUST be used in lieu of [ERC820]. :warning: + +## Simple Summary + +This standard defines a universal registry smart contract where any address (contract or regular account) can register which interface it supports and which smart contract is responsible for its implementation. + +This standard keeps backward compatibility with [ERC165]. + +## Abstract + +This standard defines a registry where smart contracts and regular accounts can publish which functionality they implement---either directly or through a proxy contract. + +Anyone can query this registry to ask if a specific address implements a given interface and which smart contract handles its implementation. + +This registry MAY be deployed on any chain and shares the same address on all chains. + +Interfaces with zeroes (`0`) as the last 28 bytes are considered [ERC165] interfaces, +and this registry SHALL forward the call to the contract to see if it implements the interface. + +This contract also acts as an [ERC165] cache to reduce gas consumption. + +## Motivation + +There have been different approaches to define pseudo-introspection in Ethereum. +The first is [ERC165] which has the limitation that it cannot be used by regular accounts. +The second attempt is [ERC672] which uses reverse [ENS]. Using reverse [ENS] has two issues. +First, it is unnecessarily complicated, and second, [ENS] is still a centralized contract controlled by a multisig. +This multisig theoretically would be able to modify the system. + +This standard is much simpler than [ERC672], and it is *fully* decentralized. + +This standard also provides a *unique* address for all chains. +Thus solving the problem of resolving the correct registry address for different chains. + +## Specification + +### [ERC1820] Registry Smart Contract + +> This is an exact copy of the code of the [ERC1820 registry smart contract]. + +``` solidity +/* ERC1820 Pseudo-introspection Registry Contract + * This standard defines a universal registry smart contract where any address (contract or regular account) can + * register which interface it supports and which smart contract is responsible for its implementation. + * + * Written in 2019 by Jordi Baylina and Jacques Dafflon + * + * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to + * this software to the public domain worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see + * . + * + * ███████╗██████╗ ██████╗ ██╗ █████╗ ██████╗ ██████╗ + * ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗ + * █████╗ ██████╔╝██║ ╚██║╚█████╔╝ █████╔╝██║██╔██║ + * ██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔═══╝ ████╔╝██║ + * ███████╗██║ ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝ + * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝ + * + * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗ + * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝ + * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝ + * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝ + * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║ + * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ + * + */ +pragma solidity 0.5.3; +// IV is value needed to have a vanity address starting with `0x1820`. +// IV: 87018 + +/// @dev The interface a contract MUST implement if it is the implementer of +/// some (other) interface for any address other than itself. +interface ERC1820ImplementerInterface { + /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not. + /// @param interfaceHash keccak256 hash of the name of the interface + /// @param addr Address for which the contract will implement the interface + /// @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`. + function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); +} + + +/// @title ERC1820 Pseudo-introspection Registry Contract +/// @author Jordi Baylina and Jacques Dafflon +/// @notice This contract is the official implementation of the ERC1820 Registry. +/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820 +contract ERC1820Registry { + /// @notice ERC165 Invalid ID. + bytes4 constant internal INVALID_ID = 0xffffffff; + /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`). + bytes4 constant internal ERC165ID = 0x01ffc9a7; + /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address. + bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")); + + /// @notice mapping from addresses and interface hashes to their implementers. + mapping(address => mapping(bytes32 => address)) internal interfaces; + /// @notice mapping from addresses to their manager. + mapping(address => address) internal managers; + /// @notice flag for each address and erc165 interface to indicate if it is cached. + mapping(address => mapping(bytes4 => bool)) internal erc165Cached; + + /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`. + event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer); + /// @notice Indicates `newManager` is the address of the new manager for `addr`. + event ManagerChanged(address indexed addr, address indexed newManager); + + /// @notice Query if an address implements an interface and through which contract. + /// @param _addr Address being queried for the implementer of an interface. + /// (If '_addr' is the zero address then 'msg.sender' is assumed.) + /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. + /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. + /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr.address()` + /// or '0' if `_addr.address()` did not register an implementer for this interface. + function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) { + address addr = _addr == address(0) ? msg.sender : _addr; + if (isERC165Interface(_interfaceHash)) { + bytes4 erc165InterfaceHash = bytes4(_interfaceHash); + return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0); + } + return interfaces[addr][_interfaceHash]; + } + + /// @notice Sets the contract which implements a specific interface for an address. + /// Only the manager defined for that address can set it. + /// (Each address is the manager for itself until it sets a new manager.) + /// @param _addr Address for which to set the interface. + /// (If '_addr' is the zero address then 'msg.sender' is assumed.) + /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. + /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. + /// @param _implementer Contract address implementing `_interfaceHash` for `_addr.address()`. + function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external { + address addr = _addr == address(0) ? msg.sender : _addr; + require(getManager(addr) == msg.sender, "Not the manager"); + + require(!isERC165Interface(_interfaceHash), "Must not be an ERC165 hash"); + if (_implementer != address(0) && _implementer != msg.sender) { + require( + ERC1820ImplementerInterface(_implementer) + .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC, + "Does not implement the interface" + ); + } + interfaces[addr][_interfaceHash] = _implementer; + emit InterfaceImplementerSet(addr, _interfaceHash, _implementer); + } + + /// @notice Sets `_newManager.address()` as manager for `_addr.address()`. + /// The new manager will be able to call 'setInterfaceImplementer' for `_addr.address()`. + /// @param _addr Address for which to set the new manager. + /// @param _newManager Address of the new manager for `addr.address()`. + /// (Pass '0x0' to reset the manager to `_addr.address()`.) + function setManager(address _addr, address _newManager) external { + require(getManager(_addr) == msg.sender, "Not the manager"); + managers[_addr] = _newManager == _addr ? address(0) : _newManager; + emit ManagerChanged(_addr, _newManager); + } + + /// @notice Get the manager of an address. + /// @param _addr Address for which to return the manager. + /// @return Address of the manager for a given address. + function getManager(address _addr) public view returns(address) { + // By default the manager of an address is the same address + if (managers[_addr] == address(0)) { + return _addr; + } else { + return managers[_addr]; + } + } + + /// @notice Compute the keccak256 hash of an interface given its name. + /// @param _interfaceName Name of the interface. + /// @return The keccak256 hash of an interface name. + function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) { + return keccak256(abi.encodePacked(_interfaceName)); + } + + /* --- ERC165 Related Functions --- */ + /* --- Developed in collaboration with William Entriken. --- */ + + /// @notice Updates the cache with whether the contract implements an ERC165 interface or not. + /// @param _contract Address of the contract for which to update the cache. + /// @param _interfaceId ERC165 interface for which to update the cache. + function updateERC165Cache(address _contract, bytes4 _interfaceId) external { + interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache( + _contract, _interfaceId) ? _contract : address(0); + erc165Cached[_contract][_interfaceId] = true; + } + + /// @notice Checks whether a contract implements an ERC165 interface or not. + // If the result is not cached a direct lookup on the contract address is performed. + // If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling + // 'updateERC165Cache' with the contract address. + /// @param _contract Address of the contract to check. + /// @param _interfaceId ERC165 interface to check. + /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise. + function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) { + if (!erc165Cached[_contract][_interfaceId]) { + return implementsERC165InterfaceNoCache(_contract, _interfaceId); + } + return interfaces[_contract][_interfaceId] == _contract; + } + + /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. + /// @param _contract Address of the contract to check. + /// @param _interfaceId ERC165 interface to check. + /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise. + function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) { + uint256 success; + uint256 result; + + (success, result) = noThrowCall(_contract, ERC165ID); + if (success == 0 || result == 0) { + return false; + } + + (success, result) = noThrowCall(_contract, INVALID_ID); + if (success == 0 || result != 0) { + return false; + } + + (success, result) = noThrowCall(_contract, _interfaceId); + if (success == 1 && result == 1) { + return true; + } + return false; + } + + /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not. + /// @param _interfaceHash The hash to check. + /// @return True if `_interfaceHash` is an ERC165 interface (ending with 28 zeroes), false otherwise. + function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) { + return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0; + } + + /// @dev Make a call on a contract without throwing if the function does not exist. + function noThrowCall(address _contract, bytes4 _interfaceId) + internal view returns (uint256 success, uint256 result) + { + bytes4 erc165ID = ERC165ID; + + assembly { + let x := mload(0x40) // Find empty storage location using "free memory pointer" + mstore(x, erc165ID) // Place signature at beginning of empty storage + mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature + + success := staticcall( + 30000, // 30k gas + _contract, // To addr + x, // Inputs are stored at location x + 0x24, // Inputs are 36 (4 + 32) bytes long + x, // Store output over input (saves space) + 0x20 // Outputs are 32 bytes long + ) + + result := mload(x) // Load the result + } + } +} + +``` + +### Deployment Transaction + +Below is the raw transaction which MUST be used to deploy the smart contract on any chain. + +``` +0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820 +``` + +The strings of `1820`'s at the end of the transaction are the `r` and `s` of the signature. +From this deterministic pattern (generated by a human), anyone can deduce that no one knows the private key for the deployment account. + +### Deployment Method + +This contract is going to be deployed using the keyless deployment method---also known as [Nick]'s method---which relies on a single-use address. +(See [Nick's article] for more details). This method works as follows: + +1. Generate a transaction which deploys the contract from a new random account. + - This transaction MUST NOT use [EIP155] in order to work on any chain. + - This transaction MUST have a relatively high gas price to be deployed on any chain. In this case, it is going to be 100 Gwei. + +2. Set the `v`, `r`, `s` of the transaction signature to the following values: + + ``` + v: 27, + r: 0x1820182018201820182018201820182018201820182018201820182018201820' + s: 0x1820182018201820182018201820182018201820182018201820182018201820' + ``` + + Those `r` and `s` values---made of a repeating pattern of `1820`'s---are predictable "random numbers" generated deterministically by a human. + +3. We recover the sender of this transaction, i.e., the single-use deployment account. + + > Thus we obtain an account that can broadcast that transaction, but we also have the warranty that nobody knows the private key of that account. + +4. Send exactly 0.08 ether to this single-use deployment account. + +5. Broadcast the deployment transaction. + +This operation can be done on any chain, guaranteeing that the contract address is always the same and nobody can use that address with a different contract. + + +### Single-use Registry Deployment Account + +``` +0x5808bA8E60E0367C9067b328D75C1f3d29de58cf +``` + +This account is generated by reverse engineering it from its signature for the transaction. +This way no one knows the private key, but it is known that it is the valid signer of the deployment transaction. + +> To deploy the registry, 0.08 ether MUST be sent to this account *first*. + +### Registry Contract Address + +``` +0x1820b744B33945482C17Dc37218C01D858EBc714 +``` + +The contract has the address above for every chain on which it is deployed. + +
    +Raw metadata of ./contracts/ERC1820Registry.sol +
    +{
    +        "compiler": {
    +          "version": "0.5.3+commit.10d17f24"
    +        },
    +        "language": "Solidity",
    +        "output": {
    +          "abi": [
    +            {
    +              "constant": false,
    +              "inputs": [
    +                {
    +                  "name": "_addr",
    +                  "type": "address"
    +                },
    +                {
    +                  "name": "_interfaceHash",
    +                  "type": "bytes32"
    +                },
    +                {
    +                  "name": "_implementer",
    +                  "type": "address"
    +                }
    +              ],
    +              "name": "setInterfaceImplementer",
    +              "outputs": [],
    +              "payable": false,
    +              "stateMutability": "nonpayable",
    +              "type": "function"
    +            },
    +            {
    +              "constant": true,
    +              "inputs": [
    +                {
    +                  "name": "_addr",
    +                  "type": "address"
    +                }
    +              ],
    +              "name": "getManager",
    +              "outputs": [
    +                {
    +                  "name": "",
    +                  "type": "address"
    +                }
    +              ],
    +              "payable": false,
    +              "stateMutability": "view",
    +              "type": "function"
    +            },
    +            {
    +              "constant": false,
    +              "inputs": [
    +                {
    +                  "name": "_addr",
    +                  "type": "address"
    +                },
    +                {
    +                  "name": "_newManager",
    +                  "type": "address"
    +                }
    +              ],
    +              "name": "setManager",
    +              "outputs": [],
    +              "payable": false,
    +              "stateMutability": "nonpayable",
    +              "type": "function"
    +            },
    +            {
    +              "constant": true,
    +              "inputs": [
    +                {
    +                  "name": "_interfaceName",
    +                  "type": "string"
    +                }
    +              ],
    +              "name": "interfaceHash",
    +              "outputs": [
    +                {
    +                  "name": "",
    +                  "type": "bytes32"
    +                }
    +              ],
    +              "payable": false,
    +              "stateMutability": "pure",
    +              "type": "function"
    +            },
    +            {
    +              "constant": false,
    +              "inputs": [
    +                {
    +                  "name": "_contract",
    +                  "type": "address"
    +                },
    +                {
    +                  "name": "_interfaceId",
    +                  "type": "bytes4"
    +                }
    +              ],
    +              "name": "updateERC165Cache",
    +              "outputs": [],
    +              "payable": false,
    +              "stateMutability": "nonpayable",
    +              "type": "function"
    +            },
    +            {
    +              "constant": true,
    +              "inputs": [
    +                {
    +                  "name": "_addr",
    +                  "type": "address"
    +                },
    +                {
    +                  "name": "_interfaceHash",
    +                  "type": "bytes32"
    +                }
    +              ],
    +              "name": "getInterfaceImplementer",
    +              "outputs": [
    +                {
    +                  "name": "",
    +                  "type": "address"
    +                }
    +              ],
    +              "payable": false,
    +              "stateMutability": "view",
    +              "type": "function"
    +            },
    +            {
    +              "constant": true,
    +              "inputs": [
    +                {
    +                  "name": "_contract",
    +                  "type": "address"
    +                },
    +                {
    +                  "name": "_interfaceId",
    +                  "type": "bytes4"
    +                }
    +              ],
    +              "name": "implementsERC165InterfaceNoCache",
    +              "outputs": [
    +                {
    +                  "name": "",
    +                  "type": "bool"
    +                }
    +              ],
    +              "payable": false,
    +              "stateMutability": "view",
    +              "type": "function"
    +            },
    +            {
    +              "constant": true,
    +              "inputs": [
    +                {
    +                  "name": "_contract",
    +                  "type": "address"
    +                },
    +                {
    +                  "name": "_interfaceId",
    +                  "type": "bytes4"
    +                }
    +              ],
    +              "name": "implementsERC165Interface",
    +              "outputs": [
    +                {
    +                  "name": "",
    +                  "type": "bool"
    +                }
    +              ],
    +              "payable": false,
    +              "stateMutability": "view",
    +              "type": "function"
    +            },
    +            {
    +              "anonymous": false,
    +              "inputs": [
    +                {
    +                  "indexed": true,
    +                  "name": "addr",
    +                  "type": "address"
    +                },
    +                {
    +                  "indexed": true,
    +                  "name": "interfaceHash",
    +                  "type": "bytes32"
    +                },
    +                {
    +                  "indexed": true,
    +                  "name": "implementer",
    +                  "type": "address"
    +                }
    +              ],
    +              "name": "InterfaceImplementerSet",
    +              "type": "event"
    +            },
    +            {
    +              "anonymous": false,
    +              "inputs": [
    +                {
    +                  "indexed": true,
    +                  "name": "addr",
    +                  "type": "address"
    +                },
    +                {
    +                  "indexed": true,
    +                  "name": "newManager",
    +                  "type": "address"
    +                }
    +              ],
    +              "name": "ManagerChanged",
    +              "type": "event"
    +            }
    +          ],
    +          "devdoc": {
    +            "author": "Jordi Baylina and Jacques Dafflon",
    +            "methods": {
    +              "getInterfaceImplementer(address,bytes32)": {
    +                "params": {
    +                  "_addr": "Address being queried for the implementer of an interface. (If '_addr' is the zero address then 'msg.sender' is assumed.)",
    +                  "_interfaceHash": "Keccak256 hash of the name of the interface as a string. E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface."
    +                },
    +                "return": "The address of the contract which implements the interface `_interfaceHash` for `_addr.address()` or '0' if `_addr.address()` did not register an implementer for this interface."
    +              },
    +              "getManager(address)": {
    +                "params": {
    +                  "_addr": "Address for which to return the manager."
    +                },
    +                "return": "Address of the manager for a given address."
    +              },
    +              "implementsERC165Interface(address,bytes4)": {
    +                "params": {
    +                  "_contract": "Address of the contract to check.",
    +                  "_interfaceId": "ERC165 interface to check."
    +                },
    +                "return": "True if `_contract.address()` implements `_interfaceId`, false otherwise."
    +              },
    +              "implementsERC165InterfaceNoCache(address,bytes4)": {
    +                "params": {
    +                  "_contract": "Address of the contract to check.",
    +                  "_interfaceId": "ERC165 interface to check."
    +                },
    +                "return": "True if `_contract.address()` implements `_interfaceId`, false otherwise."
    +              },
    +              "interfaceHash(string)": {
    +                "params": {
    +                  "_interfaceName": "Name of the interface."
    +                },
    +                "return": "The keccak256 hash of an interface name."
    +              },
    +              "setInterfaceImplementer(address,bytes32,address)": {
    +                "params": {
    +                  "_addr": "Address for which to set the interface. (If '_addr' is the zero address then 'msg.sender' is assumed.)",
    +                  "_implementer": "Contract address implementing `_interfaceHash` for `_addr.address()`.",
    +                  "_interfaceHash": "Keccak256 hash of the name of the interface as a string. E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface."
    +                }
    +              },
    +              "setManager(address,address)": {
    +                "params": {
    +                  "_addr": "Address for which to set the new manager.",
    +                  "_newManager": "Address of the new manager for `addr.address()`. (Pass '0x0' to reset the manager to `_addr.address()`.)"
    +                }
    +              },
    +              "updateERC165Cache(address,bytes4)": {
    +                "params": {
    +                  "_contract": "Address of the contract for which to update the cache.",
    +                  "_interfaceId": "ERC165 interface for which to update the cache."
    +                }
    +              }
    +            },
    +            "title": "ERC1820 Pseudo-introspection Registry Contract"
    +          },
    +          "userdoc": {
    +            "methods": {
    +              "getInterfaceImplementer(address,bytes32)": {
    +                "notice": "Query if an address implements an interface and through which contract."
    +              },
    +              "getManager(address)": {
    +                "notice": "Get the manager of an address."
    +              },
    +              "implementsERC165InterfaceNoCache(address,bytes4)": {
    +                "notice": "Checks whether a contract implements an ERC165 interface or not without using nor updating the cache."
    +              },
    +              "interfaceHash(string)": {
    +                "notice": "Compute the keccak256 hash of an interface given its name."
    +              },
    +              "setInterfaceImplementer(address,bytes32,address)": {
    +                "notice": "Sets the contract which implements a specific interface for an address. Only the manager defined for that address can set it. (Each address is the manager for itself until it sets a new manager.)"
    +              },
    +              "setManager(address,address)": {
    +                "notice": "Sets `_newManager.address()` as manager for `_addr.address()`. The new manager will be able to call 'setInterfaceImplementer' for `_addr.address()`."
    +              },
    +              "updateERC165Cache(address,bytes4)": {
    +                "notice": "Updates the cache with whether the contract implements an ERC165 interface or not."
    +              }
    +            },
    +            "notice": "This contract is the official implementation of the ERC1820 Registry.For more details, see https://eips.ethereum.org/EIPS/eip-1820"
    +          }
    +        },
    +        "settings": {
    +          "compilationTarget": {
    +            "./contracts/ERC1820Registry.sol": "ERC1820Registry"
    +          },
    +          "evmVersion": "byzantium",
    +          "libraries": {},
    +          "optimizer": {
    +            "enabled": true,
    +            "runs": 200
    +          },
    +          "remappings": []
    +        },
    +        "sources": {
    +          "./contracts/ERC1820Registry.sol": {
    +            "content": "/* ERC1820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address (contract or regular account) can\n * register which interface it supports and which smart contract is responsible for its implementation.\n *\n * Written in 2019 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to\n * this software to the public domain worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see\n * .\n *\n *    ███████╗██████╗  ██████╗ ██╗ █████╗ ██████╗  ██████╗\n *    ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗\n *    █████╗  ██████╔╝██║     ╚██║╚█████╔╝ █████╔╝██║██╔██║\n *    ██╔══╝  ██╔══██╗██║      ██║██╔══██╗██╔═══╝ ████╔╝██║\n *    ███████╗██║  ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝\n *    ╚══════╝╚═╝  ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n *    ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗   ██╗\n *    ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n *    ██████╔╝█████╗  ██║  ███╗██║███████╗   ██║   ██████╔╝ ╚████╔╝\n *    ██╔══██╗██╔══╝  ██║   ██║██║╚════██║   ██║   ██╔══██╗  ╚██╔╝\n *    ██║  ██║███████╗╚██████╔╝██║███████║   ██║   ██║  ██║   ██║\n *    ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝   ╚═╝\n *\n */\npragma solidity 0.5.3;\n// IV is value needed to have a vanity address starting with `0x1820`.\n// IV: 87018\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC1820ImplementerInterface {\n    /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not.\n    /// @param interfaceHash keccak256 hash of the name of the interface\n    /// @param addr Address for which the contract will implement the interface\n    /// @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`.\n    function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC1820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC1820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820\ncontract ERC1820Registry {\n    /// @notice ERC165 Invalid ID.\n    bytes4 constant internal INVALID_ID = 0xffffffff;\n    /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n    bytes4 constant internal ERC165ID = 0x01ffc9a7;\n    /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n    bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC1820_ACCEPT_MAGIC\"));\n\n    /// @notice mapping from addresses and interface hashes to their implementers.\n    mapping(address => mapping(bytes32 => address)) internal interfaces;\n    /// @notice mapping from addresses to their manager.\n    mapping(address => address) internal managers;\n    /// @notice flag for each address and erc165 interface to indicate if it is cached.\n    mapping(address => mapping(bytes4 => bool)) internal erc165Cached;\n\n    /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`.\n    event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n    /// @notice Indicates `newManager` is the address of the new manager for `addr`.\n    event ManagerChanged(address indexed addr, address indexed newManager);\n\n    /// @notice Query if an address implements an interface and through which contract.\n    /// @param _addr Address being queried for the implementer of an interface.\n    /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n    /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n    /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n    /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr.address()`\n    /// or '0' if `_addr.address()` did not register an implementer for this interface.\n    function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n        address addr = _addr == address(0) ? msg.sender : _addr;\n        if (isERC165Interface(_interfaceHash)) {\n            bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n            return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0);\n        }\n        return interfaces[addr][_interfaceHash];\n    }\n\n    /// @notice Sets the contract which implements a specific interface for an address.\n    /// Only the manager defined for that address can set it.\n    /// (Each address is the manager for itself until it sets a new manager.)\n    /// @param _addr Address for which to set the interface.\n    /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n    /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n    /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n    /// @param _implementer Contract address implementing `_interfaceHash` for `_addr.address()`.\n    function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n        address addr = _addr == address(0) ? msg.sender : _addr;\n        require(getManager(addr) == msg.sender, \"Not the manager\");\n\n        require(!isERC165Interface(_interfaceHash), \"Must not be an ERC165 hash\");\n        if (_implementer != address(0) && _implementer != msg.sender) {\n            require(\n                ERC1820ImplementerInterface(_implementer)\n                    .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC,\n                \"Does not implement the interface\"\n            );\n        }\n        interfaces[addr][_interfaceHash] = _implementer;\n        emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n    }\n\n    /// @notice Sets `_newManager.address()` as manager for `_addr.address()`.\n    /// The new manager will be able to call 'setInterfaceImplementer' for `_addr.address()`.\n    /// @param _addr Address for which to set the new manager.\n    /// @param _newManager Address of the new manager for `addr.address()`.\n    /// (Pass '0x0' to reset the manager to `_addr.address()`.)\n    function setManager(address _addr, address _newManager) external {\n        require(getManager(_addr) == msg.sender, \"Not the manager\");\n        managers[_addr] = _newManager == _addr ? address(0) : _newManager;\n        emit ManagerChanged(_addr, _newManager);\n    }\n\n    /// @notice Get the manager of an address.\n    /// @param _addr Address for which to return the manager.\n    /// @return Address of the manager for a given address.\n    function getManager(address _addr) public view returns(address) {\n        // By default the manager of an address is the same address\n        if (managers[_addr] == address(0)) {\n            return _addr;\n        } else {\n            return managers[_addr];\n        }\n    }\n\n    /// @notice Compute the keccak256 hash of an interface given its name.\n    /// @param _interfaceName Name of the interface.\n    /// @return The keccak256 hash of an interface name.\n    function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) {\n        return keccak256(abi.encodePacked(_interfaceName));\n    }\n\n    /* --- ERC165 Related Functions --- */\n    /* --- Developed in collaboration with William Entriken. --- */\n\n    /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n    /// @param _contract Address of the contract for which to update the cache.\n    /// @param _interfaceId ERC165 interface for which to update the cache.\n    function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n        interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(\n            _contract, _interfaceId) ? _contract : address(0);\n        erc165Cached[_contract][_interfaceId] = true;\n    }\n\n    /// @notice Checks whether a contract implements an ERC165 interface or not.\n    //  If the result is not cached a direct lookup on the contract address is performed.\n    //  If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n    //  'updateERC165Cache' with the contract address.\n    /// @param _contract Address of the contract to check.\n    /// @param _interfaceId ERC165 interface to check.\n    /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise.\n    function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n        if (!erc165Cached[_contract][_interfaceId]) {\n            return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n        }\n        return interfaces[_contract][_interfaceId] == _contract;\n    }\n\n    /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n    /// @param _contract Address of the contract to check.\n    /// @param _interfaceId ERC165 interface to check.\n    /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise.\n    function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n        uint256 success;\n        uint256 result;\n\n        (success, result) = noThrowCall(_contract, ERC165ID);\n        if (success == 0 || result == 0) {\n            return false;\n        }\n\n        (success, result) = noThrowCall(_contract, INVALID_ID);\n        if (success == 0 || result != 0) {\n            return false;\n        }\n\n        (success, result) = noThrowCall(_contract, _interfaceId);\n        if (success == 1 && result == 1) {\n            return true;\n        }\n        return false;\n    }\n\n    /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n    /// @param _interfaceHash The hash to check.\n    /// @return True if `_interfaceHash` is an ERC165 interface (ending with 28 zeroes), false otherwise.\n    function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n        return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n    }\n\n    /// @dev Make a call on a contract without throwing if the function does not exist.\n    function noThrowCall(address _contract, bytes4 _interfaceId)\n        internal view returns (uint256 success, uint256 result)\n    {\n        bytes4 erc165ID = ERC165ID;\n\n        assembly {\n            let x := mload(0x40)               // Find empty storage location using \"free memory pointer\"\n            mstore(x, erc165ID)                // Place signature at beginning of empty storage\n            mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n            success := staticcall(\n                30000,                         // 30k gas\n                _contract,                     // To addr\n                x,                             // Inputs are stored at location x\n                0x24,                          // Inputs are 36 (4 + 32) bytes long\n                x,                             // Store output over input (saves space)\n                0x20                           // Outputs are 32 bytes long\n            )\n\n            result := mload(x)                 // Load the result\n        }\n    }\n}\n",
    +            "keccak256": "0xdb01f4b0c42ecb3a60f096b0a082411875fbbd78e87d88868975ad9d983c030d"
    +          }
    +        },
    +        "version": 1
    +      }
    +
    +
    + +### Interface Name + +Any interface name is hashed using `keccak256` and sent to `getInterfaceImplementer()`. + +If the interface is part of a standard, it is best practice to explicitly state the interface name and link to this published [ERC1820] such that other people don't have to come here to look up these rules. + +For convenience, the registry provides a function to compute the hash on-chain: + +``` solidity +function interfaceHash(string _interfaceName) public pure returns(bytes32) +``` + +Compute the keccak256 hash of an interface given its name. + +> **identifier:** `65ba36c1` +> **parameters** +> `_interfaceName`: Name of the interface. +> **returns:** The `keccak256` hash of an interface name. + +#### **Approved ERCs** + +If the interface is part of an approved ERC, it MUST be named `ERC###XXXXX` where `###` is the number of the ERC and XXXXX should be the name of the interface in CamelCase. +The meaning of this interface SHOULD be defined in the specified ERC. + +Examples: + +- `keccak256("ERC20Token")` +- `keccak256("ERC777Token")` +- `keccak256("ERC777TokensSender")` +- `keccak256("ERC777TokensRecipient")` + +#### **[ERC165] Compatible Interfaces** + +> The compatibility with [ERC165], including the [ERC165 Cache], has been designed and developed with [William Entriken]. + +Any interface where the last 28 bytes are zeroes (`0`) SHALL be considered an [ERC165] interface. + +**[ERC165] Lookup** + +Anyone can explicitly check if a contract implements an [ERC165] interface using the registry by calling one of the two functions below: + +``` solidity +function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) +``` + +Checks whether a contract implements an [ERC165] interface or not. + +If the result is not cached a direct lookup on the contract address is performed. + +*NOTE*: If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling `updateERC165Cache` with the contract address. +(See [ERC165 Cache] for more details.) + +> **identifier:** `f712f3e8` +> **parameters** +> `_contract`: Address of the contract to check. +> `_interfaceId`: [ERC165] interface to check. +> **returns:** `true` if `_contract` implements `_interfaceId`, `false` otherwise. + +``` solidity +function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) +``` + +Checks whether a contract implements an [ERC165] interface or not without using nor updating the cache. + +> **identifier:** `b7056765` +> **parameters** +> `_contract`: Address of the contract to check. +> `_interfaceId`: [ERC165] interface to check. +> **returns:** `true` if `_contract` implements `_interfaceId`, false otherwise. + +**[ERC165] Cache** + +Whether a contract implements an [ERC165] interface or not can be cached manually to save gas. + +If a contract dynamically changes its interface and relies on the [ERC165] cache of the [ERC1820] registry, the cache MUST be updated manually---there is no automatic cache invalidation or cache update. +Ideally the contract SHOULD automatically update the cache when changing its interface. +However anyone MAY update the cache on the contract's behalf. + +The cache update MUST be done using the `updateERC165Cache` function: + +``` solidity +function updateERC165Cache(address _contract, bytes4 _interfaceId) external +``` + +> **identifier:** `a41e7d51` +> **parameters** +> `_contract`: Address of the contract for which to update the cache. +> `_interfaceId`: [ERC165] interface for which to update the cache. + +#### **Private User-defined Interfaces** + +This scheme is extensible. +You MAY make up your own interface name and raise awareness to get other people to implement it and then check for those implementations. +Have fun but please, you MUST not conflict with the reserved designations above. + +### Set An Interface For An Address + +For any address to set a contract as the interface implementation, it must call the following function of the [ERC1820] registry: + +``` solidity +function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external +``` + +Sets the contract which implements a specific interface for an address. + +Only the `manager` defined for that address can set it. +(Each address is the manager for itself, see the [manager] section for more details.) + +*NOTE*: If `_addr` and `_implementer` are two different addresses, then: + +- The `_implementer` MUST implement the `ERC1820ImplementerInterface` (detailed below). +- Calling `canImplementInterfaceForAddress` on `_implementer` with the given `_addr` and `_interfaceHash` MUST return the `ERC1820_ACCEPT_MAGIC` value. + +*NOTE*: The `_interfaceHash` MUST NOT be an [ERC165] interface---it MUST NOT end with 28 zeroes (`0`). + +*NOTE*: The `_addr` MAY be `0`, then `msg.sender` is assumed. +This default value simplifies interactions via multisigs where the data of the transaction to sign is constant regardless of the address of the multisig instance. + +> **identifier:** `29965a1d` +> **parameters** +> `_addr`: Address for which to set the interface. (If `_addr` is the zero address then `msg.sender` is assumed.) +> `_interfaceHash`: Keccak256 hash of the name of the interface as a string, for example `web3.utils.keccak256('ERC777TokensRecipient')` for the ERC777TokensRecipient interface. +> `_implementer`: Contract implementing `_interfaceHash` for `_addr`. + +### Get An Implementation Of An Interface For An Address + +Anyone MAY query the [ERC1820] Registry to obtain the address of a contract implementing an interface on behalf of some address using the `getInterfaceImplementer` function. + +``` solidity +function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) +``` + +Query if an address implements an interface and through which contract. + +*NOTE*: If the last 28 bytes of the `_interfaceHash` are zeroes (`0`), then the first 4 bytes are considered an [ERC165] interface and the registry SHALL forward the call to the contract at `_addr` to see if it implements the [ERC165] interface (the first 4 bytes of `_interfaceHash`). +The registry SHALL also cache [ERC165] queries to reduce gas consumption. Anyone MAY call the `erc165UpdateCache` function to update whether a contract implements an interface or not. + +*NOTE*: The `_addr` MAY be `0`, then `msg.sender` is assumed. +This default value is consistent with the behavior of the `setInterfaceImplementer` function and simplifies interactions via multisigs where the data of the transaction to sign is constant regardless of the address of the multisig instance. + +> **identifier:** `aabbb8ca` +> **parameters** +> `_addr`: Address being queried for the implementer of an interface. (If `_addr` is the zero address then `msg.sender` is assumed.) +> `_interfaceHash`: keccak256 hash of the name of the interface as a string. E.g. `web3.utils.keccak256('ERC777Token')` +> **returns:** The address of the contract which implements the interface `_interfaceHash` for `_addr` or `0` if `_addr` did not register an implementer for this interface. + + +### Interface Implementation (`ERC1820ImplementerInterface`) + +``` solidity +interface ERC1820ImplementerInterface { + /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not. + /// @param interfaceHash keccak256 hash of the name of the interface + /// @param addr Address for which the contract will implement the interface + /// @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`. + function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); +} +``` + +Any contract being registered as the implementation of an interface for a given address MUST implement said interface. +In addition if it implements an interface on behalf of a different address, the contract MUST implement the `ERC1820ImplementerInterface` shown above. + +``` solidity +function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32) +``` + +Indicates whether a contract implements an interface (`interfaceHash`) for a given address (`addr`). + +If a contract implements the interface (`interfaceHash`) for a given address (`addr`), it MUST return `ERC1820_ACCEPT_MAGIC` when called with the `addr` and the `interfaceHash`. +If it does not implement the `interfaceHash` for a given address (`addr`), it MUST NOT return `ERC1820_ACCEPT_MAGIC`. + +> **identifier:** `f0083250` +> **parameters** +> `interfaceHash`: Hash of the interface which is implemented +> `addr`: Address for which the interface is implemented +> **returns:** `ERC1820_ACCEPT_MAGIC` only if the contract implements `ìnterfaceHash` for the address `addr`. + +The special value `ERC1820_ACCEPT_MAGIC` is defined as the `keccka256` hash of the string `"ERC1820_ACCEPT_MAGIC"`. + +``` solidity +bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked("ERC1820_ACCEPT_MAGIC")); +``` + +> The reason to return `ERC1820_ACCEPT_MAGIC` instead of a boolean is to prevent cases where a contract fails to implement the `canImplementInterfaceForAddress` but implements a fallback function which does not throw. In this case, since `canImplementInterfaceForAddress` does not exist, the fallback function is called instead, executed without throwing and returns `1`. Thus making it appear as if `canImplementInterfaceForAddress` returned `true`. + +### Manager + +The manager of an address (regular account or a contract) is the only entity allowed to register implementations of interfaces for the address. +By default, any address is its own manager. + +The manager can transfer its role to another address by calling `setManager` on the registry contract with the address for which to transfer the manager and the address of the new manager. + +**`setManager` Function** + +``` solidity +function setManager(address _addr, address _newManager) external +``` + +Sets `_newManager` as manager for `_addr`. + +The new manager will be able to call `setInterfaceImplementer` for `_addr`. + +If `_newManager` is `0x0`, the manager is reset to `_addr` itself as the manager. + +> **identifier:** `5df8122f` +> **parameters** +> `_addr`: Address for which to set the new manager. +> `_newManager`: The address of the new manager for `_addr`. (Pass `0x0` to reset the manager to `_addr`.) + +**`getManager` Function** + +``` solidity +function getManager(address _addr) public view returns(address) +``` + +Get the manager of an address. + +> **identifier:** `3d584063` +> **parameters** +> `_addr`: Address for which to return the manager. +> **returns:** Address of the manager for a given address. + +## Rationale + +This standards offers a way for any type of address (externally owned and contracts) to implement an interface and potentially delegate the implementation of the interface to a proxy contract. +This delegation to a proxy contract is necessary for externally owned accounts and useful to avoid redeploying existing contracts such as multisigs and DAOs. + +The registry can also act as a [ERC165] cache in order to save gas when looking up if a contract implements a specific [ERC165] interface. +This cache is intentionally kept simple, without automatic cache update or invalidation. +Anyone can easily and safely update the cache for any interface and any contract by calling the `updateERC165Cache` function. + +The registry is deployed using a keyless deployment method relying on a single-use deployment address to ensure no one controls the registry, thereby ensuring trust. + +## Backward Compatibility + +This standard is backward compatible with [ERC165], as both methods MAY be implemented without conflicting with each other. + +## Test Cases + +Please check the [0xjac/ERC1820] repository for the full test suite. + +## Implementation + +The implementation is available in the repo: [0xjac/ERC1820]. + +## Copyright +Copyright and related rights waived via [CC0]. + +[EIP155]: https://eips.ethereum.org/EIPS/eip-155 +[ERC165]: https://eips.ethereum.org/EIPS/eip-165 +[ERC672]: https://github.com/ethereum/EIPs/issues/672 +[ERC820]: https://eips.ethereum.org/EIPS/eip-820 +[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[ERC1820 registry smart contract]: https://github.com/0xjac/ERC1820/blob/master/contracts/ERC1820Registry.sol +[erc1820-annoucement]: https://github.com/ethereum/EIPs/issues/820#issuecomment-464109166 +[erc820-bug]: https://github.com/ethereum/EIPs/issues/820#issuecomment-452465748 +[erc820-fix]: https://github.com/ethereum/EIPs/issues/820#issuecomment-454021564 +[manager]: #manager +[lookup]: #get-an-implementation-of-an-interface-for-an-address +[ERC165 Cache]: #erc165-cache +[Nick's article]: https://medium.com/@weka/how-to-send-ether-to-11-440-people-187e332566b7 +[0xjac/ERC1820]: https://github.com/0xjac/ERC1820 +[CC0]: https://creativecommons.org/publicdomain/zero/1.0/ +[Nick]: https://github.com/Arachnid/ +[William Entriken]: https://github.com/fulldecent +[ENS]: https://ens.domains/ From 1ad5a1636ff9d009c9327bddce26005f1675f3ef Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Fri, 8 Mar 2019 12:54:37 +0100 Subject: [PATCH 076/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 256fb981..1c55a63f 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -7,7 +7,7 @@ status: Draft type: Standards Track category: ERC created: 2017-11-20 -requires: 820 +requires: 1820 --- ## Simple Summary @@ -20,7 +20,7 @@ This standard defines a new way to interact with a token contract while remainin It defines advanced features to interact with tokens. Namely, *operators* to send tokens on behalf of another address—contract or regular account—and send/receive *hooks* to offer token holders more control over their tokens. -It takes advantage of [ERC820] to find out whether and where to notify contracts and regular addresses when they receive tokens as well as to allow compatibility with already-deployed contracts. +It takes advantage of [ERC1820] to find out whether and where to notify contracts and regular addresses when they receive tokens as well as to allow compatibility with already-deployed contracts. ## Motivation @@ -73,7 +73,7 @@ interface ERC777Token { ``` The token contract MUST implement the above interface. The implementation MUST follow the specifications described below. -The token contract MUST register the `ERC777Token` interface with its own address via [ERC820]. If the contract has a switch to enable or disable [ERC777] functions, every time the switch is triggered, the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via [ERC820]. (Unregistering implies setting the address to `0x0`.) +The token contract MUST register the `ERC777Token` interface with its own address via [ERC1820]. If the contract has a switch to enable or disable [ERC777] functions, every time the switch is triggered, the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via [ERC1820]. (Unregistering implies setting the address to `0x0`.) The smallest unit—for all interactions with the token contract—MUST be `1`. I.e. all amounts and balances MUST be unsigned integers. The display denomination—to display any amount to the end user—MUST be 1018 of the smallest. @@ -292,8 +292,8 @@ When an *operator* sends an `amount` of tokens from a *token holder* to a *recip - The balance of the *token holder* MUST be greater or equal to the `amount`—such that its resulting balance is greater or equal to zero (`0`) after the send. - The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent]. - The *operator* MAY include information in the `operatorData`. -- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820]. -- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820]. +- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. +- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. - The `data` and `operatorData` MUST be immutable during the entire send process—hence the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event. The token contract MUST `revert` when sending in any of the following cases: @@ -401,14 +401,14 @@ Nonetheless, the rules below MUST be respected when minting for a *recipient*: - The balance of `0x0` MUST NOT be decreased. - The balance of the *recipient* MUST be increased by the amount of tokens minted. - The token contract MUST emit a `Minted` event with the correct values as defined in the [`Minted` Event][minted]. -- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC820]. +- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. - The `data` and `operatorData` MUST be immutable during the entire mint process—hence the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. - The `data` field MUST be empty. The token contract MUST `revert` when minting in any of the following cases: - The resulting *recipient* balance after the mint is not a multiple of the *granularity* defined by the token contract. -- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC820]. +- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. - The address of the *recipient* is `0x0`. @@ -459,7 +459,7 @@ The rules below MUST be respected when burning the tokens of a *token holder*: - The balance of `0x0` MUST NOT be increased. - The balance of the *token holder* MUST be decreased by amount of tokens burned. - The token contract MUST emit a `Burned` event with the correct values as defined in the [`Burned` Event][burned]. -- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC820]. +- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. - The `operatorData` MUST be immutable during the entire burn process—hence the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. The token contract MUST `revert` when burning in any of the following cases: @@ -546,7 +546,7 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the #### **`ERC777TokensSender` And The `tokensToSend` Hook** -The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC820]. +The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. ``` solidity interface ERC777TokensSender { @@ -603,7 +603,7 @@ This hook takes precedence over [ERC20] and MUST be called (if registered) when #### **`ERC777TokensRecipient` And The `tokensReceived` Hook** -The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*. Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC820]. +The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*. Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. ``` solidity interface ERC777TokensRecipient { @@ -685,7 +685,7 @@ The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] fo This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. It avoids the problems and vulnerabilities of [EIP223]. -It goes a step further by allowing *operators* (generally contracts) which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. Finally, it adds hooks to provide further control to *token holders* over their tokens. Note that, the usage of [ERC820] provides backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks. +It goes a step further by allowing *operators* (generally contracts) which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. Finally, it adds hooks to provide further control to *token holders* over their tokens. Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks. ## Backward Compatibility @@ -701,16 +701,16 @@ Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. The state-modifying functions from both standards are decoupled and can operate independently from each other. Note that [ERC20] functions SHOULD be limited to only being called from old contracts. -If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC820]. If the contract has a switch to enable or disable [ERC20] functions, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC20Token` interface via [ERC820]. (Unregistering implies setting the address to `0x0`.) +If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC1820]. If the contract has a switch to enable or disable [ERC20] functions, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC20Token` interface via [ERC1820]. (Unregistering implies setting the address to `0x0`.) -The difference for new contracts implementing [ERC20] is that `tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC820] if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. If any hook is implemented, it MUST be called. Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. +The difference for new contracts implementing [ERC20] is that `tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC1820] if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. If any hook is implemented, it MUST be called. Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. The table below summarizes the different actions the token contract MUST take when sending, minting and transferring token via [ERC777] and [ERC20]: - + @@ -743,17 +743,17 @@ The table below summarizes the different actions the token contract MUST take wh There is no particular action to take if `tokensToSend` is not implemented. The transfer MUST proceed and only be canceled if another condition is not respected such as lack of funds or a `revert` in `tokensReceived` (if present). -During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC820], the token contract SHOULD emit a `Transfer` event for minting and burning and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard). During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted. +During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC1820], the token contract SHOULD emit a `Transfer` event for minting and burning and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard). During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted. Hence for any movement of tokens, two events MAY be emitted: an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burned` (depending on the type of movement). Third-party developers MUST be careful not to consider both events as separate movements. As a general rule, if an application considers the token as an ERC20 token, then only the `Transfer` event MUST be taken into account. If the application considers the token as an ERC777 token, then only the `Sent`, `Minted` and `Burned` events MUST be considered. ## Test Cases -The [repository with the reference implementation][jacquesd/ERC777] contains all the [tests][ref tests]. +The [repository with the reference implementation][0xjac/ERC777] contains all the [tests][ref tests]. ## Implementation -The GitHub repository [jacquesd/ERC777] contains the [reference implementation]. The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. +The GitHub repository [0xjac/ERC777] contains the [reference implementation]. The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. ## Copyright @@ -765,11 +765,11 @@ Copyright and related rights waived via [CC0]. [ERC20]: https://eips.ethereum.org/EIPS/eip-20 [ERC777]: https://eips.ethereum.org/EIPS/eip-777 -[ERC820]: https://eips.ethereum.org/EIPS/eip-820 -[jacquesd/ERC777]: https://github.com/jacquesd/ERC777 +[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[0xjac/ERC777]: https://github.com/0xjac/ERC777 [npm/erc777]: https://www.npmjs.com/package/erc777 -[ref tests]: https://github.com/jacquesd/ERC777/blob/master/test/ReferenceToken.test.js -[reference implementation]: https://github.com/jacquesd/ERC777/blob/master/contracts/examples/ReferenceToken.sol +[ref tests]: https://github.com/0xjac/ERC777/blob/master/test/ReferenceToken.test.js +[reference implementation]: https://github.com/0xjac/ERC777/blob/master/contracts/examples/ReferenceToken.sol [EIP223]: https://github.com/ethereum/EIPs/issues/223 [eth_estimateGas]: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas From 4854972ae5adb029e9e2ef503729e4f6882a3d33 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 8 Mar 2019 06:57:40 -0500 Subject: [PATCH 077/431] Correct URLs to preferred citation format (#1808) --- EIPS/eip-721.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/EIPS/eip-721.md b/EIPS/eip-721.md index 7a344681..721b6fc7 100644 --- a/EIPS/eip-721.md +++ b/EIPS/eip-721.md @@ -43,7 +43,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S pragma solidity ^0.4.20; /// @title ERC-721 Non-Fungible Token Standard -/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md +/// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x80ac58cd. interface ERC721 /* is ERC165 */ { /// @dev This emits when ownership of any NFT changes by any mechanism. @@ -176,7 +176,7 @@ The **metadata extension** is OPTIONAL for ERC-721 smart contracts (see "caveats ```solidity /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension -/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md +/// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x5b5e139f. interface ERC721Metadata /* is ERC721 */ { /// @notice A descriptive name for a collection of NFTs in this contract @@ -220,7 +220,7 @@ The **enumeration extension** is OPTIONAL for ERC-721 smart contracts (see "cave ```solidity /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension -/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md +/// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x780e9d63. interface ERC721Enumerable /* is ERC721 */ { /// @notice Count NFTs tracked by this contract @@ -390,12 +390,12 @@ XXXXERC721, by William Entriken -- a scalable example implementation **Standards** -1. ERC-20 Token Standard. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md -1. ERC-165 Standard Interface Detection. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md -1. ERC-173 Owned Standard. https://github.com/ethereum/EIPs/issues/173 -1. ERC-223 Token Standard. https://github.com/ethereum/EIPs/issues/223 -1. ERC-677 `transferAndCall` Token Standard. https://github.com/ethereum/EIPs/issues/677 -1. ERC-827 Token Standard. https://github.com/ethereum/EIPs/issues/827 +1. ERC-20 Token Standard. https://eips.ethereum.org/EIPS/eip-20 +1. ERC-165 Standard Interface Detection. https://eips.ethereum.org/EIPS/eip-165 +1. ERC-173 Owned Standard. https://eips.ethereum.org/EIPS/eip-173 +1. ERC-223 Token Standard. https://eips.ethereum.org/EIPS/eip-223 +1. ERC-677 `transferAndCall` Token Standard. https://eips.ethereum.org/EIPS/eip-677 +1. ERC-827 Token Standard. https://eips.ethereum.org/EIPS/eip-827 1. Ethereum Name Service (ENS). https://ens.domains 1. Instagram -- What's the Image Resolution? https://help.instagram.com/1631821640426723 1. JSON Schema. http://json-schema.org/ From 97ff23130895afe633c444390e4b4258c8faf6e1 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 8 Mar 2019 06:59:02 -0500 Subject: [PATCH 078/431] Add EIP-211 to metadata (#1720) --- EIPS/eip-1167.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1167.md b/EIPS/eip-1167.md index e0b39ad6..4b35d046 100644 --- a/EIPS/eip-1167.md +++ b/EIPS/eip-1167.md @@ -7,6 +7,7 @@ status: Final type: Standards Track category: ERC created: 2018-06-22 +requires: 211 --- From f98a60e1b1590c9cfa0bfe66c4e6a674e54cd386 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 8 Mar 2019 07:06:02 -0500 Subject: [PATCH 079/431] Fix language for transfer function (#1744) --- EIPS/eip-20.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-20.md b/EIPS/eip-20.md index 40d59315..a84396df 100644 --- a/EIPS/eip-20.md +++ b/EIPS/eip-20.md @@ -95,7 +95,7 @@ function balanceOf(address _owner) public view returns (uint256 balance) #### transfer Transfers `_value` amount of tokens to address `_to`, and MUST fire the `Transfer` event. -The function SHOULD `throw` if the `_from` account balance does not have enough tokens to spend. +The function SHOULD `throw` if the message caller's account balance does not have enough tokens to spend. *Note* Transfers of 0 values MUST be treated as normal transfers and fire the `Transfer` event. From 4b4b7123bd4cd23456de2fadb00e5a2dc446aabd Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 8 Mar 2019 13:16:22 +0100 Subject: [PATCH 080/431] Introduce "updated" date header in EIP-1 (#1697) --- EIPS/eip-1.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index e9b08abe..13c94669 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -5,7 +5,8 @@ status: Active type: Meta author: Martin Becze , Hudson Jameson , and others https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1.md -created: 2015-10-27, 2017-02-01 +created: 2015-10-27 +updated: 2015-12-07, 2016-02-01, 2018-03-21, 2018-05-29, 2018-10-17 --- ## What is an EIP? @@ -112,6 +113,8 @@ Each EIP must begin with an RFC 822 style header preamble, preceded and followed ` created:` +` * updated:` + ` * requires:` ` * replaces:` @@ -164,6 +167,10 @@ The `category` header specifies the EIP's category. This is required for standar The `created` header records the date that the EIP was assigned a number. Both headers should be in yyyy-mm-dd format, e.g. 2001-08-14. +#### `updated` header + +The `updated` header records the date(s) when the EIP was updated with "substantional" changes. This header is only valid for EIPs of Draft and Active status. + #### `requires` header EIPs may have a `requires` header, indicating the EIP numbers that this EIP depends on. @@ -224,7 +231,7 @@ The editors don't pass judgment on EIPs. We merely do the administrative & edito This document was derived heavily 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 Ethereum Improvement Process, and should not be bothered with technical questions specific to Ethereum or the EIP. Please direct all comments to the EIP editors. -December 7, 2016: EIP 1 has been improved and will be placed as a PR. +December 7, 2015: EIP 1 has been improved and will be placed as a PR. February 1, 2016: EIP 1 has added editors, made draft improvements to process, and has merged with Master stream. @@ -232,6 +239,8 @@ March 21, 2018: Minor edits to accommodate the new automatically-generated EIP d May 29, 2018: A last call process was added. +Oct 17, 2018: The `updated` header was introduced. + See [the revision history for further details](https://github.com/ethereum/EIPs/commits/master/EIPS/eip-1.md), which is also available by clicking on the History button in the top right of the EIP. ### Bibliography From 7609231801c72bd5ed2bac5ac1ae32a6377661d0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 8 Mar 2019 14:15:43 +0100 Subject: [PATCH 081/431] Unlimited SWAP and DUP instructions (#663) --- EIPS/eip-663.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 EIPS/eip-663.md diff --git a/EIPS/eip-663.md b/EIPS/eip-663.md new file mode 100644 index 00000000..47786a1d --- /dev/null +++ b/EIPS/eip-663.md @@ -0,0 +1,56 @@ +--- +eip: 663 +title: Unlimited SWAP and DUP instructions +author: Alex Beregszaszi (@axic) +type: Standards Track +category: Core +status: Draft +created: 2017-07-03 +--- + +## Abstract + +`SWAP` and `DUP` instructions are limited to a stack depth of 16. Introduce two new instructions, `SWAPn` and `DUPn`, which lift this limitation and allow accessing the stack up to its full depth of 1024 items. + +## Motivation + +Implementing higher level constructs, such as functions, on top of EVM will result in a list of input and output parameters as well as an instruction offset to return to. + +The number of these arguments (or stack items) can easily exceed 16 and thus will require extra care from a compiler to lay them out in a way that all of them are still accessible. + +Introducing `SWAPn` and `DUPn` will provide an option to compilers to simplify accessing deep stack items at the price of possibly increased gas costs. + +## Specification + +Instructions `DUPn` (`0xb0`) and `SWAPn` (`0xb1`) are introduced, which take the top item from stack (referred to as `n`). + +If `n` exceeds 1024 or the current stack depth is less than `n`, then a stack underflow exception is issued. If the current stack depth is at the limit, a stack overflow exception is issued. + +Otherwise +- for `DUPn` the stack item at depth `n` is duplicated at the top of the stack +- for `SWAPn` the top stack item is swapped with the item at depth `n` + +The gas cost for both instructions is set at 3. In reality the cost for such an operation is 6 including the required `PUSH`. + +Since both of these instructions require the top stack item to contain the position, it is still only possible to reach more than 16 stack items if there is at least one free stack slot. + +## Rationale + +TBA + +## Backwards Compatibility + +This has no effect on backwards compatibility. + +## Test Cases + +- executing `602a600160026003600460056006600760086009600a600b600c600d600e600f60106011b0` should have `42` as the top stack item +- executing `602a600160026003600460056006600760086009600a600b600c600d600e600f60106011b1` should have `42` as the top stack item + +## Implementation + +TBA + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 31dafbec2030d711a4fc6e4d9d272215f71bf96e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 8 Mar 2019 14:32:37 +0100 Subject: [PATCH 082/431] Add ethereum.org blog post about petersburg (#1794) --- EIPS/eip-1716.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1716.md b/EIPS/eip-1716.md index a0d0d10b..adda1b4e 100644 --- a/EIPS/eip-1716.md +++ b/EIPS/eip-1716.md @@ -31,7 +31,8 @@ If `Petersburg` is defined with an earlier block number than `Constantinople`, t ## References -The list above includes the EIPs that had to be removed from Constantinople due to a [potential reentrancy attack vector](https://medium.com/chainsecurity/constantinople-enables-new-reentrancy-attack-ace4088297d9). Removing this was agreed upon at the [All-Core-Devs call #53 in January 2019](https://github.com/ethereum/pm/issues/70). +1. The list above includes the EIPs that had to be removed from Constantinople due to a [potential reentrancy attack vector](https://medium.com/chainsecurity/constantinople-enables-new-reentrancy-attack-ace4088297d9). Removing this was agreed upon at the [All-Core-Devs call #53 in January 2019](https://github.com/ethereum/pm/issues/70). +2. https://blog.ethereum.org/2019/02/22/ethereum-constantinople-st-petersburg-upgrade-announcement/ ## Copyright From a8ac72dda50b23cdb0434ad462e52acf7c61c25f Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Fri, 8 Mar 2019 13:34:09 +0000 Subject: [PATCH 083/431] Update Solidity syntax in EIP-191 specs (#1547) --- EIPS/eip-191.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/EIPS/eip-191.md b/EIPS/eip-191.md index 63b53ea5..f3b79ae5 100644 --- a/EIPS/eip-191.md +++ b/EIPS/eip-191.md @@ -59,19 +59,23 @@ Using `0x19` thus makes it possible to extend the scheme by defining a version ` ### Example - function submitTransactionPreSigned(address destination, uint value, bytes data, uint nonce, uint8 v, bytes32 r, bytes32 s) - public - returns (bytes32 transactionHash) - { - // Arguments when calculating hash to validate - // 1: byte(0x19) - the initial 0x19 byte - // 2: byte(0) - the version byte - // 3: this - the validator address - // 4-7 : Application specific data - transactionHash = keccak256(byte(0x19),byte(0),this,destination, value, data, nonce); - sender = ecrecover(transactionHash, v, r, s); - // ... - } +The following snippet has been written in Solidity 0.5.0. + +```solidity +function submitTransactionPreSigned(address destination, uint value, bytes data, uint nonce, uint8 v, bytes32 r, bytes32 s) + public + returns (bytes32 transactionHash) +{ + // Arguments when calculating hash to validate + // 1: byte(0x19) - the initial 0x19 byte + // 2: byte(0) - the version byte + // 3: this - the validator address + // 4-7 : Application specific data + transactionHash = keccak256(abi.encodePacked(byte(0x19),byte(0),address(this),destination, value, data, nonce)); + sender = ecrecover(transactionHash, v, r, s); + // ... +} +``` ## Copyright From 5d66e479345ea5e4547613326a41d3952496a719 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 8 Mar 2019 14:35:08 +0100 Subject: [PATCH 084/431] Fix typo in EIP 1283 (#1678) --- EIPS/eip-1283.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1283.md b/EIPS/eip-1283.md index da763300..7361bdd8 100644 --- a/EIPS/eip-1283.md +++ b/EIPS/eip-1283.md @@ -155,7 +155,7 @@ When *original value* is not 0: ## Rationale -This EIP mostly archives what a transient storage tries to do +This EIP mostly achieves what a transient storage tries to do (EIP-1087 and EIP-1153), but without the complexity of introducing the concept of "dirty maps", or an extra storage struct. From 6b75cfa150292fb219f8a3866b2581f2f4882030 Mon Sep 17 00:00:00 2001 From: Trustfarm-heart Date: Fri, 8 Mar 2019 23:38:05 +0900 Subject: [PATCH 085/431] EIP-1485 TethashV1, Obsolete ETH-Asic Machine (#1545) --- EIPS/eip-1485.md | 200 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 EIPS/eip-1485.md diff --git a/EIPS/eip-1485.md b/EIPS/eip-1485.md new file mode 100644 index 00000000..716455ca --- /dev/null +++ b/EIPS/eip-1485.md @@ -0,0 +1,200 @@ +--- +eip: 1485 +title: TEthashV1 +author: trustfarm (KT Ahn - 안씨아저씨) , , +discussions-to: https://ethereum-magicians.org/t/anti-eth-asic-mining-eip-1488-pr/1807 +status: Draft +type: Standards Track +category: Core +created: 2018-11-01 +--- + +## Simple Summary +This EIP modifies ethash in order to break ASIC miners specialized for the current ethash mining algorithm. + +## Abstract +This EIP pursue "obsolete current ASIC miners" by modifying PoW algorithm in a very low risk manner and update to latest hash algorithm from deprecated FNV Hash algorithms. + +Following TEthashV1 algorithm suggests safe transition of PoW algorithms and secure the FNV Algorithm in MIX Parts. + +## Motivation +Provide original Ethash proof of work verification with minimal set of changes by updating FNV0 algorithm + +## Specification + +#### 1. Reference materials on ETHASH FNV0 + +#### Where FNV Applied on ETHASH + +- In [ETHASH](https://github.com/ethereum/wiki/wiki/Ethash) , FNV Hash is used on + * 1) On data aggregation function, MIX parts. + + * Ethash Algorithm + + ``` + Header + Nonce + | + Keccak + | + **[MIX 0]** --> **[DAG Page]** + | | + Mixing <--| + ... + | + **[Mix 63]** + | + |-----> Mix64 [Process] ---> Mix Digest [32B] + ``` + + * FNV used in DAG Generation + and Mixing for random access or DAG Page. + +#### 2. Current applied Ethash FNV hash implementation is deprecated now. + +[FNV-0_hash (deprecated)](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-0_hash_(deprecated)) + + It is a simple way of hashing algorithm + + ``` + hash = 0 + for each byte_of_data to be hashed + hash = hash × FNV_prime + hash = hash XOR octet_of_data + return hash + ``` + + When analysed FNV-0 , there's very weak [avalanche effect](https://simple.wikipedia.org/wiki/Avalanche_effect), when hash input changes on 1~2bits. refer [FNV-Analysis reference section](https://github.com/tao-foundation/FNV-Analysis#how-to-test-and-analysis-reference-test-code) + + We need to research and apply newer FNV hash or short message hash algorithm. + +#### 3. FNV1A hash algorithm description + +Previous proposed algorithm based on FNV1 [EIP-1355](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1355.md) + +There's a implementation that looks like "Missing Offset Bias" at **FNV1A**. + +Quotation of [original algorithm FNV1A](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash) +``` +use hash offset +FNV-1a hash +The FNV-1a hash differs from the FNV-1 hash by only the order in which the multiply and XOR is performed:[8][10] + + hash = FNV_offset_basis + for each byte_of_data to be hashed + hash = hash XOR byte_of_data + hash = hash × FNV_prime + return hash +``` + +FNV_offset_basis and computation order change of xor and multiplication Makes one more xor and multiply computation, but more secure hash effects than FNV0. +and make dispersion boundary condition (0, even number, ..) by using of Prime Number. + +#### 4. Real Implementation for FNV1A + +Consider real computation resources, in TEthashV1 uses hash byte_of_data to 4bytes aligned data. + +In TETHashV1, Adapts fully follow the FNV1A implementation. + + - TETHASHV1 FNV1A implementation + +Followings are reference implementation of FNV1A adapted in TETHashV1. + +```cpp +// Reference Pseudo c/cpp implementation + +#define FNV_PRIME 0x01000193U +#define FNV_OFFSET_BASIS 0x811c9dc5U + +#define fnv1a(x, y) ((((FNV_OFFSET_BASIS^(x))*FNV_PRIME) ^ (y)) * FNV_PRIME) +#define fnv1a_reduce(a,b,c,d) (fnv1a(fnv1a(fnv1a(a, b), c), d)) +``` + +Another Byte aligned implementation of FNV1A , call to FNV1c + +```cpp +#define FNV_PRIME 0x01000193U +#define FNV_OFFSET_BASIS 0x811c9dc5U + +#define fnv1i(x) ( (( (( (( \ + ( ((FNV_OFFSET_BASIS)^( ((x)>>24)&0x000000ff )) * FNV_PRIME) \ + ^ (((x)>>16 )&0x000000ff)) * FNV_PRIME) \ + ^ (((x)>>8 )&0x000000ff)) * FNV_PRIME) \ + ^ (((x) )&0x000000ff)) * FNV_PRIME) \ + ) +#define fnv1c(x, y) ((fnv1i(x) ^ (y)) * FNV_PRIME) +``` + +#### 5. [FNV-Analysis](https://github.com/tao-foundation/FNV-Analysis) +FNV Mix Algorithm Analysis for TEthashV1 + +#### How to test and analysis reference test code. + +You can compile it with simple in terminal. +No additional library needs, + +``` +gcc -o fnvtest fnvcltest.c +``` + +And You can execute it +``` +fnvtest + +F(00,00)::VEC(0, 0, ffffffff, 0):: FNV :00000000, DF=00000000(00) DS(00000000), FNV1 :00000000, DF=00000000(00) DS(00000000), FNV1a:117697cd, DF=117697cd(17) DS(117697cd), FNV1c:1210d00f, DF=127f8dbf(20) DS(11a1725f), F___RC=efe1b9c4, DF:efe1b9c4(19) , F1__RC=deb68dfe, DF:deb68dfe(22) , F1A_RC=99bad28b, DF:99bad28b(17) , F1C_RC=e29fa497, DF:e29fa497(18) +F(00,01)::VEC(0, 1, ffffffff, 0):: FNV :00000001, DF=00000001(01) DS(00000001), FNV1 :01000193, DF=01000193(06) DS(01000193), FNV1a:1076963a, DF=010001f7(09) DS(01000193), FNV1c:1110ce7c, DF=03001e73(11) DS(01000193), F___RC=fefffe6d, DF:111e47a9(14) , F1__RC=d9fd8597, DF:074b0869(12) , F1A_RC=72c287e0, DF:eb78556b(19) , F1C_RC=6b6991ef, DF:89f63578(17) +F(00,02)::VEC(0, 2, ffffffff, 0):: FNV :00000002, DF=00000003(02) DS(00000001), FNV1 :02000326, DF=030002b5(08) DS(01000193), FNV1a:0f7694a7, DF=1f00029d(11) DS(01000193), FNV1c:1410d335, DF=05001d49(09) DS(030004b9), F___RC=d8fd8404, DF:26027a69(13) , F1__RC=9b16d24c, DF:42eb57db(19) , F1A_RC=c17f0ecb, DF:b3bd892b(18) , F1C_RC=a5be8e78, DF:ced71f97(21) +F(00,03)::VEC(0, 3, ffffffff, 0):: FNV :00000003, DF=00000001(01) DS(00000001), FNV1 :030004b9, DF=0100079f(10) DS(01000193), FNV1a:0e769314, DF=010007b3(09) DS(01000193), FNV1c:1310d1a2, DF=07000297(09) DS(01000193), F___RC=b2fb099b, DF:6a068d9f(16) , F1__RC=5c301f01, DF:c726cd4d(17) , F1A_RC=94cf402e, DF:55b04ee5(16) , F1C_RC=aea1a025, DF:0b1f2e5d(17) +F(00,04)::VEC(0, 4, ffffffff, 0):: FNV :00000004, DF=00000007(03) DS(00000001), FNV1 :0400064c, DF=070002f5(10) DS(01000193), FNV1a:0d769181, DF=03000295(07) DS(01000193), FNV1c:0e10c9c3, DF=1d001861(09) DS(050007df), F___RC=8cf88f32, DF:3e0386a9(14) , F1__RC=1d496bb6, DF:417974b7(17) , F1A_RC=89401d59, DF:1d8f5d77(20) , F1C_RC=e4e96c7c, DF:4a48cc59(13) +F(00,05)::VEC(0, 5, ffffffff, 0):: FNV :00000005, DF=00000001(01) DS(00000001), FNV1 :050007df, DF=01000193(06) DS(01000193), FNV1a:0c768fee, DF=01001e6f(11) DS(01000193), FNV1c:0d10c830, DF=030001f3(09) DS(01000193), F___RC=66f614c9, DF:ea0e9bfb(20) , F1__RC=de62b86b, DF:c32bd3dd(19) , F1A_RC=346e222c, DF:bd2e3f75(21) , F1C_RC=502e5f82, DF:b4c733fe(20) +F(00,06)::VEC(0, 6, ffffffff, 0):: FNV :00000006, DF=00000003(02) DS(00000001), FNV1 :06000972, DF=03000ead(10) DS(01000193), FNV1a:0b768e5b, DF=070001b5(09) DS(01000193), FNV1c:1010cce9, DF=1d0004d9(10) DS(030004b9), F___RC=40f39a60, DF:26058ea9(13) , F1__RC=9f7c0520, DF:411ebd4b(16) , F1A_RC=b376a527, DF:8718870b(13) , F1C_RC=1241a9a4, DF:426ff626(17) +F(00,07)::VEC(0, 7, ffffffff, 0):: FNV :00000007, DF=00000001(01) DS(00000001), FNV1 :07000b05, DF=01000277(08) DS(01000193), FNV1a:0a768cc8, DF=01000293(06) DS(01000193), FNV1c:0f10cb56, DF=1f0007bf(15) DS(01000193), F___RC=1af11ff7, DF:5a028597(13) , F1__RC=609551d5, DF:ffe954f5(22) , F1A_RC=14293bea, DF:a75f9ecd(21) , F1C_RC=49d34bba, DF:5b92e21e(16) +F(00,08)::VEC(0, 8, ffffffff, 0):: FNV :00000008, DF=0000000f(04) DS(00000001), FNV1 :08000c98, DF=0f00079d(12) DS(01000193), FNV1a:09768b35, DF=030007fd(12) DS(01000193), FNV1c:1a10dca7, DF=150017f1(12) DS(0b001151), F___RC=f4eea58e, DF:ee1fba79(21) , F1__RC=21ae9e8a, DF:413bcf5f(19) , F1A_RC=eeebb7a5, DF:fac28c4f(17) , F1C_RC=7da04f47, DF:347304fd(16) +F(00,09)::VEC(0, 9, ffffffff, 0):: FNV :00000009, DF=00000001(01) DS(00000001), FNV1 :09000e2b, DF=010002b3(07) DS(01000193), FNV1a:087689a2, DF=01000297(07) DS(01000193), FNV1c:1910db14, DF=030007b3(10) DS(01000193), F___RC=ceec2b25, DF:3a028eab(14) , F1__RC=e2c7eb3f, DF:c36975b5(18) , F1A_RC=54e1aef8, DF:ba0a195d(15) , F1C_RC=d425e1af, DF:a985aee8(16) +F(00,0a)::VEC(0, a, ffffffff, 0):: FNV :0000000a, DF=00000003(02) DS(00000001), FNV1 :0a000fbe, DF=03000195(07) DS(01000193), FNV1a:0776880f, DF=0f0001ad(10) DS(01000193), FNV1c:1c10dfcd, DF=050004d9(08) DS(030004b9), F___RC=a8e9b0bc, DF:66059b99(15) , F1__RC=a3e137f4, DF:4126dccb(15) , F1A_RC=213fcd63, DF:75de639b(20) , F1C_RC=7e1d2751, DF:aa38c6fe(18) +F(00,0b)::VEC(0, b, ffffffff, 0):: FNV :0000000b, DF=00000001(01) DS(00000001), FNV1 :0b001151, DF=01001eef(12) DS(01000193), FNV1a:0676867c, DF=01000e73(09) DS(01000193), FNV1c:1b10de3a, DF=070001f7(11) DS(01000193), F___RC=82e73653, DF:2a0e86ef(16) , F1__RC=64fa84a9, DF:c71bb35d(19) , F1A_RC=5598ce46, DF:74a70325(14) , F1C_RC=6400c630, DF:1a1de161(14) +F(00,0c)::VEC(0, c, ffffffff, 0):: FNV :0000000c, DF=00000007(03) DS(00000001), FNV1 :0c0012e4, DF=070003b5(10) DS(01000193), FNV1a:057684e9, DF=03000295(07) DS(01000193), FNV1c:1610d65b, DF=0d000861(07) DS(050007df), F___RC=5ce4bbea, DF:de038db9(17) , F1__RC=2613d15e, DF:42e955f7(18) , F1A_RC=6a220ff1, DF:3fbac1b7(20) , F1C_RC=6e781da4, DF:0a78db94(15) +F(00,0d)::VEC(0, d, ffffffff, 0):: FNV :0000000d, DF=00000001(01) DS(00000001), FNV1 :0d001477, DF=01000693(07) DS(01000193), FNV1a:04768356, DF=010007bf(11) DS(01000193), FNV1c:1510d4c8, DF=03000293(07) DS(01000193), F___RC=36e24181, DF:6a06fa6b(17) , F1__RC=e72d1e13, DF:c13ecf4d(18) , F1A_RC=168d4944, DF:7caf46b5(19) , F1C_RC=65bbcfa1, DF:0bc3d205(13) +F(00,0e)::VEC(0, e, ffffffff, 0):: FNV :0000000e, DF=00000003(02) DS(00000001), FNV1 :0e00160a, DF=0300027d(09) DS(01000193), FNV1a:037681c3, DF=07000295(08) DS(01000193), FNV1c:1810d981, DF=0d000d49(09) DS(030004b9), F___RC=10dfc718, DF:263d8699(15) , F1__RC=a8466ac8, DF:4f6b74db(20) , F1A_RC=93e667bf, DF:856b2efb(19) , F1C_RC=76f80ee3, DF:1343c142(11) +F(00,0f)::VEC(0, f, ffffffff, 0):: FNV :0000000f, DF=00000001(01) DS(00000001), FNV1 :0f00179d, DF=01000197(07) DS(01000193), FNV1a:02768030, DF=010001f3(08) DS(01000193), FNV1c:1710d7ee, DF=0f000e6f(13) DS(01000193), F___RC=eadd4caf, DF:fa028bb7(17) , F1__RC=695fb77d, DF:c119ddb5(17) , F1A_RC=0f485682, DF:9cae313d(17) , F1C_RC=3667e8dc, DF:409fe63f(18) +F(00,10)::VEC(0, 10, ffffffff, 0):: FNV :00000010, DF=0000001f(05) DS(00000001), FNV1 :10001930, DF=1f000ead(13) DS(01000193), FNV1a:01767e9d, DF=0300fead(14) DS(01000193), FNV1c:0210b6df, DF=15006131(09) DS(1500210f), F___RC=c4dad246, DF:2e079ee9(17) , F1__RC=2a790432, DF:4326b34f(16) , F1A_RC=d10adebd, DF:de42883f(16) , F1C_RC=1ce48e12, DF:2a8366ce(15) +``` + +`F(00,01)` : is input x,y + +`VEC(0, 1, ffffffff, 0)` : is `fnv_reduce` input vector (a,b,c,d) + +`FNV :00000001, DF=00000001(01) DS(00000001)` : + * `FNV(00,01)` result is 00000001 , + * `DF` : is changed bitcounts, compared with previous outputs, in this case prev[00,00] current[00,01] input is 1bit changed, and output result 1bit changed. + * `DS` : is distances of previous result and current result , ABS(prev_fnvresult,current_fnvresult). + +** Basically, `DF` is higher is best on hash algorithm. + +`F___RC=fefffe6d, DF:111e47a9(14)` : `fnv_reduce = fnv(fnv(fnv(a,b),c),d) ` result is fefffe6d , and Different Bits counts are `14` bits. + + +## Rationale + +In case of ethash algorithm, it can't prevent ASIC forever. + +And, current ethash algorithm's FNV function is depricated. + +So, It needs to be upgraded and it will make current ethash based ASICs obsolete. + +And current TETHASHV1 FNV1A implementation is based on most of ethash , which is verified for a long time. + +Another propose of big differencing the Ethash algorithm need to crypto analysis for a long times and need to GPU code optimization times. + +**Verification and Optimization timeline Examples** + +orignal ethminer (2015) -> claymore optimized miner (2016) [1year] + +genoil ethminer (2015) -> ethereum-mining/ethminer (2017) [2year] + +## Test Results:: + +Tethash miner has 2~3% of hashrate degrade on GPU, due to more core computation time. + +## Copyright + +This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/). From a77c0f76227ad152b6e3d62f3ad015b0d7f8c8ac Mon Sep 17 00:00:00 2001 From: Patrick Gallagher Date: Fri, 8 Mar 2019 09:57:23 -0500 Subject: [PATCH 086/431] Automatically merged updates to draft EIP(s) 1822 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1822.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1822.md b/EIPS/eip-1822.md index e9b10f68..40daeaf9 100644 --- a/EIPS/eip-1822.md +++ b/EIPS/eip-1822.md @@ -2,7 +2,7 @@ eip: 1822 title: Universal Upgradeable Proxy Standard (UUPS) author: Gabriel Barros , Patrick Gallagher -discussions-to: https://ethereum-magicians.org/t/eip-universal-upgradeable-proxy-standard-uups +discussions-to: https://ethereum-magicians.org/t/eip-1822-universal-upgradeable-proxy-standard-uups status: Draft type: Standards Track category: ERC @@ -339,7 +339,7 @@ contract MyToken is ERC20DataLayout, ERC20, Owned, Proxiable, LibraryLock { ## References -- "Escape-hatch" proxy Medium Post (TBA) +- ["Escape-hatch" proxy Medium Post](https://medium.com/terminaldotco/escape-hatch-proxy-efb681de108d) ## Copyright From de54e2b43bd1a40a4b108e167af7baf358183dbb Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 8 Mar 2019 16:41:49 +0100 Subject: [PATCH 087/431] Ensure hardfork metas depend on eachother (#1795) --- EIPS/eip-1013.md | 2 +- EIPS/eip-606.md | 2 +- EIPS/eip-607.md | 2 +- EIPS/eip-608.md | 2 +- EIPS/eip-609.md | 2 +- EIPS/eip-779.md | 1 + 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1013.md b/EIPS/eip-1013.md index c3bca12a..e4cf68a9 100644 --- a/EIPS/eip-1013.md +++ b/EIPS/eip-1013.md @@ -5,7 +5,7 @@ author: Nick Savers (@nicksavers) type: Meta status: Final created: 2018-04-20 -requires: 145, 1014, 1052, 1234, 1283 +requires: 145, 609, 1014, 1052, 1234, 1283 --- ## Abstract diff --git a/EIPS/eip-606.md b/EIPS/eip-606.md index 9273e9eb..74920a85 100644 --- a/EIPS/eip-606.md +++ b/EIPS/eip-606.md @@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic) type: Meta status: Final created: 2017-04-23 -requires: 2, 7 +requires: 2, 7, 8 --- ## Abstract diff --git a/EIPS/eip-607.md b/EIPS/eip-607.md index aee1efa0..fe11ea7a 100644 --- a/EIPS/eip-607.md +++ b/EIPS/eip-607.md @@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic) type: Meta status: Final created: 2017-04-23 -requires: 155, 160, 161, 170 +requires: 155, 160, 161, 170, 608 --- ## Abstract diff --git a/EIPS/eip-608.md b/EIPS/eip-608.md index 5c5060d8..2b300b4f 100644 --- a/EIPS/eip-608.md +++ b/EIPS/eip-608.md @@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic) type: Meta status: Final created: 2017-04-23 -requires: 150 +requires: 150, 779 --- ## Abstract diff --git a/EIPS/eip-609.md b/EIPS/eip-609.md index 203ae6fc..daa5c609 100644 --- a/EIPS/eip-609.md +++ b/EIPS/eip-609.md @@ -5,7 +5,7 @@ author: Alex Beregszaszi (@axic) type: Meta status: Final created: 2017-04-23 -requires: 100, 140, 196, 197, 198, 211, 214, 649, 658 +requires: 100, 140, 196, 197, 198, 211, 214, 607, 649, 658 --- ## Abstract diff --git a/EIPS/eip-779.md b/EIPS/eip-779.md index a8669b2a..4d185471 100644 --- a/EIPS/eip-779.md +++ b/EIPS/eip-779.md @@ -5,6 +5,7 @@ author: Casey Detrio type: Meta status: Final created: 2017-11-26 +requires: 606 --- ## Abstract From df507d5de731310000de27eb3db91ba8ca2d5ddc Mon Sep 17 00:00:00 2001 From: Cody Burns Date: Fri, 8 Mar 2019 10:17:55 -0600 Subject: [PATCH 088/431] Add opcode 0x46 blockreward (#700) --- EIPS/eip-698.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 EIPS/eip-698.md diff --git a/EIPS/eip-698.md b/EIPS/eip-698.md new file mode 100644 index 00000000..1235c5c9 --- /dev/null +++ b/EIPS/eip-698.md @@ -0,0 +1,85 @@ +--- +eip: 698 +title: OPCODE 0x46 BLOCKREWARD +author: Cody Burns +discussions-to: https://github.com/ethereum/EIPs/issues/698 +status: Draft +type: Standards Track +category: Core +created: 2017-28-08 +--- + +## Simple Summary + +This EIP adds an additional opcode to the EVM which will return a finalized blocks reward value. + +## Abstract + +In the EVM, the 0x40 opcodes are reserved for `Block Information`. Currently reserved opcodes are: +* `0X40 BLOCKHASH` +* `0X41 COINBASE` +* `0X42 TIMESTAMP` +* `0X43 NUMBER` +* `0X44 DIFFICULTY` +* `0X45 GASLIMIT` + +This EIP would add an additional opcode, `0x46 BLOCKREWARD`, which would return the block reward for any finalized block. The finalized block reward would include the base reward, uncle payments, and gas. + +## Motivation + + +Per EIP-649 ( #669 ) periodic block reward reductions/variance are now planned in the roadmap, however, this EIP is consensus system agnostic and is most useful in decentralized pool operations and for any contract that benefits from knowing a block reward payout(i.e. Merge mined tokens) + +## Specification + +After block `n` all clients should process opcode `0x46` as follows: + +* Value: `0x46` +* Mnemonic: `BLOCKREWARD` +* δ:` 0` nothing removed from stack +* α:`1` block reward added to stack +* Description: `Get the block's reward emission` +* GasCost: `Gbase` + +Where:`µ's[0] ≡ IHR` + + +## Rationale + +### Contract Mining Pools + +For distributed consensus systems(staking pools and mining pools) ad hoc groups combine resources in order to reduce variance in payouts. Broadly, pool operations function by allowing a collective of miners / stakers to verify their contribution to solving PoW or staking share by periodically submitting solutions which are is representative of the miners probability of finding a true block. + +In all these schemes `B` stands for a block reward minus pool fee and `p` is a probability of finding a block in a share attempt ( `p=1/D`, where `D` is current block difficulty). + +Some common methods of mining pool payout are pay-per-share, `R = B * p`, proportional [`R = B * (n/N)` where `n` is amount of a miners shares, and `N` is amount of all shares in this round.], and pay-per-last-N-shares [`R = B * (n/N)` where miner's reward is calculated on a basis of `N` last shares, instead of all shares for the last round]. All of these methods are predicated on knowing the block reward paid for a given block. In order to provide a trust minimized solution, `0x46` can be used to call a blocks reward for computing payouts. + +### Merge mined tokens + +Contracts could create tokens which could be variably ‘minted’ as a function of block reward by calling `0x46` + +## Backwards Compatibility + + +### Currently deployed contracts + +No impact + +### Current clients + +This EIP would be incompatible with currently deployed clients that are not able to handle `0x46` and would process all transactions and block containing the opcode as invalid. + +Implementation should occur as part of a coordinated hardfork. + +## Implementation + + +## Further reading + +[Mining Pools](https://en.wikipedia.org/wiki/Mining_pool) + +The Yellow Paper Appendix H. Virtual Machine Specification section H.2 + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From ac0e1f94a805dab61197a05c08b06cd9620c3131 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 8 Mar 2019 17:20:05 +0100 Subject: [PATCH 089/431] Add temporal replay protection (#1681) --- EIPS/eip-1681.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 EIPS/eip-1681.md diff --git a/EIPS/eip-1681.md b/EIPS/eip-1681.md new file mode 100644 index 00000000..2e557f28 --- /dev/null +++ b/EIPS/eip-1681.md @@ -0,0 +1,91 @@ +--- +eip: 1681 +title: Temporal Replay Protection +author: Martin Holst Swende (@holiman) +discussions-to: https://ethereum-magicians.org/t/temporal-replay-protection/2355 +status: Draft +type: Standards Track +category: Core +created: 2019-01-08 +--- + +## Simple Summary + +This EIP proposes adding a 'temporal' replay protection to transactions, in the form of a `valid-until` timestamp. +This EIP is very similar to https://github.com/ethereum/EIPs/pull/599 by Nick Johnson and Konrad Feldmeier, the main difference +being that this EIP is based on clock-time / walltime instead of block numbers. + + +## Motivation + +There are a couple of different motivators for introducing a timebased transaction validity. + +- If any form of dust-account clearing is introduced, e.g. (https://github.com/ethereum/EIPs/issues/168), it will be necessary +to introduce a replay protection, such as https://github.com/ethereum/EIPs/issues/169 . Having temporal replay protection removes the need +to change nonce-behaviour in the state, since transactions would not be replayable at a later date than explicitly set by the user. +- In many cases, such as during ICOs, a lot of people want their transactions to either become included soon (within a couple of hours) or not at all. Currently, +transactions are queued and may not execute for several days, at a cost for both the user (who ends up paying gas for a failing purchase) and the network, dealing with the large transaction queues. +- Node implementations have no commonly agreed metric for which transactions to keep, discard or propagate. Having a TTL on transactions would make it easier to remove stale transactions from the system. + +## Specification + +The roll-out would be performed in two phases, `X` (hardfork), and `Y` (softfork). + +At block `X`, + +- Add an optional field `valid-until` to the RLP-encoded transaction, defined as a `uint64` (same as `nonce`). +- If the field is present in transaction `t`, then + - `t` is only eligible for inclusion in a block if `block.timestamp` < `t.valid-until`. + +At block `Y`, +- Make `valid-until` mandatory, and consider any transaction without `valid-until` to be invalid. + +## Rationale + +### Rationale for this EIP + +For the dust-account clearing usecase, +- This change is much less invasive in the consensus engine. + - No need to maintain a consensus-field of 'highest-known-nonce' or cap the number of transactions from a sender in a block. + - Only touches the transaction validation part of the consensus engine + - Other schemas which uses the `nonce` can have unintended side-effects, + - such as inability to create contracts at certain addresses. + - more difficult to integrate with offline signers, since more elaborate nonce-schemes requires state access to determine. + - More intricate schemes like `highest-nonce` are a lot more difficult, since highest-known-nonce will be a consensus-struct that is incremented and possibly reverted during transaction execution, requireing one more journalled field. + + +### Rationale for walltime + +Why use walltime instead of block numbers, as proposed in https://github.com/ethereum/EIPs/pull/599 ? + +- The UTC time is generally available in most settings, even on a computer which is offline. This means that even a setup where blockchain information is unavailable, the party signing a transaction can generate a transaction with the desired properties. +- The correlation between time and block number is not fixed; even though a 14s blocktime is 'desired', this varies due to both network hashrate and difficulty bomb progression. +- The block number is even more unreliable as a timestamp for testnets and private networks. +- UTC time is more user-friendly, a user can more easily decide on reasonable end-date for a transaction, rather than a suitalbe number of valid blocks. + + +## Backwards Compatibility + +This EIP means that all software/hardware that creates transactions need to add timestamps to the transactions, or will otherwise be incapable of signing transactions after block `Y`. Note: this EIP does not introduce any maximum `valid-until` date, so it would still be possible to create +transactions with near infinite validity. + +## Test Cases + +todo + +## Implementation + +None yet + +## Security considerations + +The most notable security impact is that pre-signed transactions stored on paper backups, will become invalid as of block `Y`. There are a couple of cases where this might be used + - Pregenerated onetime 'bootstrap' transactions, e.g. to onboard a user into Ethereum. Instead of giving a user a giftcard with actual ether on it, someone may instead give the person a one-time pregenerated transaction that will only send those ether to the card once the +user actively wants to start using it. + - If a user has an offline paper-wallet, he may have pregenerated transactions to send value to e.g. an exchange. This is sometimes done to be able to send ether to an exchange without having to go through all the hoops of bringing the paper wallet back to 'life'. + +Secondary security impacts are that the addition of a timestamp would make the transactions a little bit larger. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + From 8f506518ecc8ba911d3df0c4968bdb2b07012c25 Mon Sep 17 00:00:00 2001 From: Alex Van de Sande Date: Fri, 8 Mar 2019 15:22:02 -0300 Subject: [PATCH 090/431] Adding co-author to EIP-55 (#951) --- EIPS/eip-55.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-55.md b/EIPS/eip-55.md index f57bb693..3ef0eff3 100644 --- a/EIPS/eip-55.md +++ b/EIPS/eip-55.md @@ -1,7 +1,7 @@ --- eip: 55 title: Mixed-case checksum address encoding -author: Vitalik Buterin +author: Vitalik Buterin , Alex Van de Sande type: Standards Track category: ERC status: Final From 5d81cc0062890a5056e6c7f8886ed6b2c34cd47e Mon Sep 17 00:00:00 2001 From: ligi Date: Fri, 8 Mar 2019 19:32:18 +0100 Subject: [PATCH 091/431] Strip the list of chain ID's (#1835) --- EIPS/eip-155.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/EIPS/eip-155.md b/EIPS/eip-155.md index d5615331..52324ad1 100644 --- a/EIPS/eip-155.md +++ b/EIPS/eip-155.md @@ -60,17 +60,9 @@ This would provide a way to send transactions that work on Ethereum without work | 2 | Morden (disused), Expanse mainnet | | 3 | Ropsten | | 4 | Rinkeby | -| 8 | Ubiq mainnet | -| 9 | Ubiq testnet | -| 30 | Rootstock mainnet | -| 31 | Rootstock testnet | +| 5 | Goerli | | 42 | Kovan | -| 61 | Ethereum Classic mainnet | -| 62 | Ethereum Classic testnet | -| 66 | ewasm testnet | | 1337 | Geth private chains (default) | -| 6284 | Görli | -| 43568 | Gangnam | -| 314158 | Stureby | + Find more chain ID's on [chainid.network](https://chainid.network) and contribute to [ethereum-lists/chains](https://github.com/ethereum-lists/chains). \ No newline at end of file From 035a0211685145c8951bab9f439880894c5d0cdf Mon Sep 17 00:00:00 2001 From: William Entriken Date: Sat, 9 Mar 2019 02:56:08 -0500 Subject: [PATCH 092/431] Update HTTP->HTTPS when both URLs work (#1714) --- EIPS/eip-1.md | 4 ++-- EIPS/eip-1015.md | 6 +++--- EIPS/eip-1066.md | 2 +- EIPS/eip-1123.md | 12 ++++++------ EIPS/eip-1155.md | 2 +- EIPS/eip-1261.md | 2 +- EIPS/eip-137.md | 4 ++-- EIPS/eip-1444.md | 6 +++--- EIPS/eip-1613.md | 2 +- EIPS/eip-162.md | 2 +- EIPS/eip-165.md | 2 +- EIPS/eip-190.md | 6 +++--- EIPS/eip-616.md | 8 ++++---- EIPS/eip-665.md | 4 ++-- EIPS/eip-712.md | 4 ++-- EIPS/eip-721.md | 4 ++-- EIPS/eip-725.md | 4 ++-- EIPS/eip-8.md | 2 +- EIPS/eip-820.md | 4 ++-- EIPS/eip-884.md | 2 +- EIPS/eip-908.md | 8 ++++---- EIPS/eip-969.md | 2 +- README.md | 2 +- _layouts/eip.html | 2 +- assets/eip-858/calculations.md | 2 +- 25 files changed, 49 insertions(+), 49 deletions(-) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 13c94669..8fc28d16 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -56,7 +56,7 @@ Each status change is requested by the EIP author and reviewed by the EIP editor * **Draft** -- Once the first draft has been merged, you may submit follow-up pull requests with further changes to your draft until such point as you believe the EIP to be mature and ready to proceed to the next status. An EIP in draft status must be implemented to be considered for promotion to the next status (ignore this requirement for core EIPs). * :arrow_right: Last Call -- If agreeable, the EIP editor will assign Last Call status and set a review end date (`review-period-end`), normally 14 days later. * :x: Last Call -- A request for Last Call status will be denied if material changes are still expected to be made to the draft. We hope that EIPs only enter Last Call once, so as to avoid unnecessary noise on the RSS feed. -* **Last Call** -- This EIP will listed prominently on the http://eips.ethereum.org/ website (subscribe via RSS at [last-call.xml](/last-call.xml)). +* **Last Call** -- This EIP will listed prominently on the https://eips.ethereum.org/ website (subscribe via RSS at [last-call.xml](/last-call.xml)). * :x: -- A Last Call which results in material changes or substantial unaddressed technical complaints will cause the EIP to revert to Draft. * :arrow_right: Accepted (Core EIPs only) -- A successful Last Call without material changes or unaddressed technical complaints will become Accepted. * :arrow_right: Final (Not core EIPs) -- A successful Last Call without material changes or unaddressed technical complaints will become Final. @@ -235,7 +235,7 @@ December 7, 2015: EIP 1 has been improved and will be placed as a PR. February 1, 2016: EIP 1 has added editors, made draft improvements to process, and has merged with Master stream. -March 21, 2018: Minor edits to accommodate the new automatically-generated EIP directory on [eips.ethereum.org](http://eips.ethereum.org/). +March 21, 2018: Minor edits to accommodate the new automatically-generated EIP directory on [eips.ethereum.org](https://eips.ethereum.org/). May 29, 2018: A last call process was added. diff --git a/EIPS/eip-1015.md b/EIPS/eip-1015.md index c9e9ba7b..9c844a55 100644 --- a/EIPS/eip-1015.md +++ b/EIPS/eip-1015.md @@ -28,16 +28,16 @@ Moving to PoS has been on the roadmap since day 0 for ethereum, along with a red #### Asics and advantadges of PoW -[EIP 960](http://eips.ethereum.org/EIPS/eip-969) proposes a change in algorithm to avoid mining being dominated by ASICS. Counter arguments by Phil Daian argue among others than [resisting economies of scale is futile and there might be specific security advantadges to specialized hardware](https://pdaian.com/blog/anti-asic-forks-considered-harmful/). One of the main arguments for PoW mining, even when it doesn't provide security, it is useful as a fair distribution mechanism, that **PoW allows any person with a computer, internet access and electricity to obtain currency without having to deal with government imposed currency controls**. +[EIP 960](https://eips.ethereum.org/EIPS/eip-969) proposes a change in algorithm to avoid mining being dominated by ASICS. Counter arguments by Phil Daian argue among others than [resisting economies of scale is futile and there might be specific security advantadges to specialized hardware](https://pdaian.com/blog/anti-asic-forks-considered-harmful/). One of the main arguments for PoW mining, even when it doesn't provide security, it is useful as a fair distribution mechanism, that **PoW allows any person with a computer, internet access and electricity to obtain currency without having to deal with government imposed currency controls**. #### Recovery Forks -After the Parity Multisig library self destruction, three different strategies have been attempted to recover the funds: [a general protocol improvement to allow reviving self destructed contracts](https://gist.github.com/5chdn/a9bb8617cc8523a030126a3d1c60baf3) (which was considered dangerous), a [general process to recover funds](https://github.com/ethereum/EIPs/pull/867) and a [specific recovery of the multisig library](http://eips.ethereum.org/EIPS/eip-999). The latter two are finding a lot of resistance from the community, but it's unlikely that these issues are going away soon. The affected parties have a large incentive (fluctuating at almost half a billion dollars) to keep trying, and it's an issue that is likely to occur again in the future. If they get reimbursed, [there are many other special cases of ether provably burnt or stuck](https://github.com/ethereum/EIPs/issues/156) that might deserve the same treatment. If they get shut down, they have an incentive to move forward a fork implementation: even if they are a minority chain, it's likely they'll recover an amount larger than 0, which is what they would otherwise, and it means the main ethereum community might lose a valuable team of developers. +After the Parity Multisig library self destruction, three different strategies have been attempted to recover the funds: [a general protocol improvement to allow reviving self destructed contracts](https://gist.github.com/5chdn/a9bb8617cc8523a030126a3d1c60baf3) (which was considered dangerous), a [general process to recover funds](https://github.com/ethereum/EIPs/pull/867) and a [specific recovery of the multisig library](https://eips.ethereum.org/EIPS/eip-999). The latter two are finding a lot of resistance from the community, but it's unlikely that these issues are going away soon. The affected parties have a large incentive (fluctuating at almost half a billion dollars) to keep trying, and it's an issue that is likely to occur again in the future. If they get reimbursed, [there are many other special cases of ether provably burnt or stuck](https://github.com/ethereum/EIPs/issues/156) that might deserve the same treatment. If they get shut down, they have an incentive to move forward a fork implementation: even if they are a minority chain, it's likely they'll recover an amount larger than 0, which is what they would otherwise, and it means the main ethereum community might lose a valuable team of developers. #### Other Public Goods -There are many other types of public goods that could be funded by issuance. By *Public Good*, I'm using a strict definition of something that brings value to everyone, both those who funded it and free-loaders, making it hard to fund it exclusively by traditional private incentives. They can be research, whole network security, [incentivize full clients and networking](http://eips.ethereum.org/EIPS/eip-908), fair distribution of tokens etc. +There are many other types of public goods that could be funded by issuance. By *Public Good*, I'm using a strict definition of something that brings value to everyone, both those who funded it and free-loaders, making it hard to fund it exclusively by traditional private incentives. They can be research, whole network security, [incentivize full clients and networking](https://eips.ethereum.org/EIPS/eip-908), fair distribution of tokens etc. ## Proposed Solution ### Issuance Contract diff --git a/EIPS/eip-1066.md b/EIPS/eip-1066.md index d7df61af..e5ea916a 100644 --- a/EIPS/eip-1066.md +++ b/EIPS/eip-1066.md @@ -47,7 +47,7 @@ At time of writing, other than stepping through EVM execution and inspecting mem Having a fixed set of codes also makes it possible to write common helper functions to react in common ways to certain signals. This can live off- or on-chain library, lowering the overhead in building smart contracts, and helping raise code quality with trusted shared components. -We also see a desire for this [in transactions](http://eips.ethereum.org/EIPS/eip-658), and there's no reason that these status codes couldn't be used by the EVM itself. +We also see a desire for this [in transactions](https://eips.ethereum.org/EIPS/eip-658), and there's no reason that these status codes couldn't be used by the EVM itself. ### Smart Contract Autonomy diff --git a/EIPS/eip-1123.md b/EIPS/eip-1123.md index 3ef991f5..11605fcf 100644 --- a/EIPS/eip-1123.md +++ b/EIPS/eip-1123.md @@ -77,7 +77,7 @@ contracts. > **Note** > > A [hosted -> version](http://ethpm.github.io/ethpm-spec) of this +> version](https://ethpm.github.io/ethpm-spec) of this > specification is available via GitHub Pages. This EIP and the hosted > HTML document were both autogenerated from the same documentation > source. @@ -174,7 +174,7 @@ name collisions with future versions of the specification. - + @@ -286,7 +286,7 @@ be included in all Packages. The `version` field declares the version number of this release. This value **must** be included in all Packages. This value **should** -conform to the [semver](http://semver.org/) version +conform to the [semver](https://semver.org/) version numbering specification.
    ERC820ERC1820 to address ERC777 Sending And Minting ERC20 transfer/transferFrom

    See Also

    Formalized (JSON-Schema) version of this specification: package.spec.json

    Formalized (JSON-Schema) version of this specification: package.spec.json

    Jump To

    @@ -1404,7 +1404,7 @@ The `name` field defines which compiler was used in compilation. The `version` field defines the version of the compiler. The field **should** be OS agnostic (OS not included in the string) and take the form of either the stable version in -[semver](http://semver.org/) format or if built on a +[semver](https://semver.org/) format or if built on a nightly should be denoted in the form of `-` ex: `0.4.8-commit.60cc1668`. @@ -1435,7 +1435,7 @@ nightly should be denoted in the form of `-` ex: The `settings` field defines any settings or configuration that was used in compilation. For the `"solc"` compiler, this **should** conform to the [Compiler Input and Output -Description](http://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description). +Description](https://solidity.readthedocs.io/en/latest/using-the-compiler.html#compiler-input-and-output-json-description).
    @@ -1848,7 +1848,7 @@ a supporting implementation. - [Truffle](http://trufflesuite.com/) -- [Populus](http://populus.readthedocs.io/en/latest/) +- [Populus](https://populus.readthedocs.io/en/latest/) - [Embark](https://embark.status.im/) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index ea28760a..cf6df776 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -486,7 +486,7 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok - [ERC-721 Non-Fungible Token Standard](https://raw.githubusercontent.com/ethereum/EIPs/master/EIPS/eip-721.md) - [ERC-165 Standard Interface Detection](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md) - [ERC-1538 Transparent Contract Standard](https://github.com/ethereum/EIPs/issues/1538) -- [JSON Schema](http://json-schema.org/) +- [JSON Schema](https://json-schema.org/) - [RFC 2119 Key words for use in RFCs to Indicate Requirement Levels](https://www.ietf.org/rfc/rfc2119.txt) **Implementations** diff --git a/EIPS/eip-1261.md b/EIPS/eip-1261.md index 85314f24..5645d025 100644 --- a/EIPS/eip-1261.md +++ b/EIPS/eip-1261.md @@ -365,7 +365,7 @@ Membership Verification Token ERC1261 -- a reference implementation 1. ERC-165 Standard Interface Detection. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md 1. ERC-725/735 Claim Registry https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md 1. ERC-173 Owned Standard. https://github.com/ethereum/EIPs/issues/173 -1. JSON Schema. http://json-schema.org/ +1. JSON Schema. https://json-schema.org/ 1. Multiaddr. https://github.com/multiformats/multiaddr 1. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt diff --git a/EIPS/eip-137.md b/EIPS/eip-137.md index 5b0c7b67..cc873744 100644 --- a/EIPS/eip-137.md +++ b/EIPS/eip-137.md @@ -70,10 +70,10 @@ Because the `namehash` procedure depends only on the name itself, this can be pr ENS names must conform to the following syntax:
    <domain> ::= <label> | <domain> "." <label>
    -<label> ::= any valid string label per [UTS46](http://unicode.org/reports/tr46/)
    +<label> ::= any valid string label per [UTS46](https://unicode.org/reports/tr46/)
     
    -In short, names consist of a series of dot-separated labels. Each label must be a valid normalised label as described in [UTS46](http://unicode.org/reports/tr46/) with the options `transitional=false` and `useSTD3AsciiRules=true`. For Javascript implementations, a [library](https://www.npmjs.com/package/idna-uts46) is available that normalises and checks names. +In short, names consist of a series of dot-separated labels. Each label must be a valid normalised label as described in [UTS46](https://unicode.org/reports/tr46/) with the options `transitional=false` and `useSTD3AsciiRules=true`. For Javascript implementations, a [library](https://www.npmjs.com/package/idna-uts46) is available that normalises and checks names. Note that while upper and lower case letters are allowed in names, the UTS46 normalisation process case-folds labels before hashing them, so two names with different case but identical spelling will produce the same namehash. diff --git a/EIPS/eip-1444.md b/EIPS/eip-1444.md index ac3a05a0..b46d4f58 100644 --- a/EIPS/eip-1444.md +++ b/EIPS/eip-1444.md @@ -106,7 +106,7 @@ function textFor(bytes32 _code) external view returns (bool _wasFound, string _t ### String Format -All strings MUST be encoded as [UTF-8](http://www.ietf.org/rfc/rfc3629.txt). +All strings MUST be encoded as [UTF-8](https://www.ietf.org/rfc/rfc3629.txt). ```solidity "Špeĉiäl chârãçtérs are permitted" @@ -117,7 +117,7 @@ All strings MUST be encoded as [UTF-8](http://www.ietf.org/rfc/rfc3629.txt). ### Templates -Template strings are allowed, and MUST follow the [ANSI C `printf`](http://pubs.opengroup.org/onlinepubs/009696799/utilities/printf.html) conventions. +Template strings are allowed, and MUST follow the [ANSI C `printf`](https://pubs.opengroup.org/onlinepubs/009696799/utilities/printf.html) conventions. ```solidity "Satoshi's true identity is %s" @@ -155,7 +155,7 @@ A very viable alternative is to store text off chain, with a pointer to the tran UTF-8 is the most widely used encoding at time of writing. It contains a direct embedding of ASCII, while providing characters for most natural languages, emoji, and special characters. -Please see the [UTF-8 Everywhere Manifesto](http://utf8everywhere.org/) for more information. +Please see the [UTF-8 Everywhere Manifesto](https://utf8everywhere.org/) for more information. ### When No Text is Found diff --git a/EIPS/eip-1613.md b/EIPS/eip-1613.md index 0dd558e3..7ed7b64c 100644 --- a/EIPS/eip-1613.md +++ b/EIPS/eip-1613.md @@ -87,7 +87,7 @@ Glossary of terms used in the processes below: * `Sender` - an external address with a valid keypair but no ETH to pay for gas. * `Relay` - a node holding ETH in an external address, listed in RelayHub and relaying transactions from Senders to RelayHub for a fee. -![Sequence Diagram](http://bit.ly/2EWWVN8) +![Sequence Diagram](https://bit.ly/2EWWVN8) The process of registering/refreshing a `Relay`: diff --git a/EIPS/eip-162.md b/EIPS/eip-162.md index 02f6b13f..60cec465 100644 --- a/EIPS/eip-162.md +++ b/EIPS/eip-162.md @@ -226,7 +226,7 @@ A slower release allows for extra time to identify, and address any issues which Choosing a single TLD helps to maximize network effects by focusing on one namespace. -A three letter TLD is a pattern made familiar by it's common usage in internet domain names. This familiarity significantly increases the potential of the ENS to be integrated into pre-existing DNS systems, and reserved as a [special-use domain name](http://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml#special-use-domain). A recent precedent for this is the [reservation of the `.onion` domain](https://tools.ietf.org/html/rfc7686). +A three letter TLD is a pattern made familiar by it's common usage in internet domain names. This familiarity significantly increases the potential of the ENS to be integrated into pre-existing DNS systems, and reserved as a [special-use domain name](https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml#special-use-domain). A recent precedent for this is the [reservation of the `.onion` domain](https://tools.ietf.org/html/rfc7686). ### Holding ether as collateral diff --git a/EIPS/eip-165.md b/EIPS/eip-165.md index 666c3bb2..5d333aab 100644 --- a/EIPS/eip-165.md +++ b/EIPS/eip-165.md @@ -30,7 +30,7 @@ For some "standard interfaces" like [the ERC-20 token interface](https://github. ### How Interfaces are Identified -For this standard, an *interface* is a set of [function selectors as defined by the Ethereum ABI](http://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector). This a subset of [Solidity's concept of interfaces](http://solidity.readthedocs.io/en/develop/abi-spec.html) and the `interface` keyword definition which also defines return types, mutability and events. +For this standard, an *interface* is a set of [function selectors as defined by the Ethereum ABI](https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector). This a subset of [Solidity's concept of interfaces](https://solidity.readthedocs.io/en/develop/abi-spec.html) and the `interface` keyword definition which also defines return types, mutability and events. We define the interface identifier as the XOR of all function selectors in the interface. This code example shows how to calculate an interface identifier: diff --git a/EIPS/eip-190.md b/EIPS/eip-190.md index 6e5d9247..a56bc332 100644 --- a/EIPS/eip-190.md +++ b/EIPS/eip-190.md @@ -88,9 +88,9 @@ Allows for packages which exclude source code or other elements which would be n Support for ERC190 is either implemented or in progress for the following: -* [Truffle](http://truffleframework.com/) -* [Populus](http://populus.readthedocs.io/en/latest/) -* [Dapple](http://dapple.readthedocs.io/en/master/) +* [Truffle](https://truffleframework.com/) +* [Populus](https://populus.readthedocs.io/en/latest/) +* [Dapple](https://dapple.readthedocs.io/en/master/) * [Eris PM](https://github.com/eris-ltd/eris-cli) * [Embark](https://github.com/iurimatias/embark-framework) * [Browser Solidity](https://github.com/ethereum/remix-ide/issues/386) diff --git a/EIPS/eip-616.md b/EIPS/eip-616.md index d7801086..d4289642 100644 --- a/EIPS/eip-616.md +++ b/EIPS/eip-616.md @@ -16,12 +16,12 @@ A proposal to provide Single Instruction Multiple Data types and operations for Most all modern CPUs include SIMD hardware that operates on wide registers of data, applying a Single Instruction to Multiple Data lanes in parallel, where lanes divide a register into a vector of scalar elements of equal size. This model is an excellent fit for the wide stack items of the EVM, offering substantial performance boosts for operations that can be expressed as parallel operations on vectors of scalars. For some examples, a brief literature search finds SIMD speedups of * up to 7X for [SHA-512](http://keccak.noekeon.org/sw_performance.html) -* 4X for [elliptic curve scalar multiplication](http://link.springer.com/chapter/10.1007/3-540-45439-X_16) -* 3X to 4X for [BLAKE2b](http://github.com/minio/blake2b-simd) +* 4X for [elliptic curve scalar multiplication](https://link.springer.com/chapter/10.1007/3-540-45439-X_16) +* 3X to 4X for [BLAKE2b](https://github.com/minio/blake2b-simd) * up to 3X for [OpenSSL](https://software.intel.com/en-us/articles/improving-openssl-performance) * 2X to 3X for [elliptic curve modular multiplication](http://ieee-hpec.org/2013/index_htm_files/24-Simd-acceleration-Pabbuleti-2886999.pdf) * 1.7X to 1.9X for [SHA-256](https://github.com/minio/sha256-simd) -* 1.3X for [RSA encryption](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.738.1218&rep=rep1&type=pdf) +* 1.3X for [RSA encryption](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.738.1218&rep=rep1&type=pdf) ## SPECIFICATION @@ -118,7 +118,7 @@ For most modern languages (including Rust, Python, Go, Java, and C++) compilers One motivation for these operations, besides taking full advantage of the hardware, is assigning lower gas costs for operations on smaller scalars. -On a machine with 64-bit registers the standard algorithms from Knuth's [Art of Computer Programming](http://library.aceondo.net/ebooks/Computer_Science/algorithm-the_art_of_computer_programming-knuth.pdf) require 32-bit digits, using the upper half of a register for overflows, so for 256-bit values N=8 digits are needed, and for 64-bit values N=2 digits are needed. The cycle counts for these algorithms are: +On a machine with 64-bit registers the standard algorithms from Knuth's [Art of Computer Programming](https://library.aceondo.net/ebooks/Computer_Science/algorithm-the_art_of_computer_programming-knuth.pdf) require 32-bit digits, using the upper half of a register for overflows, so for 256-bit values N=8 digits are needed, and for 64-bit values N=2 digits are needed. The cycle counts for these algorithms are: operation | cycles | N = 2 | N = 4 | N = 8 -|-|-|-|- diff --git a/EIPS/eip-665.md b/EIPS/eip-665.md index a3527c30..a6dbcd71 100644 --- a/EIPS/eip-665.md +++ b/EIPS/eip-665.md @@ -130,8 +130,8 @@ Implementations of this proposal are here: * Test vectors for Ed25519: https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-6 * NaCl regression tests: https://ed25519.cr.yp.to/python/sign.py and https://ed25519.cr.yp.to/python/sign.input * On the recoverability of public keys from signature+message (alone): https://crypto.stackexchange.com/questions/9936/what-signature-schemes-allow-recovering-the-public-key-from-a-signature -* Bernstein, D., "Curve25519: new Diffie-Hellman speed records", DOI 10.1007/11745853_14, February 2006, http://cr.yp.to/ecdh.html -* Hamburg, M., "Ed448-Goldilocks, a new elliptic curve", June 2015, http://eprint.iacr.org/2015/625> +* Bernstein, D., "Curve25519: new Diffie-Hellman speed records", DOI 10.1007/11745853_14, February 2006, https://cr.yp.to/ecdh.html +* Hamburg, M., "Ed448-Goldilocks, a new elliptic curve", June 2015, https://eprint.iacr.org/2015/625> * RFC8080: Edwards-Curve Digital Security Algorithm (EdDSA) for DNSSEC (https://tools.ietf.org/html/rfc8080) ## Copyright diff --git a/EIPS/eip-712.md b/EIPS/eip-712.md index 9637275f..f7e8f893 100644 --- a/EIPS/eip-712.md +++ b/EIPS/eip-712.md @@ -207,7 +207,7 @@ By adding a prefix to the message makes the calculated signature recognisable as Typed data is a JSON object containing type information, domain seprator parameters and the message object. Below is the [json-schema][jsons] definition for `TypedData` param. -[jsons]: http://json-schema.org/ +[jsons]: https://json-schema.org/ ```JavaScript { @@ -274,7 +274,7 @@ There also should be a corresponding `personal_signTypedData` method which accep Two methods are added to [Web 3 version 1][web3-1] that parallel the `web3.eth.sign` and `web3.eth.personal.sign` methods. -[web3-1]: http://web3js.readthedocs.io/en/1.0/index.html +[web3-1]: https://web3js.readthedocs.io/en/1.0/index.html #### web3.eth.signTypedData diff --git a/EIPS/eip-721.md b/EIPS/eip-721.md index 721b6fc7..3cb20230 100644 --- a/EIPS/eip-721.md +++ b/EIPS/eip-721.md @@ -398,7 +398,7 @@ XXXXERC721, by William Entriken -- a scalable example implementation 1. ERC-827 Token Standard. https://eips.ethereum.org/EIPS/eip-827 1. Ethereum Name Service (ENS). https://ens.domains 1. Instagram -- What's the Image Resolution? https://help.instagram.com/1631821640426723 -1. JSON Schema. http://json-schema.org/ +1. JSON Schema. https://json-schema.org/ 1. Multiaddr. https://github.com/multiformats/multiaddr 1. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt @@ -412,7 +412,7 @@ XXXXERC721, by William Entriken -- a scalable example implementation 1. Solidity Issue \#3544 -- Cannot Calculate Selector of Function Named `transfer`. https://github.com/ethereum/solidity/issues/3544 1. CryptoKitties Bounty Issue \#4 -- Listing all Kitties Owned by a User is `O(n^2)`. https://github.com/axiomzen/cryptokitties-bounty/issues/4 1. OpenZeppelin Issue \#438 -- Implementation of `approve` method violates ERC20 standard. https://github.com/OpenZeppelin/zeppelin-solidity/issues/438 -1. Solidity DelegateCallReturnValue Bug. http://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue +1. Solidity DelegateCallReturnValue Bug. https://solidity.readthedocs.io/en/develop/bugs.html#DelegateCallReturnValue **Discussions** diff --git a/EIPS/eip-725.md b/EIPS/eip-725.md index 94d6f5a6..ee0b8c9b 100644 --- a/EIPS/eip-725.md +++ b/EIPS/eip-725.md @@ -294,9 +294,9 @@ contract ERC725 { - [Slides of the ERC Identity presentation](https://www.slideshare.net/FabianVogelsteller/erc-725-identity) - [In-contract claim VS claim registry](https://github.com/ethereum/wiki/wiki/ERC-735:-Claim-Holder-Registry-vs.-in-contract) -- [Identity related reports](http://www.weboftrust.info/specs.html) +- [Identity related reports](https://www.weboftrust.info/specs.html) - [W3C Verifiable Claims Use Cases](https://w3c.github.io/vc-use-cases/) -- [Decentralised Identity Foundation](http://identity.foundation) +- [Decentralised Identity Foundation](https://identity.foundation) - [Sovrin Foundation Self Sovereign Identity](https://sovrin.org/wp-content/uploads/2017/06/The-Inevitable-Rise-of-Self-Sovereign-Identity.pdf) ## Copyright diff --git a/EIPS/eip-8.md b/EIPS/eip-8.md index 006e85c1..6a01a1ce 100644 --- a/EIPS/eip-8.md +++ b/EIPS/eip-8.md @@ -85,7 +85,7 @@ The proposed changes address forward compatibility by applying Postel's Law (als the Robustness Principle) throughout the protocol stack. The merit and applicability of this approach has been studied repeatedly since its original application in RFC 761. For a recent perspective, see -["The Robustness Principle Reconsidered" (Eric Allman, 2011)](http://queue.acm.org/detail.cfm?id=1999945). +["The Robustness Principle Reconsidered" (Eric Allman, 2011)](https://queue.acm.org/detail.cfm?id=1999945). #### Changes to the devp2p Wire Protocol diff --git a/EIPS/eip-820.md b/EIPS/eip-820.md index dbfded3b..fb17ab6b 100644 --- a/EIPS/eip-820.md +++ b/EIPS/eip-820.md @@ -56,7 +56,7 @@ This standard also provides a *unique* address for all chains. Thus solving the * * You should have received a copy of the CC0 Public Domain Dedication along * with this software. If not, see - * . + * . * * ███████╗██████╗ ██████╗ █████╗ ██████╗ ██████╗ * ██╔════╝██╔══██╗██╔════╝██╔══██╗╚════██╗██╔═████╗ @@ -636,7 +636,7 @@ The contract has the address above for every chain on which it is deployed. }, "sources": { "./contracts/ERC820Registry.sol": { - "content": "/* ERC820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address\n * (contract or regular account) can register which interface it supports and\n * which smart contract is responsible for its implementation.\n *\n * Written in 2018 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright\n * and related and neighboring rights to this software to the public domain\n * worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along\n * with this software. If not, see\n * .\n *\n * ███████╗██████╗ ██████╗ █████╗ ██████╗ ██████╗\n * ██╔════╝██╔══██╗██╔════╝██╔══██╗╚════██╗██╔═████╗\n * █████╗ ██████╔╝██║ ╚█████╔╝ █████╔╝██║██╔██║\n * ██╔══╝ ██╔══██╗██║ ██╔══██╗██╔═══╝ ████╔╝██║\n * ███████╗██║ ██║╚██████╗╚█████╔╝███████╗╚██████╔╝\n * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗\n * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝\n * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝\n * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║\n * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\n *\n */\npragma solidity 0.4.24;\n// IV is value needed to have a vanity address starting with `0x820`.\n// IV: 9513\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC820ImplementerInterface {\n /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not.\n /// @param interfaceHash keccak256 hash of the name of the interface\n /// @param addr Address for which the contract will implement the interface\n /// @return ERC820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`.\n function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-820\ncontract ERC820Registry {\n /// @notice ERC165 Invalid ID.\n bytes4 constant INVALID_ID = 0xffffffff;\n /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n bytes4 constant ERC165ID = 0x01ffc9a7;\n /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n bytes32 constant ERC820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC820_ACCEPT_MAGIC\"));\n\n mapping (address => mapping(bytes32 => address)) interfaces;\n mapping (address => address) managers;\n mapping (address => mapping(bytes4 => bool)) erc165Cached;\n\n /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`.\n event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n /// @notice Indicates `newManager` is the address of the new manager for `addr`.\n event ManagerChanged(address indexed addr, address indexed newManager);\n\n /// @notice Query if an address implements an interface and through which contract.\n /// @param _addr Address being queried for the implementer of an interface.\n /// (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// E.g., `web3.utils.keccak256('ERC777Token')`.\n /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr`\n /// or `0x0` if `_addr` did not register an implementer for this interface.\n function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n address addr = _addr == 0 ? msg.sender : _addr;\n if (isERC165Interface(_interfaceHash)) {\n bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : 0;\n }\n return interfaces[addr][_interfaceHash];\n }\n\n /// @notice Sets the contract which implements a specific interface for an address.\n /// Only the manager defined for that address can set it.\n /// (Each address is the manager for itself until it sets a new manager.)\n /// @param _addr Address to define the interface for. (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// For example, `web3.utils.keccak256('ERC777TokensRecipient')` for the `ERC777TokensRecipient` interface.\n /// @param _implementer Contract address implementing _interfaceHash for _addr.\n function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n address addr = _addr == 0 ? msg.sender : _addr;\n require(getManager(addr) == msg.sender, \"Not the manager\");\n\n require(!isERC165Interface(_interfaceHash), \"Must not be a ERC165 hash\");\n if (_implementer != 0 && _implementer != msg.sender) {\n require(\n ERC820ImplementerInterface(_implementer)\n .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC820_ACCEPT_MAGIC,\n \"Does not implement the interface\"\n );\n }\n interfaces[addr][_interfaceHash] = _implementer;\n emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n }\n\n /// @notice Sets the `_newManager` as manager for the `_addr` address.\n /// The new manager will be able to call `setInterfaceImplementer` for `_addr`.\n /// @param _addr Address for which to set the new manager.\n /// @param _newManager Address of the new manager for `addr`.\n function setManager(address _addr, address _newManager) external {\n require(getManager(_addr) == msg.sender, \"Not the manager\");\n managers[_addr] = _newManager == _addr ? 0 : _newManager;\n emit ManagerChanged(_addr, _newManager);\n }\n\n /// @notice Get the manager of an address.\n /// @param _addr Address for which to return the manager.\n /// @return Address of the manager for a given address.\n function getManager(address _addr) public view returns(address) {\n // By default the manager of an address is the same address\n if (managers[_addr] == 0) {\n return _addr;\n } else {\n return managers[_addr];\n }\n }\n\n /// @notice Compute the keccak256 hash of an interface given its name.\n /// @param _interfaceName Name of the interface.\n /// @return The keccak256 hash of an interface name.\n function interfaceHash(string _interfaceName) external pure returns(bytes32) {\n return keccak256(abi.encodePacked(_interfaceName));\n }\n\n /* --- ERC165 Related Functions --- */\n /* --- Developed in collaboration with William Entriken. --- */\n\n /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n /// @param _contract Address of the contract for which to update the cache.\n /// @param _interfaceId ERC165 interface for which to update the cache.\n function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(_contract, _interfaceId) ? _contract : 0;\n erc165Cached[_contract][_interfaceId] = true;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not.\n /// The result may be cached, if not a direct lookup is performed.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n if (!erc165Cached[_contract][_interfaceId]) {\n return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n }\n return interfaces[_contract][_interfaceId] == _contract;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n uint256 success;\n uint256 result;\n\n (success, result) = noThrowCall(_contract, ERC165ID);\n if (success == 0 || result == 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, INVALID_ID);\n if (success == 0 || result != 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, _interfaceId);\n if (success == 1 && result == 1) {\n return true;\n }\n return false;\n }\n\n /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n /// @param _interfaceHash The hash to check.\n /// @return `true` if the hash is a ERC165 interface (ending with 28 zeroes), `false` otherwise.\n function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n }\n\n /// @dev Make a call on a contract without throwing if the function does not exist.\n function noThrowCall(address _contract, bytes4 _interfaceId)\n internal view returns (uint256 success, uint256 result)\n {\n bytes4 erc165ID = ERC165ID;\n\n assembly {\n let x := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(x, erc165ID) // Place signature at beginning of empty storage\n mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n success := staticcall(\n 30000, // 30k gas\n _contract, // To addr\n x, // Inputs are stored at location x\n 0x08, // Inputs are 8 bytes long\n x, // Store output over input (saves space)\n 0x20 // Outputs are 32 bytes long\n )\n\n result := mload(x) // Load the result\n }\n }\n}\n", + "content": "/* ERC820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address\n * (contract or regular account) can register which interface it supports and\n * which smart contract is responsible for its implementation.\n *\n * Written in 2018 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright\n * and related and neighboring rights to this software to the public domain\n * worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along\n * with this software. If not, see\n * .\n *\n * ███████╗██████╗ ██████╗ █████╗ ██████╗ ██████╗\n * ██╔════╝██╔══██╗██╔════╝██╔══██╗╚════██╗██╔═████╗\n * █████╗ ██████╔╝██║ ╚█████╔╝ █████╔╝██║██╔██║\n * ██╔══╝ ██╔══██╗██║ ██╔══██╗██╔═══╝ ████╔╝██║\n * ███████╗██║ ██║╚██████╗╚█████╔╝███████╗╚██████╔╝\n * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗\n * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝\n * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝\n * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║\n * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\n *\n */\npragma solidity 0.4.24;\n// IV is value needed to have a vanity address starting with `0x820`.\n// IV: 9513\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC820ImplementerInterface {\n /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not.\n /// @param interfaceHash keccak256 hash of the name of the interface\n /// @param addr Address for which the contract will implement the interface\n /// @return ERC820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`.\n function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-820\ncontract ERC820Registry {\n /// @notice ERC165 Invalid ID.\n bytes4 constant INVALID_ID = 0xffffffff;\n /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n bytes4 constant ERC165ID = 0x01ffc9a7;\n /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n bytes32 constant ERC820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC820_ACCEPT_MAGIC\"));\n\n mapping (address => mapping(bytes32 => address)) interfaces;\n mapping (address => address) managers;\n mapping (address => mapping(bytes4 => bool)) erc165Cached;\n\n /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`.\n event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n /// @notice Indicates `newManager` is the address of the new manager for `addr`.\n event ManagerChanged(address indexed addr, address indexed newManager);\n\n /// @notice Query if an address implements an interface and through which contract.\n /// @param _addr Address being queried for the implementer of an interface.\n /// (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// E.g., `web3.utils.keccak256('ERC777Token')`.\n /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr`\n /// or `0x0` if `_addr` did not register an implementer for this interface.\n function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n address addr = _addr == 0 ? msg.sender : _addr;\n if (isERC165Interface(_interfaceHash)) {\n bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : 0;\n }\n return interfaces[addr][_interfaceHash];\n }\n\n /// @notice Sets the contract which implements a specific interface for an address.\n /// Only the manager defined for that address can set it.\n /// (Each address is the manager for itself until it sets a new manager.)\n /// @param _addr Address to define the interface for. (If `_addr == 0` then `msg.sender` is assumed.)\n /// @param _interfaceHash keccak256 hash of the name of the interface as a string.\n /// For example, `web3.utils.keccak256('ERC777TokensRecipient')` for the `ERC777TokensRecipient` interface.\n /// @param _implementer Contract address implementing _interfaceHash for _addr.\n function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n address addr = _addr == 0 ? msg.sender : _addr;\n require(getManager(addr) == msg.sender, \"Not the manager\");\n\n require(!isERC165Interface(_interfaceHash), \"Must not be a ERC165 hash\");\n if (_implementer != 0 && _implementer != msg.sender) {\n require(\n ERC820ImplementerInterface(_implementer)\n .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC820_ACCEPT_MAGIC,\n \"Does not implement the interface\"\n );\n }\n interfaces[addr][_interfaceHash] = _implementer;\n emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n }\n\n /// @notice Sets the `_newManager` as manager for the `_addr` address.\n /// The new manager will be able to call `setInterfaceImplementer` for `_addr`.\n /// @param _addr Address for which to set the new manager.\n /// @param _newManager Address of the new manager for `addr`.\n function setManager(address _addr, address _newManager) external {\n require(getManager(_addr) == msg.sender, \"Not the manager\");\n managers[_addr] = _newManager == _addr ? 0 : _newManager;\n emit ManagerChanged(_addr, _newManager);\n }\n\n /// @notice Get the manager of an address.\n /// @param _addr Address for which to return the manager.\n /// @return Address of the manager for a given address.\n function getManager(address _addr) public view returns(address) {\n // By default the manager of an address is the same address\n if (managers[_addr] == 0) {\n return _addr;\n } else {\n return managers[_addr];\n }\n }\n\n /// @notice Compute the keccak256 hash of an interface given its name.\n /// @param _interfaceName Name of the interface.\n /// @return The keccak256 hash of an interface name.\n function interfaceHash(string _interfaceName) external pure returns(bytes32) {\n return keccak256(abi.encodePacked(_interfaceName));\n }\n\n /* --- ERC165 Related Functions --- */\n /* --- Developed in collaboration with William Entriken. --- */\n\n /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n /// @param _contract Address of the contract for which to update the cache.\n /// @param _interfaceId ERC165 interface for which to update the cache.\n function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(_contract, _interfaceId) ? _contract : 0;\n erc165Cached[_contract][_interfaceId] = true;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not.\n /// The result may be cached, if not a direct lookup is performed.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n if (!erc165Cached[_contract][_interfaceId]) {\n return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n }\n return interfaces[_contract][_interfaceId] == _contract;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return `true` if `_contract` implements `_interfaceId`, false otherwise.\n function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n uint256 success;\n uint256 result;\n\n (success, result) = noThrowCall(_contract, ERC165ID);\n if (success == 0 || result == 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, INVALID_ID);\n if (success == 0 || result != 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, _interfaceId);\n if (success == 1 && result == 1) {\n return true;\n }\n return false;\n }\n\n /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n /// @param _interfaceHash The hash to check.\n /// @return `true` if the hash is a ERC165 interface (ending with 28 zeroes), `false` otherwise.\n function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n }\n\n /// @dev Make a call on a contract without throwing if the function does not exist.\n function noThrowCall(address _contract, bytes4 _interfaceId)\n internal view returns (uint256 success, uint256 result)\n {\n bytes4 erc165ID = ERC165ID;\n\n assembly {\n let x := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(x, erc165ID) // Place signature at beginning of empty storage\n mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n success := staticcall(\n 30000, // 30k gas\n _contract, // To addr\n x, // Inputs are stored at location x\n 0x08, // Inputs are 8 bytes long\n x, // Store output over input (saves space)\n 0x20 // Outputs are 32 bytes long\n )\n\n result := mload(x) // Load the result\n }\n }\n}\n", "keccak256": "0x8eecce3912a15087b3f5845d5a74af7712c93d0a8fcd6f2d40f07ed5032022ab" } }, diff --git a/EIPS/eip-884.md b/EIPS/eip-884.md index e7a58c63..87d2d414 100644 --- a/EIPS/eip-884.md +++ b/EIPS/eip-884.md @@ -10,7 +10,7 @@ created: 2018-02-14 # Delaware General Corporations Law (DGCL) compatible share token -Ref: [proposing-an-eip-for-DGCL-tokens](http://forum.ethereum.org/discussion/17200/proposing-an-eip-for-regulation-a-Tokens) +Ref: [proposing-an-eip-for-DGCL-tokens](https://forum.ethereum.org/discussion/17200/proposing-an-eip-for-regulation-a-Tokens) ## Simple Summary diff --git a/EIPS/eip-908.md b/EIPS/eip-908.md index dace932f..638f0655 100644 --- a/EIPS/eip-908.md +++ b/EIPS/eip-908.md @@ -22,7 +22,7 @@ The tragedy of the commons is a phenomenon that is well known in many sectors, m Reward mechanisms that are external to being built in to the protocol are beyond the scope of this EIP. Such extra-protocol reward methods include state channel payments for extra services such as light client servers providing faster information such as receipts; state channel payments for buying state reads from full nodes; archival services (which is only applicable to future proposed versions of Ethereum with stateless clients); and tokens for the client and running full nodes. ## Motivation -Currently there is a lack of incentives for anyone to run a full node, while joining a mining pool is not really economical if one has to purchase a mining rig (several GPUs) now, since there is unlikely to be a return on investment by the time that Ethereum transitions to hybrid Proof-of-Work/Proof-of-Stake with [Casper FFG](http://eips.ethereum.org/EIPS/eip-1011), then full PoS with [CBC Casper](https://github.com/ethereum/research/blob/master/papers/CasperTFG/CasperTFG.pdf). +Currently there is a lack of incentives for anyone to run a full node, while joining a mining pool is not really economical if one has to purchase a mining rig (several GPUs) now, since there is unlikely to be a return on investment by the time that Ethereum transitions to hybrid Proof-of-Work/Proof-of-Stake with [Casper FFG](https://eips.ethereum.org/EIPS/eip-1011), then full PoS with [CBC Casper](https://github.com/ethereum/research/blob/master/papers/CasperTFG/CasperTFG.pdf). Additionally, providing a reward for clients gives a revenue stream that is independent of state channels or other layer 2 mechanisms, which are less secure, although this insecurity can be offset by mechanisms such as insurance, bonded payments and time locks. Rationalising that investors may invest in a client because it is an enabler for the Ethereum ecosystem (and thus opening up investment opportunities) may not scale very well, and it seems that it is more sustainable to monetize the client as part of the service(s) that it provides. @@ -40,7 +40,7 @@ Implementing this as a layer 2 solution may not ensure the sustainability of the Not providing incentives for clients is an issue now as there is less incentive to build a client that aligns with the needs of users, funds need to be raised externally to the protocol to fund client development, which is not as decentralized. If only a smaller subset is able to fund client development, such as VCs, angel investors and institutional investors, that may not align well with the interests of all current and potential stakeholders of Ethereum (which includes future stakeholders). Ostensibly, one of the goals of Ethereum is to decentralize everything, including wealth, or in other words, to improve wealth equality. Not providing incentives for full nodes validating transactions may not seem like as much of an issue now, but not doing so could hinder the growth of the protocol. Of course, incentives aren't enough, it also needs to be technically decentralized so that it is ideally possible for a low-end mainstream computer or perhaps even a mobile or embedded IoT device to be a verifying full node, or at least to be able to help with securing the network if it is deemed impractical for them to be a full node. -Note that with a supply cap (as in [EIP 960](https://github.com/ethereum/EIPs/issues/960), the issuance can be prevented from increasing indefinitely. Alternatively, it could at least be reduced (still potentially but not necessarily to zero, or to the same rate at which Ether is burnt when slashing participants, such as validators under a Casper PoS scheme or notaries under a sharding scheme), e.g. by hard forks, or as per [EIP 1015](http://eips.ethereum.org/EIPS/eip-1015), an on-chain contract governed by a decision assembly that gets signalling from other contracts that represent some set of stakeholders. +Note that with a supply cap (as in [EIP 960](https://github.com/ethereum/EIPs/issues/960), the issuance can be prevented from increasing indefinitely. Alternatively, it could at least be reduced (still potentially but not necessarily to zero, or to the same rate at which Ether is burnt when slashing participants, such as validators under a Casper PoS scheme or notaries under a sharding scheme), e.g. by hard forks, or as per [EIP 1015](https://eips.ethereum.org/EIPS/eip-1015), an on-chain contract governed by a decision assembly that gets signalling from other contracts that represent some set of stakeholders. ## Specification Add a new field to each block called `PrevBlockVerifications`, which is an arbitrary, unlimited size byte array. When a client verifies that a previous block is [valid](https://ethereum.github.io/yellowpaper/paper.pdf#subsubsection.4.3.2), the client appends a user agent to PrevBlockVerifications via an opcode in a transaction, PREV_BLOCK_VERIF. The user agent is a vector with the immutable fields: the blockhash of the block that is validated, and the index of a client address in an access list (details are below). A miner validates a transaction before including it in a block, however they are not able to change these fields of the vector because they're immutable. @@ -55,9 +55,9 @@ A miner could create a client and fill their block with transactions that only c ### More details on the access list -The access list prevents anyone inserting any address to the first element of the vector, where there may be a way to prevent censorship and centralization of authority of who decides to register new addresses in the list, e.g. on-chain governance with signalling (possibly similar to [EIP 1015](http://eips.ethereum.org/EIPS/eip-1015), which also specifies an alternative way of sending funds) or a layer 2 proof of authority network where new addresses can be added via a smart contract. Note that there may be serious drawbacks to implementing either of these listed examples. There is a refutation of [on-chain governance](https://medium.com/@Vlad_Zamfir/against-on-chain-governance-a4ceacd040ca) as well as of [plutocracy](https://vitalik.ca/general/2018/03/28/plutocracy.html). [Proof of Authority](https://en.wikipedia.org/wiki/Proof-of-authority) isn't suitable for a public network since it doesn't distribute trust well. However, using signalling in layer 2 contracts is more acceptable, but Vlad Zamfir argues that using that to influence outcomes in the protocol can disenfranchise miners from being necessary participants in the governance process. Thus, in light of these counterpoints, having an access list may not be suitable until a decentralized, trustless way of maintaining it is implemented and ideally accepted by the majority of a random sample that represents the population of Ethereum users. +The access list prevents anyone inserting any address to the first element of the vector, where there may be a way to prevent censorship and centralization of authority of who decides to register new addresses in the list, e.g. on-chain governance with signalling (possibly similar to [EIP 1015](https://eips.ethereum.org/EIPS/eip-1015), which also specifies an alternative way of sending funds) or a layer 2 proof of authority network where new addresses can be added via a smart contract. Note that there may be serious drawbacks to implementing either of these listed examples. There is a refutation of [on-chain governance](https://medium.com/@Vlad_Zamfir/against-on-chain-governance-a4ceacd040ca) as well as of [plutocracy](https://vitalik.ca/general/2018/03/28/plutocracy.html). [Proof of Authority](https://en.wikipedia.org/wiki/Proof-of-authority) isn't suitable for a public network since it doesn't distribute trust well. However, using signalling in layer 2 contracts is more acceptable, but Vlad Zamfir argues that using that to influence outcomes in the protocol can disenfranchise miners from being necessary participants in the governance process. Thus, in light of these counterpoints, having an access list may not be suitable until a decentralized, trustless way of maintaining it is implemented and ideally accepted by the majority of a random sample that represents the population of Ethereum users. -However, another alternative to managing the access list would be to have decentralized verification that the address produced from querying an index in the access list does correspond to that of a "legitimate" client. Part of this verification would involve checking that there is a client that claims that this address is owned by them, that they are happy to receive funds in this manner and agree or arranged to putting the address in the access list, and that the client passes all tests in the [Ethereum test suite](https://github.com/ethereum/tests). However, this last proviso would then preclude new clients being funded from the start of development, although such would-be clients would not be able to receive funds in-protocol until they implement the client anyway (as an aside, they could raise funds in various ways—a DAII, pronounced die-yee, is recommended, while a platform for DAIIs is under development by [Dogezer](http://dogezer.com/)). All of this could be done off-chain, and if anyone found that some address in the access list was not legitimate, then they could challenge that address with a proof of illegitimacy, and the participant that submitted the address to the access list could be slashed (while they must hold a deposit in order to register and keep an address in the access list). +However, another alternative to managing the access list would be to have decentralized verification that the address produced from querying an index in the access list does correspond to that of a "legitimate" client. Part of this verification would involve checking that there is a client that claims that this address is owned by them, that they are happy to receive funds in this manner and agree or arranged to putting the address in the access list, and that the client passes all tests in the [Ethereum test suite](https://github.com/ethereum/tests). However, this last proviso would then preclude new clients being funded from the start of development, although such would-be clients would not be able to receive funds in-protocol until they implement the client anyway (as an aside, they could raise funds in various ways—a DAII, pronounced die-yee, is recommended, while a platform for DAIIs is under development by [Dogezer](https://dogezer.com/)). All of this could be done off-chain, and if anyone found that some address in the access list was not legitimate, then they could challenge that address with a proof of illegitimacy, and the participant that submitted the address to the access list could be slashed (while they must hold a deposit in order to register and keep an address in the access list). Additionally, it should help with being only able to read the client's address from the client, and the whole transaction could revert if the address is not in the access list. You could provide the index of the address in the access list, and then you could `assert` that the address found at that index matches that which can be read by the client (where the latter would be a read-only address). diff --git a/EIPS/eip-969.md b/EIPS/eip-969.md index 1c41070c..8b6301e6 100644 --- a/EIPS/eip-969.md +++ b/EIPS/eip-969.md @@ -159,7 +159,7 @@ An analysis can be done regarding the dispersion of these constants as compared `0x01000193`, using the following snippet. ``` c -// http://eips.ethereum.org/EIPS/eip-969 +// https://eips.ethereum.org/EIPS/eip-969 #include #include diff --git a/README.md b/README.md index ad7b3575..abc1aab8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # EIPs [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/EIPs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Ethereum Improvement Proposals (EIPs) describe standards for the Ethereum platform, including core protocol specifications, client APIs, and contract standards. -A browsable version of all current and draft EIPs can be found on [the official EIP site](http://eips.ethereum.org/). +A browsable version of all current and draft EIPs can be found on [the official EIP site](https://eips.ethereum.org/). # Contributing diff --git a/_layouts/eip.html b/_layouts/eip.html index 41980eee..215f5f19 100644 --- a/_layouts/eip.html +++ b/_layouts/eip.html @@ -5,7 +5,7 @@ layout: default

    EIP {{ page.eip | xml_escape }}: {{ page.title | xml_escape }} - Source + Source

    diff --git a/assets/eip-858/calculations.md b/assets/eip-858/calculations.md index b7b1ba70..e02b94fa 100644 --- a/assets/eip-858/calculations.md +++ b/assets/eip-858/calculations.md @@ -1,7 +1,7 @@ | Variable | Symbol | Value | Unit | Source | | -------------------|--------------|---------------|---------------|--------| | Network Hashrate |HN | 296000 | GH/s | https://etherscan.io/chart/hashrate | -| GPU Hashrate |HM | 31.2 | MH/s | http://www.legitreviews.com/geforce-gtx-1070-ethereum-mining-small-tweaks-great-hashrate-low-power_195451 | +| GPU Hashrate |HM | 31.2 | MH/s | https://www.legitreviews.com/geforce-gtx-1070-ethereum-mining-small-tweaks-great-hashrate-low-power_195451 | | GPU Power |PM | 110.6 | W | https://www.reddit.com/r/ethereum/comments/7vewys/10000_tons_co2_per_day_and_climbing_eip_858/dtrswyz/ | From edc38f607553a5625d11cafdf9cb48c9379d3920 Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Sun, 10 Mar 2019 08:30:44 +0100 Subject: [PATCH 093/431] Add EIP-1620 (#1722) --- EIPS/eip-1620.md | 308 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 EIPS/eip-1620.md diff --git a/EIPS/eip-1620.md b/EIPS/eip-1620.md new file mode 100644 index 00000000..fc127e91 --- /dev/null +++ b/EIPS/eip-1620.md @@ -0,0 +1,308 @@ +--- +eip: 1620 +title: ERC-1620 Money Streaming +author: Paul Berg (@PaulRBerg) +discussions-to: https://github.com/ethereum/EIPs/issues/1620 +status: Draft +type: Standards Track +category: ERC +created: 2018-11-24 +--- + + + +## Simple Summary + +Money streaming represents the idea of continuous payments over a finite period of time. Block numbers are used as a proxy of time to continuously update balances. + +## Abstract + +The following describes a standard whereby time is measured using block numbers and streams are mappings in a master contract. + +1. A provider sets up a money streaming contract. +2. A prospective payer can interact with the contract and start the stream right away by depositing the funds required for the chosen period. +3. The payee is able to withdraw money from the contract based on its ongoing solvency. That is: `payment rate * (current block height - starting block height)` +4. The stream terms (payment rate, length, metadata) can be updated at any time if both parties pledge their signatures. +5. The stream can be stopped at any point in time by any party without on-chain consensus. +6. If the stream period ended and it was not previously stopped by any party, the payee is entitled to withdraw all the deposited funds. + +## Motivation + +This standardised interface aims to change the way we think about long-term financial commitments. Thanks to blockchains, payments need not be sent in chunks (e.g. monthly salaries), as there is much less overhead in paying-as-you-go. Money as a function of time would better align incentives in a host of scenarios. + +### Use Cases + +This is just a preliminary list of use cases. There are other spooky ideas interesting to explore, such as time-dependent disincetivisation, but, for brevity, we have not included them here. + +- Salaries +- Subscriptions +- Consultancies +- CDPs +- Rent +- Parking + +### Crowdsales +[RICOs](https://github.com/lukso-network/rico), or Reversible ICOs, were introduced at Devcon4 by @frozeman. The idea is to endow investors with more power and safety guarantees by allowing them to "reverse" the investment based on the evolution of the project. We previously discussed a similar concept called SICOs, or Streamable ICOs, in this research [thread](https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928/14?u=paulrberg). + +Instead of investing a lump sum and giving the money away to the project developers, funds are held in a smart contract which allocates money based on the passage of time. Project developers can withdraw funds as the stream stays active, while investors have the power to get back a significant percentage of their initial commitment if the project halts. + +## Specification + + +
    Expand + +### Structs + +The structure of a `stream` should be as follows: + +- `stream` + - `sender`: the `address` of the entity funding the stream + - `recipient`: the `address` where the money is being delivered to + - `tokenAddress`: the `address` of the ERC20 token used as payment asset + - `balance`: the total funds left in the stream + - `timeframe`: as defined below + - `rate`: as defined below + +```solidity + struct Stream { + address sender; + address recipient; + address tokenAddress; + uint256 balance; + Timeframe timeframe; + Rate rate; + } +``` + +- `timeframe` + - `start`: the starting block number of the stream + - `stop`: the stopping block number of the stream + +```solidity +struct Timeframe { + uint256 start; + uint256 stop; +} +``` + +- `rate` + - `payment`: how much money moves from `sender` to `recipient` + - `interval`: how often `payment` moves from `sender` to `recipient` + +```solidity +struct Rate { + uint256 payment; + uint256 interval; +} +``` + +--- + +### Methods + +#### balanceOf + +Returns available funds for the given stream id and address. + +```solidity +function balanceOf(uint256 _streamId, address _addr) +``` + +#### getStream + +Returns the full stream data, if the id points to a valid stream. + +```solidity +function getStream(uint256 _streamId) returns (address sender, address recipient, address tokenAddress, uint256 balance, uint256 startBlock, uint256 stopBlock, uint256 payment, uint256 interval) +``` + +#### create + +Creates a new stream between `msg.sender` and `_recipient`. + +MUST allow senders to create multiple streams in parallel. SHOULD not accept Ether and only use ERC20-compatible tokens. + +**Triggers Event**: [LogCreate](#log-create) + +```solidity +function create(address _recipient, address _tokenAddress, uint256 _startBlock, uint256 _stopBlock, uint256 _payment, uint256 _interval) +``` + +#### withdraw + +Withdraws all or a fraction of the available funds. + +MUST allow only the recipient to perform this action. + +**Triggers Event**: [LogWithdraw](#log-withdraw) + +```solidity +function withdraw(uint256 _streamId, uint256 _funds) +``` + +#### redeem + +Redeems the stream by distributing the funds to the sender and the recipient. + +SHOULD allow any party to redeem the stream. + +**Triggers Event**: [LogRedeem](#log-redeem) + +```solidity +function redeem(uint256 _streamId) +``` + +#### confirmUpdate + +Signals one party's willingness to update the stream + +SHOULD allow any party to do this but MUST NOT be executed without consent from all involved parties. + +**Triggers Event**: [LogConfirmUpdate](#log-confirm-update) + +**Triggers Event**: [LogExecuteUpdate](#log-execute-update) when the last involved party calls this function + +```solidity +function update(uint256 _streamId, address _tokenAddress, uint256 _stopBlock, uint256 _payment, uint256 _interval) +``` + +#### revokeUpdate + +Revokes an update proposed by one of the involved parties. + +MUST allow any party to do this. + +**Triggers Event**: [LogRevokeUpdate](#log-revoke-update) + +```solidity +function confirmUpdate(uint256 _streamId, address _tokenAddress, uint256 _stopBlock, uint256 _payment, uint256 _interval) +``` + +--- + +### Events + +#### LogCreate + +MUST be triggered when `create` is successfully called. + +```solidity +event LogCreate(uint256 indexed _streamId, address indexed _sender, address indexed _recipient, address _tokenAddress, uint256 _startBlock, uint256 _stopBlock, uint256 _payment, uint256 _interval) +``` + +#### LogWithdraw + +MUST be triggered when `withdraw` is successfully called. + +```solidity +event LogWithdraw(uint256 indexed _streamId, address indexed _recipient, uint256 _funds) +``` + +#### LogRedeem + +MUST be triggered when `redeem` is successfully called. + +```solidity +event LogRedeem(uint256 indexed _streamId, address indexed _sender, address indexed _recipient, uint256 _senderBalance, uint256 _recipientBalance) +``` + +#### LogConfirmUpdate + +MUST be triggered when `confirmUpdate` is successfully called. + +```solidity +event LogConfirmUpdate(uint256 indexed _streamId, address indexed _confirmer, address _newTokenAddress, uint256 _newStopBlock, uint256 _newPayment, uint256 _newInterval); +``` + +#### LogRevokeUpdate + +MUST be triggered when `revokeUpdate` is successfully called. + +```solidity +event LogRevokeUpdate(uint256 indexed _streamId, address indexed revoker, address _newTokenAddress, uint256 _newStopBlock, uint256 _newPayment, uint256 _newInterval) +``` + +#### LogExecuteUpdate + +MUST be triggered when an update is approved by all involved parties. + +```solidity +event LogExecuteUpdate(uint256 indexed _newStreamId, address indexed _sender, address indexed _recipient, address _newTokenAddress, uint256 _newStopBlock, uint256 _newPayment, uint256 _newInterval) +``` + +
    + +## Rationale + + +This specification was designed to serve as an entry point to the quirky concept of money as a function of time and it is definitely not set in stone. Several other designs, including payment channels and Plasma chains were also considered, but they were eventually deemed dense in assumptions unnecessary for an initial version. + + + +Block times are a reasonable, trustless proxy for time on the blockchain. Between 2016 and 2018, the Ethereum block time average value [hovered](https://etherscan.io/chart/blocktime) around 14 seconds, excluding the last two quarters of 2017. Mathematically speaking, it would be ideal to have a standard deviation as close to 0 as possible, but that is not how things work in the real world. This has huge implications on the feasibility of this ERC which we shall investigate below. + +### GCD +When setting up a stream, a payer and a payee may want to make the total streaming duration a multiple of the "greatest common denominator" (GCD) of the chain they operate on; that is, the average block time. This is not imperative in the smart contracts per se, but there needs to be an off-chain process to map streams to real world time units in order to create a sound and fair payment mechanism. + +### Block Times +Because there is uncertainty regarding block times, streams may not be settled on the blockchain as initially planned. Let `$d` be the total streaming duration measured in seconds, `$t` the average block time before the stream started and `$t'` the actual average block time over `$d` after the stream started. We distinguish two undesirable scenarios: + +1. `$t` < `$t'`: the payee will get their funds *later* than expected + +2. `$t` > `$t'`: the payee will get their funds *sooner* than expected + +If the combined error delta is smaller than the payment rate (fifth parameter of the `create` method, measured in wei), there is no problem at all. Conversely, we stumble upon trust issues because real-world time frames do not correspond to the stream terms. For instance, if an employee is normally entitled to withdraw all the funds from the stream at the end of the month, but block times cause case 1 from above to occur, the employee is in a financial disadvantage because their continuous effort is not compensated as promised. + +Limiting the problem scope only to Ethereum, we propose two remedies: + +1. Consensus on calling the `update` function to correct the stream terms. This might sound preposterous, but in most cases the stakes are low and stream participants are involved in long-term financial commitments. There is a high disincentive to refuse to cooperate. + +2. Autonomously fix significant error deltas. In theory, we could achieve this using previous blocks' timestamps, "checkpointing" the stream once in a predefined number of blocks. This is still an area of active research because of potentially high overheads in gas costs. + +Nonetheless, it is important to note that this is still a major improvement on the traditional model where absolute trust is required. + +### Sidechains + +It could be more efficient to implement this standard on independent sidechains like [POA Network](https://poa.network) or [xDai](https://medium.com/poa-network/poa-network-partners-with-makerdao-on-xdai-chain-the-first-ever-usd-stable-blockchain-65a078c41e6a) - thanks to their rather predictable nature. Admittedly, security is traded for scalability, but proper cryptoeconomic stakes could alleviate potential problems. + +Furthermore, it is intriguing to explore the prospect of stream-specific sidechains. + +### Oracles + +The proposed specification uses block numbers to proxy time, but this need not be the only method. Albeit it would imply different trust assumptions, oracles could be used to provide a feed of timestamps. Coupled with the aforementioned idea of stream-specific sidechains, oracles could efficiently solve the problems outlined in [Block Times](#block-times). + +### Multi-Hop Streams + +Future or upgraded versions of this standard may describe "multi-hop" streams. If: + +1. There is a stream between A and B +2. There is another stream between B and C + +There could be a way to avoid running two different streams in parallel. That is, a fraction or all of the funds being streamed from A to B could be automatically wired to C. An interesting use case for this is taxes. Instead of manually moving money around, proactively calculating how much you owe and then transfer it, a stream could atomically perform those operations for you. + +## Implementation + + +- [ChronosProtocol WIP implementation](https://github.com/ChronosProtocol/monorepo) + +## Additional References +- [Chronos Protocol Ethresear.ch Plasma Proposal](https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928?u=paulrberg) +- [Chronos Protocol White Paper](http://chronosprotocol.org/chronos-white-paper.pdf) +- [Flipper: Streaming Salaries @ CryptoLife Hackathon](https://devpost.com/software/flipper-3gvl4b) +- [SICOs or Streamed ICOs](https://ethresear.ch/t/chronos-a-quirky-application-proposal-for-plasma/2928/14?u=paulrberg) +- [RICOs or Reversible ICOs](https://twitter.com/feindura/status/1058057076306518017) +- [Andreas Antonopoulos' Keynote on Bitcoin, Lightning and Money Streaming](https://www.youtube.com/watch?v=gF_ZQ_eijPs) + +## Final Notes + +Many thanks to @mmilton41 for countless brainstorming sessions. We have been doing research on the topic of money streaming for quite a while within the context of @ChronosProtocol. In August this year, we published the first version of our white paper describing a Plasma approach. However, in the meantime, we realised that it would be much more [fun](https://twitter.com/PaulRBerg/status/1056595919116910592) and easier to start small on Ethereum itself and sidechains like [xDai](https://blockscout.com/poa/dai). + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file From a34278a50552dae107271d6284911698d49c757a Mon Sep 17 00:00:00 2001 From: Pelle Braendgaard Date: Sun, 10 Mar 2019 10:56:38 -0400 Subject: [PATCH 094/431] Ethereum Verifiable Claims (#1812) --- EIPS/eip-1812.md | 442 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 EIPS/eip-1812.md diff --git a/EIPS/eip-1812.md b/EIPS/eip-1812.md new file mode 100644 index 00000000..11d4bd47 --- /dev/null +++ b/EIPS/eip-1812.md @@ -0,0 +1,442 @@ +--- +eip: 1812 +title: Ethereum Verifiable Claims +author: Pelle Braendgaard <@pelle> +discussions-to: https://ethereum-magicians.org/t/erc-1812-ethereum-verifiable-claims/2814 +status: Draft +type: Standards Track +category: ERC +created: 2019-03-03 +requires: 712 +--- + +# Ethereum Verifiable Claims + +## Simple Summary + +Reusable Verifiable Claims using [EIP 712 Signed Typed Data](https://github.com/ethereum/EIPs/issues/712). + +## Abstract +A new method for Off-Chain Verifiable Claims built on [EIP 712](https://github.com/ethereum/EIPs/issues/712). These Claims can be issued by any user with a EIP 712 compatible web3 provider. Claims can be stored off chain and verified on-chain by Solidity Smart Contracts, State Channel Implementations or off-chain libraries. + +## Motivation +Reusable Off-Chain Verifiable Claims provide an important piece of integrating smart contracts with real world organizational requirements such as meeting regulatory requirements such as KYC, GDPR, Accredited Investor rules etc. + +[ERC 735](https://github.com/ethereum/EIPs/issues/735) and [ERC 780](https://github.com/ethereum/EIPs/issues/780) provide methods of making claims that live on chain. This is useful for some particular use cases, where some claim about an address must be verified on chain. + +In most cases though it is both dangerous and in some cases illegal (according to EU GDPR rules for example) to record Identity Claims containing Personal Identifying Information (PII) on an immutable public database such as the Ethereum blockchain. + +The W3C [Verifiable Claims Data Model and Representations](https://www.w3.org/TR/verifiable-claims-data-model/) as well as uPorts [Verification Message Spec](https://developer.uport.me/messages/verification) are proposed off-chain solutions. + +While built on industry standards such as [JSON-LD](https://json-ld.org) and [JWT](https://jwt.io) neither of them are easy to integrate with the Ethereum ecosystem. + +[EIP 712](https://eips.ethereum.org/EIPS/eip-712) introduces a new method of signing off chain Identity data. This provides both a data format based on Solidity ABI encoding that can easily be parsed on-chain an a new JSON-RPC call that is easily supported by existing Ethereum wallets and Web3 clients. + +This format allows reusable off-chain Verifiable Claims to be cheaply issued to users, who can present them when needed. + +## Prior Art +Verified Identity Claims such as those proposed by [uPort](https://developer.uport.me/messages/verification) and [W3C Verifiable Claims Working Group](https://www.w3.org/2017/vc/WG/) form an important part of building up reusable identity claims. + +[ERC 735](https://github.com/ethereum/EIPs/issues/735) and [ERC 780](https://github.com/ethereum/EIPs/issues/780) provide on-chain storage and lookups of Verifiable Claims. + +## Specification +### Claims +Claims can be generalized like this: + +> Issuer makes the claim that Subject is something or has some attribute and value. + +Claims should be deterministic, in that the same claim signed multiple times by the same signer. + +### Claims data structure +Each claim should be typed based on its specific use case, which EIP 712 lets us do effortlessly. But there are 3 minimal attributes required of the claims structure. + +* `subject` the subject of the claim as an `address` (who the claim is about) +* `validFrom` the time in seconds encoded as a `uint256` of start of validity of claim. In most cases this would be the time of issuance, but some claims may be valid in the future or past. +* `validTo` the time in seconds encoded as a `uint256` of when the validity of the claim expires. If you intend for the claim not to expire use `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`. + +The basic minimal claim data structure as a Solidity struct: + +```solidity +struct [CLAIM TYPE] { + address subject; + uint256 validFrom; + uint256 validTo; +} +``` + +The CLAIM TYPE is the actual name of the claim. While not required, in most cases use the taxonomy developed by [schema.org](https://schema.org/docs/full.html) which is also commonly used in other Verifiable Claims formats. + +Example claim that issuer knows a subject: + +```solidity +struct Know { + address subject; + uint256 validFrom; + uint256 validTo; +} +``` + +### Presenting a Verifiable Claim +#### Verifying Contract +When defining Verifiable Claims formats a Verifying Contract should be created with a public `verify()` view function. This makes it very easy for other smart contracts to verify a claim correctly. + +It also provides a convenient interface for web3 and state channel apps to verify claims securely. + +```solidity +function verifyIssuer(Know memory claim, uint8 v, bytes32 r, bytes32 s) public returns (address) { + bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR, + hash(claim) + ) + ); + require( + (claim.validFrom >= block.timestamp) && (block.timestamp < claim.validTo) +, "invalid issuance timestamps"); + return ecrecover(digest, v, r, s); +} +``` + +#### Calling a SmartContract function +Verifiable Claims can be presented to a solidity function call as it’s struct together with the `v`, `r` and `s` signature components. + +```solidity +function vouch(Know memory claim, uint8 v, bytes32 r, bytes32 s) public returns (bool) { + address issuer = verifier.verifyIssuer(claim, v, r, s); + require(issuer !== '0x0'); + knows[issuer][claim.subject] = block.number; + return true; +} +``` + +#### Embedding a Verifiable Claim in another Signed Typed Data structure +The Claim struct should be embedded in another struct together with the `v`, `r` and `s` signature parameters. + +```solidity +struct Know { + address subject; + uint256 validFrom; + uint256 validTo; +} + +struct VerifiableReference { + Know delegate; + uint8 v; + bytes32 r; + bytes32 s; +} + +struct Introduction { + address recipient; + VerifiableReference issuer; +} +``` + +Each Verifiable Claim should be individually verified together with the parent Signed Typed Data structure. + +Verifiable Claims issued to different EIP 712 Domains can be embedded within each other. + +#### State Channels +This proposal will not show how to use Eth Verifiable Claims as part of a specific State Channel method. + +Any State Channel based on EIP712 should be able to include the embeddable Verifiable Claims as part of its protocol. This could be useful for exchanging private Identity Claims between the parties for regulatory reasons, while ultimately not posting them to the blockchain on conclusion of a channel. + +### Key Delegation +In most simple cases the issuer of a Claim is the signer of the data. There are cases however where signing should be delegated to an intermediary key. + +KeyDelegation can be used to implement off chain signing for smart contract based addresses, server side key rotation as well as employee permissions in complex business use cases. + +#### ERC1056 Signing Delegation + +[ERC-1056](https://github.com/ethereum/EIPs/issues/1056) provides a method for addresses to assign delegate signers. One of the primary use cases for this is that a smart contract can allow a key pair to sign on its behalf for a certain period. It also allows server based issuance tools to institute key rotation. + +To support this an additional `issuer` attribute can be added to the Claim Type struct. In this case the verification code should lookup the EthereumDIDRegistry to see if the signer of the data is an allowed signing delegate for the `issuer` + +The following is the minimal struct for a Claim containing an issuer: + +```solidity +struct [CLAIM TYPE] { + address subject; + address issuer; + uint256 validFrom; + uint256 validTo; +} +``` + +If the `issuer` is specified in the struct In addition to performing the standard ERC712 verification the verification code MUST also verify that the signing address is a valid `veriKey` delegate for the address specified in the issuer. + +```solidity +registry.validDelegate(issuer, 'veriKey', recoveredAddress) +``` + + +#### Embedded Delegation Proof +There may be applications, in particularly where organizations want to allow delegates to issue claims about specific domains and types. + +For this purpose instead of the `issuer` we allow a special claim to be embedded following this same format: + +```solidity +struct Delegate { + address issuer; + address subject; + uint256 validFrom; + uint256 validTo; +} + +struct VerifiableDelegate { + Delegate delegate; + uint8 v; + bytes32 r; + bytes32 s; +} + + +struct [CLAIM TYPE] { + address subject; + VerifiedDelegate issuer; + uint256 validFrom; + uint256 validTo; +} +``` + +Delegates should be created for specific EIP 712 Domains and not be reused across Domains. + +Implementers of new EIP 712 Domains can add further data to the `Delegate` struct to allow finer grained application specific rules to it. + +### Claim Types +#### Binary Claims +A Binary claim is something that doesn’t have a particular value. It either is issued or not. + +Examples: +* subject is a Person +* subject is my owner (eg. Linking an ethereum account to an owner identity) + +Example: + +```solidity +struct Person { + address issuer; + address subject; + uint256 validFrom; + uint256 validTo; +} +``` + +This is exactly the same as the minimal claim above with the CLAIM TYPE set to [Person](https://schema.org/Person). + +### Value Claims +Value claims can be used to make a claim about the subject containing a specific readable value. + +**WARNING**: Be very careful about using Value Claims as part of Smart Contract transactions. Identity Claims containing values could be a GDPR violation for the business or developer encouraging a user to post it to a public blockchain. + +Examples: +* subject’s name is Alice +* subjects average account balance is 1234555 + +Each value should use the `value` field to indicate the value. + +A Name Claim + +```solidity +struct Name { + address issuer; + address subject; + string name; + uint256 validFrom; + uint256 validTo; +} +``` + +Average Balance + +```solidity +struct AverageBalance { + address issuer; + address subject; + uint256 value; + uint256 validFrom; + uint256 validTo; +} +``` + +### Hashed Claims +Hashed claims can be used to make a claim about the subject containing the hash of a claim value. Hashes should use ethereum standard `keccak256` hashing function. + +**WARNING**: Be very careful about using Hashed Claims as part of Smart Contract transactions. Identity Claims containing hashes of known values could be a GDPR violation for the business or developer encouraging a user to post it to a public blockchain. + +Examples: +- [ ] hash of subject’s name is `keccak256(“Alice Torres”)` +- [ ] hash of subject’s email is `keccak256(“alice@example.com”)` + +Each value should use the `keccak256 ` field to indicate the hashed value. Question. The choice of using this name is that we can easily add support for future algorithms as well as maybe zkSnark proofs. + +A Name Claim + +```solidity +struct Name { + address issuer; + address subject; + bytes32 keccak256; + uint256 validFrom; + uint256 validTo; +} +``` + +Email Claim + +```solidity +struct Email { + address issuer; + address subject; + bytes32 keccak256; + uint256 validFrom; + uint256 validTo; +} +``` + +### EIP 712 Domain +The EIP 712 Domain specifies what kind of message that is to be signed and is used to differentiate between signed data types. The content MUST contain the following: + +```solidity +{ + name: "EIP1???Claim", + version: 1, + chainId: 1, // for mainnet + verifyingContract: 0x // TBD + salt: ... +} +``` + +#### Full Combined format for EIP 712 signing: + +Following the EIP 712 standard we can combine the Claim Type with the EIP 712 Domain and the claim itself (in the `message`) attribute. + +Eg: +```solidity + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Email": [ + { + "name": "subject", + "type": "address" + }, + { + "name": "keccak256", + "type": "bytes32" + }, + { + "name": "validFrom", + "type": "uint256" + }, + { + "name": "validTo", + "type": "uint256" + } + ] + }, + "primaryType": "Email", + "domain": { + "name": "EIP1??? Claim", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "subject": "0x5792e817336f41de1d8f54feab4bc200624a1d9d", + "value": "9c8465d9ae0b0bc167dee7f62880034f59313100a638dcc86a901956ea52e280", + "validFrom": "0x0000000000000000000000000000000000000000000000000001644b74c2a0", + "validTo": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + } +``` + + +### Revocation +Both Issuers and Subjects should be allowed to revoke Verifiable Claims. Revocations can be handled through a simple on-chain registry. + +The ultimate rules of who should be able to revoke a claim is determined by the Verifying contract. + +The `digest` used for revocation is the EIP712 Signed Typed Data digest. + +```solidity +contract RevocationRegistry { + mapping (bytes32 => mapping (address => uint)) public revocations; + + function revoke(bytes32 digest) public returns (bool) { + revocations[digest][msg.sender] = block.number; + return true; + } + + function revoked(address party, bytes32 digest) public view returns (bool) { + return revocations[digest][party] > 0; + } +} +``` + +A verifying contract can query the Revocation Registry as such: + +```solidity +bytes32 digest = keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR, + hash(claim) + ) +); +require(valid(claim.validFrom, claim.validTo), "invalid issuance timestamps"); +address issuer = ecrecover(digest, v, r, s); +require(!revocations.revoked(issuer, digest), "claim was revoked by issuer"); +require(!revocations.revoked(claim.subject, digest), "claim was revoked by subject"); +``` + +### Creation of Verifiable Claims Domains + +Creating specific is Verifiable Claims Domains is out of the scope of this EIP. The Example Code has a few examples. + +EIP’s or another process could be used to standardize specific important Domains that are universally useful across the Ethereum world. + +## Rationale +Signed Typed Data provides a strong foundation for Verifiable Claims that can be used in many different kinds of applications built on both Layer 1 and Layer 2 of Ethereum. + +### Rationale for using not using a single EIP 712 Domain +EIP712 supports complex types and domains in itself, that we believe are perfect building blocks for building Verifiable Claims for specific purposes. + +The Type and Domain of a Claim is itself an important part of a claim and ensures that Verifiable Claims are used for the specific purposes required and not misused. + +EIP712 Domains also allow rapid experimentation, allowing taxonomies to be built up by the community. + +## Test Cases +There is a repo with a few example verifiers and consuming smart contracts written in Solidity: + +**Example Verifiers** +* [Verifier for very simple IdVerification Verifiable Claims containing minimal Personal Data](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/IdentityClaimsVerifier.sol) +* [Verifier for OwnershipProofs signed by a users wallet](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/OwnershipProofVerifier.sol) + +**Example Smart Contracts** +* [KYCCoin.sol](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/KYCCoin.sol) - Example Token allows reusable IdVerification claims issued by trusted verifiers and users to whitelist their own addresses using OwnershipProofs +* [ConsortiumAgreement.sol](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/ConsortiumAgreements.sol) - Example Consortium Agreement smart contract. Consortium Members can issue Delegated Claims to employees or servers to interact on their behalf. + +**Shared Registries** +* [RevocationRegistry.sol](https://github.com/uport-project/eip712-claims-experiments/blob/master/contracts/RevocationRegistry.sol) + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/_). From 68aff6be02b4d28a3ac5383e13dc3ee02782e679 Mon Sep 17 00:00:00 2001 From: Philippe Castonguay Date: Mon, 11 Mar 2019 12:12:10 -0400 Subject: [PATCH 095/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index cf6df776..50b07341 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -43,9 +43,9 @@ pragma solidity ^0.5.2; interface ERC1155 /* is ERC165 */ { /** @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning. - Operator will always be msg.sender. - Either event from address `0x0` signifies a minting operation. - An event to address `0x0` signifies a burning or melting operation. + Operator MUST be msg.sender. + When minting/creating tokens, the `_from` field MUST be set to `0x0` + When burning/destroying tokens, the `_to` field MUST be set to `0x0` The total value transferred from address 0x0 minus the total value transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ @@ -53,9 +53,9 @@ interface ERC1155 /* is ERC165 */ { /** @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning. - Operator will always be msg.sender. - Either event from address `0x0` signifies a minting operation. - An event to address `0x0` signifies a burning or melting operation. + Operator MUST be msg.sender. + When minting/creating tokens, the `_from` field MUST be set to `0x0` + When burning/destroying tokens, the `_to` field MUST be set to `0x0` The total value transferred from address 0x0 minus the total value transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ @@ -119,7 +119,7 @@ interface ERC1155 /* is ERC165 */ { @notice Get the balance of multiple account/token pairs @param _owners The addresses of the token holders @param _ids ID of the Tokens - @return The _owner's balance of the Token types requested + @return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair) */ function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory); @@ -503,4 +503,4 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok - [Beyond Gaming - Exploring the Utility of ERC-1155 Token Standard!](https://blockgeeks.com/erc-1155-token/) ## Copyright -Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From abab38735a842bc28f8fbe9aa994522aad060a02 Mon Sep 17 00:00:00 2001 From: Witek Date: Mon, 11 Mar 2019 12:53:01 -0700 Subject: [PATCH 096/431] ERC-1761 Scoped Approval Interface (#1839) --- EIPS/eip-1761.md | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 EIPS/eip-1761.md diff --git a/EIPS/eip-1761.md b/EIPS/eip-1761.md new file mode 100644 index 00000000..41596de7 --- /dev/null +++ b/EIPS/eip-1761.md @@ -0,0 +1,175 @@ +--- +eip: 1761 +title: ERC-1761 Scoped Approval Interface +author: Witek Radomski , Andrew Cooke , James Therien , Eric Binet +type: Standards Track +category: ERC +status: Draft +created: 2019-02-18 +discussions-to: https://github.com/ethereum/EIPs/issues/1761 +requires: 165 +--- + +## Simple Summary + +A standard interface to permit restricted approval in token contracts by defining "scopes" of one or more Token IDs. + +## Abstract + +This interface is designed for use with token contracts that have an "ID" domain, such as ERC-1155 or ERC-721. This enables restricted approval of one or more Token IDs to a specific "scope". When considering a smart contract managing tokens from multiple different domains, it makes sense to limit approvals to those domains. Scoped approval is a generalization of this idea. Implementors can define scopes as needed. + +Sample use cases for scopes: + +* A company may represent it's fleet of vehicles on the blockchain and it could create a scope for each regional office. +* Game developers could share an [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) contract where each developer manages tokens under a specified scope. +* Tokens of different value could be split into separate scopes. High-value tokens could be kept in smaller separate scopes while low-value tokens might be kept in a shared scope. Users would approve the entire low-value token scope to a third-party smart contract, exchange, or other application without concern about losing their high-value tokens in the event of a problem. + +## Motivation + +It may be desired to restrict approval in some applications. Restricted approval can prevent losses in cases where users do not audit the contracts they're approving. No standard API is supplied to manage scopes as this is implementation specific. Some implementations may opt to offer a fixed number of scopes, or assign a specific set of scopes to certain types. Other implementations may open up scope configuration to its users and offer methods to create scopes and assign IDs to them. + +# Specification + +```solidity +pragma solidity ^0.5.2; + +/** + Note: The ERC-165 identifier for this interface is 0x30168307. +*/ +interface ScopedApproval { + /** + @dev MUST emit when approval changes for scope. + */ + event ApprovalForScope(address indexed _owner, address indexed _operator, bytes32 indexed _scope, bool _approved); + + /** + @dev MUST emit when the token IDs are added to the scope. + By default, IDs are in no scope. + The range is inclusive: _idStart, _idEnd, and all IDs in between have been added to the scope. + _idStart must be lower than or equal to _idEnd. + */ + event AddIdsToScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); + + /** + @dev MUST emit when the token IDs are removed from the scope. + The range is inclusive: _idStart, _idEnd, and all IDs in between have been removed from the scope. + _idStart must be lower than or equal to _idEnd. + */ + event RemoveIdsFromScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); + + /** @dev MUST emit when a scope URI is set or changes. + URIs are defined in RFC 3986. + The URI MUST point a JSON file that conforms to the "Scope Metadata JSON Schema". + */ + event ScopeURI(string _value, bytes32 indexed _scope); + + /** + @notice Returns the number of scopes that contain _id. + @param _id The token ID + @return The number of scopes containing the ID + */ + function scopeCountForId(uint256 _id) public view returns (uint32); + + /** + @notice Returns a scope that contains _id. + @param _id The token ID + @param _scopeIndex The scope index to query (valid values are 0 to scopeCountForId(_id)-1) + @return The Nth scope containing the ID + */ + function scopeForId(uint256 _id, uint32 _scopeIndex) public view returns (bytes32); + + /** + @notice Returns a URI that can be queried to get scope metadata. This URI should return a JSON document containing, at least the scope name and description. Although supplying a URI for every scope is recommended, returning an empty string "" is accepted for scopes without a URI. + @param _scope The queried scope + @return The URI describing this scope. + */ + function scopeUri(bytes32 _scope) public view returns (string memory); + + /** + @notice Enable or disable approval for a third party ("operator") to manage the caller's tokens in the specified scope. + @dev MUST emit the ApprovalForScope event on success. + @param _operator Address to add to the set of authorized operators + @param _scope Approval scope (can be identified by calling scopeForId) + @param _approved True if the operator is approved, false to revoke approval + */ + function setApprovalForScope(address _operator, bytes32 _scope, bool _approved) external; + + /** + @notice Queries the approval status of an operator for a given owner, within the specified scope. + @param _owner The owner of the Tokens + @param _operator Address of authorized operator + @param _scope Scope to test for approval (can be identified by calling scopeForId) + @return True if the operator is approved, false otherwise + */ + function isApprovedForScope(address _owner, address _operator, bytes32 _scope) public view returns (bool); +} +``` + +## Scope Metadata JSON Schema + +This schema allows for localization. `{id}` and `{locale}` should be replaced with the appropriate values by clients. + +```json +{ + "title": "Scope Metadata", + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Identifies the scope in a human-readable way.", + }, + "description": { + "type": "string", + "description": "Describes the scope to allow users to make informed approval decisions.", + }, + "localization": { + "type": "object", + "required": ["uri", "default", "locales"], + "properties": { + "uri": { + "type": "string", + "description": "The URI pattern to fetch localized data from. This URI should contain the substring `{locale}` which will be replaced with the appropriate locale value before sending the request." + }, + "default": { + "type": "string", + "description": "The locale of the default data within the base JSON" + }, + "locales": { + "type": "array", + "description": "The list of locales for which data is available. These locales should conform to those defined in the Unicode Common Locale Data Repository (http://cldr.unicode.org/)." + } + } + } + } +} +``` + +### Localization + +Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. + +## Rationale + +The initial design was proposed as an extension to ERC-1155: [Discussion Thread - Comment 1](https://github.com/ethereum/EIPs/issues/1155#issuecomment-459505728). After some discussion: [Comment 2](https://github.com/ethereum/EIPs/issues/1155#issuecomment-460603439) and suggestions by the community to implement this approval mechanism in an external contract [Comment 3](https://github.com/ethereum/EIPs/issues/1155#issuecomment-461758755), it was decided that as an interface standard, this design would allow many different token standards such as ERC-721 and ERC-1155 to implement scoped approvals without forcing the system into all implementations of the tokens. + +### Metadata JSON + +The Scope Metadata JSON Schema was added in order to support human-readable scope names and descriptions in more than one language. + +## References + +**Standards** +- [ERC-1155 Multi Token Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) +- [ERC-165 Standard Interface Detection](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md) +- [JSON Schema](http://json-schema.org/) + +**Implementations** +- [Enjin Coin](https://enjincoin.io) ([github](https://github.com/enjin)) + +**Articles & Discussions** +- [Github - Original Discussion Thread](https://github.com/ethereum/EIPs/issues/1761) +- [Github - ERC-1155 Discussion Thread](https://github.com/ethereum/EIPs/issues/1155) + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 9ce2e5f657ba17dc4ec52e0536caa63693e59916 Mon Sep 17 00:00:00 2001 From: Witek Date: Tue, 12 Mar 2019 02:17:08 -0700 Subject: [PATCH 097/431] Status changed to Last Call for ERC-1155 (#1841) --- EIPS/eip-1155.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 50b07341..e289d8a6 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -4,7 +4,8 @@ title: ERC-1155 Multi Token Standard author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet type: Standards Track category: ERC -status: Draft +status: Last Call +review-period-end: 2019-03-28 created: 2018-06-17 discussions-to: https://github.com/ethereum/EIPs/issues/1155 requires: 165 From 963795f3239b05ff764fd735d8f98eeb0eff4da7 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Tue, 12 Mar 2019 16:00:34 -0400 Subject: [PATCH 098/431] Show review end date on website (#1842) --- _layouts/eip.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_layouts/eip.html b/_layouts/eip.html index 215f5f19..7362e167 100644 --- a/_layouts/eip.html +++ b/_layouts/eip.html @@ -12,7 +12,11 @@ layout: default {% if page["discussions-to"] != undefined %}
    {% endif %} - + {% if page.category != undefined %} From d432c8278ad7ce867c10c182b46fcee71858219f Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 13 Mar 2019 03:54:49 -0400 Subject: [PATCH 099/431] EIP-1418 Blockchain Storage Rent Payment (#1752) --- EIPS/eip-1418.md | 186 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 EIPS/eip-1418.md diff --git a/EIPS/eip-1418.md b/EIPS/eip-1418.md new file mode 100644 index 00000000..6289137a --- /dev/null +++ b/EIPS/eip-1418.md @@ -0,0 +1,186 @@ +--- +eip: 1418 +title: Blockchain Storage Rent Payment +author: William Entriken <@fulldecent> +discussions-to: https://github.com/ethereum/EIPs/issues/1418 +status: Draft +type: Standards Track +category: Core +created: 2018-09-16 +--- + +# Simple Summary + +At each block, deduct an amount of value from every account based on the quantity of storage used by that account. + +# Abstract + +The most naive implementation would be to simply loop through every account on each block and deduct a certain fee. We show that a better implementation could achieve reasonable performance. Also we review practical considerations of switching to a fee-based rent system. + +In other words, `product=0; while(factor1--)product+= factor2;` is slow, but equivalently `product = factor1 * factor2` is fast. And we can reason about both at the same time. + +# Motivation + +Ethereum is a public utility and we are underpricing the long-term costs of storage. Storage cost can be approximately modeled as bytes × time. + +# Specification + +**New state variables (per account)** + +* rent -- σ[a]_r -- an amount of value, in Wei +* rentLastPaid -- σ[a]_p -- a block number that is set when: + * Value is transferred into an account + * Code is set for an account (CREATE) + * An account's storage is updated (SSTORE) +* storageWords -- σ[a]_w -- number of words in storage +* rentEvictBlock -- σ[a]_e -- the block number when this account will be destructed + * Note: it is possible that a client could implement the Yellow Paper without storing this value explicitly. It can be calculated simply on demand. + +**New constants** + +* RENT_WORD_COST -- The rent cost, in Wei, paid for each word-block +* RENT_ACCOUNT_COST -- The rent cost, in Wei, paid for each account-block +* RENT_STIPEND -- The amount of rent, in Wei, given to accounts when touched + +**New opcodes** + +* RENTBALANCE(address) -- G_BALANCE -- Similar to BALANCE +* SENDRENT(address, amount) -- G_BASE -- Convert value to rent and send to account + 1. σ[account]_rent += amount + 2. σ[msg.sender]_balance -= amount + +**Updated opcodes** + +A new subroutine, paying for rent, is established as such: + +```pseudocode +PAYRENT(account) + ASSERT(σ[account]_rentEviction >= NUMBER) // TODO: I'm not sure if should be > or >= + blocks_to_pay = NUMBER - σ[account]_rentLastPaid + cost_per_block = RENT_ACCOUNT_COST + RENT_WORD_COST * ⌈∥σ[account]_code∥ / 32⌉ + RENT_WORD_COST * σ[a]_storageWords + rent_to_pay = blocks_to_pay * cost_per_block + σ[account]_rent -= rent_to_pay + σ[account]_rentLastPaid = NUMBER + σ[account]_rentEvictBlock = NUMBER + ⌊σ[account]_rent / cost_per_block⌋ +END PAYRENT +``` + +* SSTORE(account, key, value) + * Perform PAYRENT(account) + * Set σ[account]_rent = MAX(σ[account]_rent, RENT_STIPEND) + * Do normal SSTORE operation + * If the old value was zero for this [account, key] and the new value is non-zero, then σ[account]_storageSize++ + * If the old value was non-zero for this [account, key] and the new value is zero, then σ[account]_storageSize-- +* CALL (and derivatives) + * If value > 0 then perform PAYRENT(account) + * Do normal CALL operation +* CREATE + * Set σ[account]_rent = MAX(σ[account]_rent, RENT_STIPEND) + * Set σ[account]_rentLastPaid = HEIGHT + * Do normal CREATE operation + * Note: it is possible there is a pre-existing rent balance here + +**Updated substate** + +The substate tuple is defined as: + +> A ≡ (As, Al, At, Ar) + +This includes A_t, "the set of touched accounts, of which the empty ones are deleted at the end of a transaction". + +This definition is updated to: "the set of touched accounts, of which the empty ones or evicted ones (BLOCK >= σ[a]_rentEvictBlock) are deleted at the end of a transaction" + +// TODO: I'm not sure if that should be > or >= + +**New built-in contract** + +* PAYRENT(address, amount) -- Calls PAYRENT opcode + +*This is a convenience for humans to send Ether from their accounts and turn it into rent. Note that simple accounts (CODESIZE == 0) cannot call arbitrary opcodes, they can only call CREATE or CALL.* + +The gas cost of PAYRENT will be 10,000. + +**No changes to current opcode gas costs.** + +# Rationale + +**No call** + +A contract will not know or react to the receipt of rent. This is okay. Workaround: if a contract really needed to know who provided rent payments then it could create a function in its ABI to attribute these payments. It is already possible to send payments to a contract without attribution by using SELFDESTRUCT. + +**Eviction responsibility / lazy evaluation** + +The specification gives responsibility for eviction to the consensus clients. This is the most predictable behavior because it happens exactly when it should. Also there need not be any incentive mechanism (refund gas, bounty) for outside participants (off chain) to monitor accounts and request removal. + +This adds a computational responsibility to the clients to track eviction dates. This is possible in efficient time (at double the memory) using a double-ended priority queue (one for addressing by account address, the other for addressing by eviction date). There may be other ways of implementing this with different time-memory guarantees. + +**No converting rent to value** + +Ether converted to rent cannot be converted back. Anybody that works in accounting and knows about gifts cards should tell you this is a good idea. It makes reasoning about the system much easier. + +**Accounts pay rent** + +Yes, they pay rent. It costs money to keep their balances so we charge them rent. + +**You can lose all your money** + +Yes, if you do not pay rent for your account or contract then you lose it all. User education is required. + +Alternative: spend value (Ether balance) when rent is depleted + * Rename rentEvictBlock to rentUsingValueBlock + * Update eviction calculation to include RENT + VALUE. Also update CALL (and friends) operations to recalculate eviction date when value is transferred. This is the new rentEvictBlock. + * Update CALL (and friends), RENTBALANCE and SENDRENT operations. If HEIGHT >= rentUsingValueBlock then proceed as if rent started paying using value. + +This alternative is a good idea, if there is support I can include this part formally in the specification. The specification is a little complicated so I like the informal definition above until we have some consent around it. + +Alternative2: do not have a separate rent account -- directly deduct rent from value + * Every time the state is updated (including receiving value) you get a rent subsidity + * Need to review invariants of existing contracts to see what problems and broken assumptions this will cause in real life + +**Permanent removal** + +All state about an account is destructed during eviction. The data cannot be recovered. That's the point. + +Hint to implementers: make sure this works: + +1. Send value to a new account (gets stipend) +2. Pay rent to that account +3. Wait until after the rent expires (account is gone) +4. Send value to that account (gets stipend again) +5. Deploy a contract (CREATE) to that account (stipend gets topped off) + +# Rationale -- economics & constants + +An `SSTORE` executed in 2015 cost 20,000 gas and has survived about 6 million blocks. The gas price has been around 1 ~ 50 Gwei. So basically 4,000 Wei per block per word so far. Maybe storing an account is 10 times more intensive than storing a word. But actually G_transaction is 21,000 and G_sstore is 20,000 so these are similar and they can both create new accounts / words. + +How about: + +* RENT_WORD_COST -- 4,000 Wei +* RENT_ACCOUNT_COST -- 4,000 Wei +* RENT_STIPEND -- 4,000 Wei * 360 days worth of blocks + +The rent is priced in cold, hard Ether. It is not negotiated by clients, it is not dynamic. It is linear. Why is this a good idea? Because right now Ethereum is a system with multiple free variables -- Ether/gas price, gas/opcodes costs, Ether/block reward. [Add some note here about reducing a system of equations...] So the end result is that we can peg one of the values and it will be okay. + +By setting the RENT price in Ether and by having the existing gas prices set based on the floating rate, there is an implicit price of ~4 gwei set into the Yellow Paper. In other words, if in the future the price of gas goes to 1 Ether then people will be upset because they will say "I paid 20,000 gas for an SSTORE" but I only got 360 days of stipend. If I paid for the rent directly I would have gotten enough rent to last until the Sun explodes." I acknowledge this complaint and do not think it is sufficient to warrant dismissing this proposal. + +Q: There is a finite-ish amount of Ether and this proposal introduces a word-price in Ether, do math for me. A: The current size of Ethereum is about ~1 TB, maybe half of that is branch nodes. So that's like 15B words. There is about 100M Ether mined. The answer is that all the Ether can be spent on 400,000 terabyte-years of storage. I'm not sure if it is helpful to look at it that way. + +# Backwards compatibility + +There is a 360-day transition period (related to the RENT_STIPEND). This requires a hard fork. On the block of the fork, every account is immediately funded with enough rent to pay for ~ 360 days' worth of their current storage requirements. The formal implementation is that this new rule is applied if any existing account has σ[account]_rentLastPaid = 0. Therefore this can be implemented by clients lazily or eagerly. + +Preexisting accounts which increase their storage needs will evict sooner than 360 days. + +Users will need to be educated. + +# Test Cases + +TO BE ADDED + +# Implementation + +TO BE ADDED + +# Copyright + +Copyright and related rights waived via CC0. From 123b7267b6270914a822001c119d11607e695517 Mon Sep 17 00:00:00 2001 From: Nick Gheorghita Date: Thu, 14 Mar 2019 22:33:06 +0100 Subject: [PATCH 100/431] Proposal to add numPackageIds() and numReleaseIds() (#1609) --- EIPS/eip-1319.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1319.md b/EIPS/eip-1319.md index 1770712d..21d42440 100644 --- a/EIPS/eip-1319.md +++ b/EIPS/eip-1319.md @@ -1,7 +1,7 @@ --- eip: 1319 title: Smart Contract Package Registry Interface -author: Piper Merriam , Christopher Gewecke , g. nicholas d'andrea +author: Piper Merriam , Christopher Gewecke , g. nicholas d'andrea , Nick Gheorghita type: Standards Track category: ERC status: Draft @@ -94,6 +94,16 @@ details the contents of the release. function release(string packageName, string version, string manifestURI) public returns (bytes32 releaseId); ``` + +### Events + +#### VersionRelease +MUST be triggered when `release` is successfully called. + +```solidity +event VersionRelease(string packageName, string version, string manifestURI) +``` + ### Read API Specification The read API consists of a set of methods that allows tooling to extract all consumable data from a registry. @@ -103,7 +113,7 @@ The read API consists of a set of methods that allows tooling to extract all con // `offset` and `limit` enable paginated responses / retrieval of the complete set. (See note below) function getAllPackageIds(uint offset, uint limit) public view returns ( - bytes32 packageIds, + bytes32[] packageIds, uint offset ); @@ -135,6 +145,12 @@ function generateReleaseId(string packageName, string version) public view returns (bytes32); + +// Returns the total number of unique packages in a registry. +function numPackageIds() public view returns (uint totalCount); + +// Returns the total number of unique releases belonging to the given packageName in a registry. +function numReleaseIds(string packageName) public view returns (uint totalCount); ``` **Pagination** From 8c676fc6047628988222e8fefe5101b809c0088d Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 15 Mar 2019 15:53:31 +1300 Subject: [PATCH 101/431] Wrote ENS Interface discovery EIP (#1844) * Wrote ENS Interface discovery EIP * Rename EIP and add discussion URL --- EIPS/eip-1844.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 EIPS/eip-1844.md diff --git a/EIPS/eip-1844.md b/EIPS/eip-1844.md new file mode 100644 index 00000000..d0794ec7 --- /dev/null +++ b/EIPS/eip-1844.md @@ -0,0 +1,64 @@ +--- +eip: 1844 +title: ENS Interface Discovery +author: Nick Johnson (@arachnid) +discussions-to: https://github.com/ensdomains/resolvers/ +status: Draft +type: Standards Track +category: ERC +created: 2019-03-15 +requires: 137, 165 +--- + +## Simple Summary +Defines a method of associating contract interfaces with ENS names and addresses, and of discovering those interfaces. + +## Abstract +This EIP specifies a method for exposing interfaces associated with an ENS name or an address (typically a contract address) and allowing applications to discover those interfaces and interact with them. Interfaces can be implemented either by the target contract (if any) or by any other contract. + +## Motivation +EIP 165 supports interface discovery - determining if the contract at a given address supports a requested interface. However, in many cases it's useful to be able to discover functionality associated with a name or an address that is implemented by other contracts. + +For example, a token contract may not itself provide any kind of 'atomic swap' functionality, but there may be associated contracts that do. With ENS interface discovery, the token contract can expose this metadata, informing applications where they can find that functionality. + +## Specification +A new profile for ENS resolvers is defined, consisting of the following method: + +``` +function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address); +``` + +The EIP-165 interface ID of this interface is `0xb8f2bbb4`. + +Given an ENS name hash `node` and an EIP-165 `interfaceID`, this function returns the address of an appropriate implementer of that interface. If there is no interface matching that interface ID for that node, 0 is returned. + +The address returned by `interfaceImplementer` MUST refer to a smart contract. + +The smart contract at the returned address SHOULD implement EIP-165. + +Resolvers implementing this interface MAY utilise a fallback strategy: If no matching interface was explicitly provided by the user, query the contract returned by `addr()`, returning its address if the requested interface is supported by that contract, and 0 otherwise. If they do this, they MUST ensure they return 0, rather than reverting, if the target contract reverts. + +This field may be used with both forward resolution and reverse resolution. + +## Rationale + +A naive approach to this problem would involve adding this method directly to the target contract. However, doing this has several shortcomings: + + 1. Each contract must maintain its own list of interface implementations. + 2. Modifying this list requires access controls, which the contract may not have previously required. + 3. Support for this must be designed in when the contract is written, and cannot be retrofitted afterwards. + 4. Only one canonical list of interfaces can be supported. + +Using ENS resolvers instead mitigates these shortcomings, making it possible for anyone to associate interfaces with a name, even for contracts not previously built with this in mind. + +## Backwards Compatibility +There are no backwards compatibility issues. + +## Test Cases +TBD + +## Implementation +The PublicResolver in the [ensdomains/resolvers](https://github.com/ensdomains/resolvers/) repository implements this interface. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 8a210906d95ab9afd72cec45dd3a712255aff1ae Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 15 Mar 2019 16:09:43 +1300 Subject: [PATCH 102/431] Fix discussions-to URL --- EIPS/eip-1844.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1844.md b/EIPS/eip-1844.md index d0794ec7..5bb1c2d7 100644 --- a/EIPS/eip-1844.md +++ b/EIPS/eip-1844.md @@ -2,7 +2,7 @@ eip: 1844 title: ENS Interface Discovery author: Nick Johnson (@arachnid) -discussions-to: https://github.com/ensdomains/resolvers/ +discussions-to: https://ethereum-magicians.org/t/ens-interface-discovery/2924 status: Draft type: Standards Track category: ERC From 768ad55b8a5cbea9f36206ef1d900e6962398435 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 18 Mar 2019 02:45:22 -0700 Subject: [PATCH 103/431] Automatically merged updates to draft EIP(s) 225 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-225.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-225.md b/EIPS/eip-225.md index cf7d64c6..2404a73b 100644 --- a/EIPS/eip-225.md +++ b/EIPS/eip-225.md @@ -120,6 +120,7 @@ We repurpose the `ethash` header fields as follows: * Should be filled with zeroes normally, modified only while voting. * Arbitrary values are permitted nonetheless (even meaningless ones such as voting out non signers) to avoid extra complexity in implementations around voting mechanics. * **Must** be filled with zeroes on checkpoint (i.e. epoch transition) blocks. + * Transaction execution **must** use the actual block signer (see `extraData`) for the `COINBASE` opcode. * **`nonce`**: Signer proposal regarding the account defined by the `beneficiary` field. * Should be **`NONCE_DROP`** to propose deauthorizing `beneficiary` as a existing signer. * Should be **`NONCE_AUTH`** to propose authorizing `beneficiary` as a new signer. From 3d4dc87e230da4b1c0475285d3e004208e378cd4 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Tue, 19 Mar 2019 11:38:30 +1300 Subject: [PATCH 104/431] Ethereum purpose allocation and path scheme for deterministic wallets (#600) --- eip-600.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 eip-600.md diff --git a/eip-600.md b/eip-600.md new file mode 100644 index 00000000..c315aefc --- /dev/null +++ b/eip-600.md @@ -0,0 +1,65 @@ +--- +eip: 600 +title: Ethereum purpose allocation for Deterministic Wallets +author: Nick Johnson (@arachnid), Micah Zoltu (@micahzoltu) +type: Standard Track +category: ERC +status: Draft +discussions-to: https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742 +created: 2017-04-13 +--- + +## Abstract +This EIP defines a logical hierarchy for deterministic wallets based on [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), the purpose scheme defined in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) and [this proposed change to BIP43](https://github.com/bitcoin/bips/pull/523). + +This EIP is a particular application of BIP43. + +## Motivation +Because Ethereum is based on account balances rather than UTXO, the hierarchy defined by BIP44 is poorly suited. As a result, several competing derivation path strategies have sprung up for deterministic wallets, resulting in inter-client incompatibility. This BIP seeks to provide a path to standardise this in a fashion better suited to Ethereum's unique requirements. + +## Specification +We define the following 2 levels in BIP32 path: + +
    +m / purpose' / subpurpose' / EIP'
    +
    + +Apostrophe in the path indicates that BIP32 hardened derivation is used. + +Each level has a special meaning, described in the chapters below. + +### Purpose + +Purpose is set to 43, as documented in [this proposed change to BIP43](https://github.com/bitcoin/bips/pull/523). + +The purpose field indicates that this path is for a non-bitcoin cryptocurrency. + +Hardened derivation is used at this level. + +### Subpurpose +Subpurpose is set to 60, the SLIP-44 code for Ethereum. + +Hardened derivation is used at this level. + +### EIP +EIP is set to the EIP number specifying the remainder of the BIP32 derivation path. This permits new Ethereum-focused applications of deterministic wallets without needing to interface with the BIP process. + +Hardened derivation is used at this level. + +## Rationale +The existing convention is to use the 'Ethereum' coin type, leading to paths starting with `m/44'/60'/*`. Because this still assumes a UTXO-based coin, we contend that this is a poor fit, resulting in standardisation, usability, and security compromises. As a result, we are making the above proposal to define an entirely new hierarchy for Ethereum-based chains. + +## Backwards Compatibility +The introduction of another derivation path requires existing software to add support for this scheme in addition to any existing schemes. Given the already confused nature of wallet derivation paths in Ethereum, we anticipate this will cause relatively little additional disruption, and has the potential to improve matters significantly in the long run. + +## Test Cases +TBD + +## Implementation +None yet. + +## References +[This discussion on derivation paths](https://github.com/ethereum/EIPs/issues/84) + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 36cc935cfa6e7888da13e655eb7db310f0cb1fe9 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Tue, 19 Mar 2019 11:43:15 +1300 Subject: [PATCH 105/431] Ethereum hierarchy for deterministic wallets (#601) --- EIPS/eip-601.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 EIPS/eip-601.md diff --git a/EIPS/eip-601.md b/EIPS/eip-601.md new file mode 100644 index 00000000..4768679a --- /dev/null +++ b/EIPS/eip-601.md @@ -0,0 +1,80 @@ +--- +eip: 601 +title: Ethereum hierarchy for deterministic wallets +author: Nick Johnson (@arachnid), Micah Zoltu (@micahzoltu) +type: Standards Track +category : ERC +status: Draft +discussions-to: https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742 +created: 2017-04-13 +--- + +## Abstract +This EIP defines a logical hierarchy for deterministic wallets based on [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), the purpose scheme defined in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) and eip-draft-ethereum-purpose. + +This EIP is a particular application of eip-draft-ethereum-purpose. + +## Motivation +At present, different Ethereum clients and wallets use different derivation paths; a summary of them can be found [here](https://github.com/ethereum/EIPs/issues/84#issuecomment-292324521). Some of these paths violate BIP44, the standard defining derivation paths starting with `m/44'/`. This creates confusion and incompatibility between wallet implementations, in some cases making funds from one wallet inaccessible on another, and in others requiring prompting users manually for a derivation path, which hinders usability. + +Further, BIP44 was designed with UTXO-based blockchains in mind, and is a poor fit for Ethereum, which uses an accounts abstraction instead. + +As an alternative, we propose a deterministic wallet hierarchy better tailored to Ethereum's unique requiremnts. + +## Specification +We define the following 4 levels in BIP32 path: + +
    +m / purpose' / subpurpose' / EIP' / wallet'
    +
    + +Apostrophe in the path indicates that BIP32 hardened derivation is used. + +Each level has a special meaning, described in the chapters below. + +### Purpose + +Purpose is a constant set to 43, indicating the key derivation is for a non-bitcoin cryptocurrency. + +Hardened derivation is used at this level. + +### Subpurpose +Subpurpose is set to 60, the SLIP-44 code for Ethereum. + +Hardened derivation is used at this level. + +### EIP +EIP is set to the EIP number specifying the remainder of the BIP32 derivation path. For paths following this EIP specification, the number assigned to this EIP is used. + +Hardened derivation is used at this level. + +### Wallet +This component of the path splits the wallet into different user identities, allowing a single wallet to have multiple public identities. + +Accounts are numbered from index 0 in sequentially increasing manner. This number is used as child index in BIP32 derivation. + +Hardened derivation is used at this level. + +Software should prevent a creation of an account if a previous account does not have a transaction history (meaning its address has not been used before). + +Software needs to discover all used accounts after importing the seed from an external source. + +## Rationale +The existing convention is to use the 'Ethereum' coin type, leading to paths starting with `m/44'/60'/*`. Because this still assumes a UTXO-based coin, we contend that this is a poor fit, resulting in standardisation, usability, and security compromises. As a result, we are making the above proposal to define an entirely new hierarchy for Ethereum-based chains. + +## Backwards Compatibility +The introduction of another derivation path requires existing software to add support for this scheme in addition to any existing schemes. Given the already confused nature of wallet derivation paths in Ethereum, we anticipate this will cause relatively little additional disruption, and has the potential to improve matters significantly in the long run. + +For applications that utilise mnemonics, the authors expect to submit another EIP draft that describes a method for avoiding backwards compatibility concerns when transitioning to this new derivation path. + +## Test Cases +TBD + +## Implementation +None yet. + +## References +[This discussion on derivation paths](https://github.com/ethereum/EIPs/issues/84) + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 695726d6be77d057a46227735657b0460a2634b0 Mon Sep 17 00:00:00 2001 From: Nick Savers Date: Wed, 20 Mar 2019 12:57:54 +0100 Subject: [PATCH 106/431] Rename eip-600.md to EIPS/eip-600.md (#1854) --- eip-600.md => EIPS/eip-600.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename eip-600.md => EIPS/eip-600.md (99%) diff --git a/eip-600.md b/EIPS/eip-600.md similarity index 99% rename from eip-600.md rename to EIPS/eip-600.md index c315aefc..07d9519a 100644 --- a/eip-600.md +++ b/EIPS/eip-600.md @@ -2,7 +2,7 @@ eip: 600 title: Ethereum purpose allocation for Deterministic Wallets author: Nick Johnson (@arachnid), Micah Zoltu (@micahzoltu) -type: Standard Track +type: Standards Track category: ERC status: Draft discussions-to: https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742 From 964292f1939f952d5d296247c4fb5780fc2d704b Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Fri, 22 Mar 2019 00:47:43 +0100 Subject: [PATCH 107/431] ERC1820: Last Call (#1857) --- EIPS/eip-1820.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md index 9e418c5c..fc07fc8b 100644 --- a/EIPS/eip-1820.md +++ b/EIPS/eip-1820.md @@ -3,7 +3,8 @@ eip: 1820 title: Pseudo-introspection Registry Contract author: Jordi Baylina , Jacques Dafflon discussions-to: https://github.com/ethereum/EIPs/pulls/1820 -status: Draft +status: Last Call +review-period-end: 2019-04-04 type: Standards Track category: ERC requires: 165, 214 From 0997aa44ad33abc0cdb8b4e6f96a54e27b979a8a Mon Sep 17 00:00:00 2001 From: Ilan <36084092+ilanolkies@users.noreply.github.com> Date: Fri, 22 Mar 2019 11:41:15 -0300 Subject: [PATCH 108/431] Automatically merged updates to draft EIP(s) 1191 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1191.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/EIPS/eip-1191.md b/EIPS/eip-1191.md index 871127b5..7b0149fe 100644 --- a/EIPS/eip-1191.md +++ b/EIPS/eip-1191.md @@ -88,10 +88,10 @@ for chainid, cases in test_cases.items(): | RSK Mainnet | 30 | Yes | | RSK Testnet | 31 | Yes | - -| Wallet | Implements this EIP| -|--------------|--------------------| -| MyCrypto | In progress | -| Ledger | In progress | -| Trezor | In progress | - +### Implementation Table +| Wallet | Adopted this EIP | Implementation | +|----------------|------------------| -------------- | +| MyCrypto | Yes | [JavaScript](https://github.com/MyCryptoHQ/MyCrypto/blob/develop/common/utils/formatters.ts#L126) | +| MyEtherWallet | Yes | [JavaScript](https://github.com/MyEtherWallet/MyEtherWallet/blob/73c4a24f8f67c655749ac990c5b62efd92a2b11a/src/helpers/addressUtils.js#L22) | +| Ledger | Yes | [C](https://github.com/LedgerHQ/ledger-app-eth/blob/master/src_common/ethUtils.c#L203) | +| Trezor | Yes | [Python](https://github.com/trezor/trezor-core/blob/270bf732121d004a4cd1ab129adaccf7346ff1db/src/apps/ethereum/get_address.py#L32) and [C](https://github.com/trezor/trezor-crypto/blob/4153e662b60a0d83c1be15150f18483a37e9092c/address.c#L62) | From 85a8a2af13bfe251bf7787e6ea11a1b0c83489a7 Mon Sep 17 00:00:00 2001 From: Alex Van de Sande Date: Fri, 22 Mar 2019 20:42:32 +0100 Subject: [PATCH 109/431] Changing the status of this EIP to deferred (#1859) --- EIPS/eip-1015.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1015.md b/EIPS/eip-1015.md index 9c844a55..4aecc15a 100644 --- a/EIPS/eip-1015.md +++ b/EIPS/eip-1015.md @@ -3,7 +3,7 @@ eip: 1015 title: Configurable On Chain Issuance author: Alex Van de Sande discussions-to: https://ethereum-magicians.org/t/eip-dynamic-block-rewards-with-governance-contract/204 -status: Draft +status: Deferred type: Standards Track category: Core created: 2018-04-20 From 00fbcbcd0f6d6b7c62b4ab817d84e06448e28501 Mon Sep 17 00:00:00 2001 From: Nick Savers Date: Sun, 24 Mar 2019 22:43:12 +0100 Subject: [PATCH 110/431] Automatically merged updates to draft EIP(s) 1706 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1706.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1706.md b/EIPS/eip-1706.md index c3f7ca0f..7d8ec43c 100644 --- a/EIPS/eip-1706.md +++ b/EIPS/eip-1706.md @@ -1,7 +1,7 @@ --- eip: 1706 title: Disable SSTORE with gasleft lower than call stipend -author: Alex Forshtat (alex@tabookey.com), Yoav Weiss (yoav@tabookey.com) +author: Alex Forshtat , Yoav Weiss discussions-to: https://github.com/alex-forshtat-tbk/EIPs/issues/1 status: Draft type: Standards Track From e2692803625e98dc30aa59b87cfa04ba5c8155c3 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 25 Mar 2019 00:56:18 +0100 Subject: [PATCH 111/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 73 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 1c55a63f..f612366a 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -71,13 +71,35 @@ interface ERC777Token { event RevokedOperator(address indexed operator, address indexed tokenHolder); } ``` -The token contract MUST implement the above interface. The implementation MUST follow the specifications described below. +The token contract MUST implement the above interface. +The implementation MUST follow the specifications described below. -The token contract MUST register the `ERC777Token` interface with its own address via [ERC1820]. If the contract has a switch to enable or disable [ERC777] functions, every time the switch is triggered, the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via [ERC1820]. (Unregistering implies setting the address to `0x0`.) +The token contract MUST register the `ERC777Token` interface with its own address via [ERC1820]. +This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry +with the token contract address as both the address and the implementer +and the `keccak256` hash of `ERC777Token` as the interface hash. -The smallest unit—for all interactions with the token contract—MUST be `1`. I.e. all amounts and balances MUST be unsigned integers. The display denomination—to display any amount to the end user—MUST be 1018 of the smallest. +If the contract has a switch to enable or disable ERC777 functions, every time the switch is triggered, +the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via ERC1820. +Unregistering implies calling the `setInterfaceImplementer` with the token contract address as the address, +the `keccak256` hash of `ERC777Token` as the interface hash and `0x0` as the implementer. +(See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.) -In other words the technical denomination is similar to a wei and the display denomination is similar to an ether. It is equivalent to an [ERC20]'s `decimals` function returning `18`. E.g. if a token contract holds a balance of `500,000,000,000,000,000` (0.5×1018) for a user, the user interface SHOULD show `0.5` tokens to the user. If the user wishes to send `0.3` tokens, the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3×1018). +When interacting with the token contract, all amounts and balances MUST be unsigned integers. +I.e. Internally, all values are stored as a denomination of 1E-18 of a token. +The display denomination—to display any amount to the end user—MUST be 1018 of the internal denomination. + +In other words, the internal denomination is similar to a wei +and the display denomination is similar to an ether. +It is equivalent to an [ERC20]'s `decimals` function returning `18`. +E.g. if a token contract returns a balance of `500,000,000,000,000,000` (0.5×1018) for a user, +the user interface MUST show `0.5` tokens to the user. +If the user wishes to send `0.3` tokens, +the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3×1018). + +User Interfaces which are generated programmatically from the ABI of the token contract +MAY use and display the internal denomination. +But this MUST be made clear, for example by displaying the `uint256` type. #### **View Functions** @@ -89,7 +111,7 @@ The `view` functions detailed below MUST be implemented. function name() external view returns (string) ``` -Returns the name of the token, e.g., `"MyToken"`. +Get the name of the token, e.g., `"MyToken"`. > **returns:** Name of the token. @@ -99,7 +121,7 @@ Returns the name of the token, e.g., `"MyToken"`. function symbol() external view returns (string) ``` -Returns the symbol of the token, e.g., `"MYT"`. +Get the symbol of the token, e.g., `"MYT"`. > **returns:** Symbol of the token. @@ -113,7 +135,7 @@ Get the total number of minted tokens. *NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as returned by the `balanceOf` function. -*NOTE*: The total supply MUST be equal to the sum of all the minted tokens as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. (This applies as well to [tokens minted when the token contract is created][initial supply].) +*NOTE*: The total supply MUST be equal to the sum of all the minted tokens as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. > **returns:** Total supply of tokens currently in circulation. @@ -131,7 +153,7 @@ The balance MUST be zero (`0`) or higher. > **parameters** > `tokenHolder`: Address for which the balance is returned. > -> **returns:** Amount of token held by `tokenHolder` in the token contract. +> **returns:** Amount of tokens held by `tokenHolder` in the token contract. **`granularity` function** @@ -158,14 +180,11 @@ The following rules MUST be applied regarding the *granularity*: *NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, defined under the [operators] for consistency. *[ERC20] compatibility requirement*: -The decimals of the token MUST always be `18`. For a *pure* ERC777 token the [ERC20] `decimal` function is OPTIONAL, and its existence SHALL NOT be relied upon when interacting with the token contract. (The decimal value of `18` is implied.) For an [ERC20] compatible token, the `decimal` function is REQUIRED and MUST return `18`. (In [ERC20], the `decimals` function is OPTIONAL. If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`. Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.) - -*[ERC20] compatibility requirement*: -The `name`, `symbol`, `totalSupply`, and `balanceOf` `view` functions MUST be backward compatible with [ERC20]. +The decimals of the token MUST always be `18`. For a *pure* ERC777 token the [ERC20] `decimals` function is OPTIONAL, and its existence SHALL NOT be relied upon when interacting with the token contract. (The decimal value of `18` is implied.) For an [ERC20] compatible token, the `decimals` function is REQUIRED and MUST return `18`. (In [ERC20], the `decimals` function is OPTIONAL. If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`. Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.) #### **Operators** -An `operator` is an address which is allowed to send and burn tokens on behalf of another address. +An `operator` is an address which is allowed to send and burn tokens on behalf of some *token holder*. When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted. The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively. @@ -194,8 +213,6 @@ The following rules apply to any *operator*: *NOTE*: A *token holder* MAY revoke an already revoked *operator*. A `RevokedOperator` MUST be emitted each time. -*NOTE*: A token holder MAY have multiple *operators* at the same time. - **`AuthorizedOperator` event** ``` solidity @@ -286,7 +303,7 @@ Indicate whether the `operator` address is an *operator* of the `tokenHolder` ad When an *operator* sends an `amount` of tokens from a *token holder* to a *recipient* with the associated `data` and `operatorData`, the token contract MUST apply the following rules: -- Any *token holder* MAY send tokens to any *recipient*. +- Any authorized *operator* MAY send tokens to any *recipient* (except to `0x0`). - The balance of the *token holder* MUST be decreased by the `amount`. - The balance of the *recipient* MUST be increased by the `amount`. - The balance of the *token holder* MUST be greater or equal to the `amount`—such that its resulting balance is greater or equal to zero (`0`) after the send. @@ -300,6 +317,7 @@ The token contract MUST `revert` when sending in any of the following cases: - The *operator* address is not an authorized operator for the *token holder*. - The resulting *token holder* balance or *recipient* balance after the send is not a multiple of the *granularity* defined by the token contract. +- The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. - The address of the *token holder* or the *recipient* is `0x0`. - Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`). @@ -329,7 +347,7 @@ MAY use the information to decide if they wish to reject the transaction. *NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*. -Typically, `data` is used to describe the intent behind the send. The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. +The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. **`Sent` event** @@ -352,8 +370,6 @@ Indicate a send of `amount` of tokens from the `from` address to the `to` addres The `send` and `operatorSend` functions described below MUST be implemented to send tokens. Token contracts MAY implement other functions to send tokens. -*NOTE*: An address MAY send an amount of `0`, which is valid and MUST be treated as a regular send. - **`send` function** ``` solidity @@ -411,7 +427,6 @@ The token contract MUST `revert` when minting in any of the following cases: - The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. - The address of the *recipient* is `0x0`. - *NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting for the amount of the initial supply to the address(es) receiving the initial supply. This means one or more `Minted` events must be emitted and the `tokensReceived` hook of the recipient(s) MUST be called. *[ERC20] compatibility requirement*: @@ -430,7 +445,6 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca to the data field in a regular ether send transaction. The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction. - **`Minted` event** ``` solidity @@ -664,6 +678,7 @@ The following rules apply when calling the `tokensReceived` hook: This hook takes precedence over [ERC20] and MUST be called (if registered) when calling [ERC20]'s `transfer` and `transferFrom` event. When called from a `transfer`, `operator` MUST be the same value as the `from`. When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. #### **Note On Gas Consumption** + Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens—using [`eth_estimateGas`][eth_estimateGas]—to avoid running out of gas during the transaction. ### Logo @@ -697,11 +712,21 @@ This standard allows the implementation of [ERC20] functions `transfer`, `transf The token MAY implement `decimals()` for backward compatibility with [ERC20]. If implemented, it MUST always return `18`. -Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data (such as the mapping of balances) overlap without problems. Note however that the following functions are mandatory in [ERC777] and MUST be implemented: `name`, `symbol` `balanceOf` and `totalSupply` (`decimal` is not part of the [ERC777] standard). +Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data (such as the mapping of balances) overlap without problems. Note however that the following functions are mandatory in [ERC777] and MUST be implemented: `name`, `symbol` `balanceOf` and `totalSupply` (`decimals` is not part of the [ERC777] standard). The state-modifying functions from both standards are decoupled and can operate independently from each other. Note that [ERC20] functions SHOULD be limited to only being called from old contracts. -If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC1820]. If the contract has a switch to enable or disable [ERC20] functions, every time the switch is triggered, the token MUST register or unregister its own address accordingly the `ERC20Token` interface via [ERC1820]. (Unregistering implies setting the address to `0x0`.) +If the token implements [ERC20], +it MUST register the `ERC20Token` interface with its own address via [ERC1820]. +This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry +with the token contract address as both the address and the implementer +and the `keccak256` hash of `ERC20Token` as the interface hash. + +If the contract has a switch to enable or disable ERC20 functions, every time the switch is triggered, +the token MUST register or unregister the `ERC20Token` interface for its own address accordingly via ERC1820. +Unregistering implies calling the `setInterfaceImplementer` with the token contract address as the address, +the `keccak256` hash of `ERC20Token` as the interface hash and `0x0` as the implementer. +(See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.) The difference for new contracts implementing [ERC20] is that `tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC1820] if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. If any hook is implemented, it MUST be called. Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. @@ -766,6 +791,7 @@ Copyright and related rights waived via [CC0]. [ERC20]: https://eips.ethereum.org/EIPS/eip-20 [ERC777]: https://eips.ethereum.org/EIPS/eip-777 [ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[erc1820-set]: https://eips.ethereum.org/EIPS/eip-1820#set-an-interface-for-an-address [0xjac/ERC777]: https://github.com/0xjac/ERC777 [npm/erc777]: https://www.npmjs.com/package/erc777 [ref tests]: https://github.com/0xjac/ERC777/blob/master/test/ReferenceToken.test.js @@ -780,7 +806,6 @@ Copyright and related rights waived via [CC0]. [sent]: #sent [minted]: #minted [burned]: #burned -[initial supply]: #initialSupply [logos]: https://github.com/ethereum/EIPs/tree/master/assets/eip-777/logo [beige logo]: ../assets/eip-777/logo/png/ERC-777-logo-beige-48px.png From 48b2ff3cdf84ff6990dc91ac983ed658301244b8 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 25 Mar 2019 01:12:29 +0100 Subject: [PATCH 112/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 52 ++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index f612366a..f76f4b68 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -40,22 +40,28 @@ This standard tries to improve the widely used [ERC20] token standard. The main ``` solidity interface ERC777Token { - function name() external view returns (string); - function symbol() external view returns (string); + function name() external view returns (string memory); + function symbol() external view returns (string memory); function totalSupply() external view returns (uint256); - function balanceOf(address owner) external view returns (uint256); + function balanceOf(address tokenHolder) external view returns (uint256); function granularity() external view returns (uint256); - function defaultOperators() external view returns (address[]); + function defaultOperators() external view returns (address[] memory); + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); function authorizeOperator(address operator) external; function revokeOperator(address operator) external; - function isOperatorFor(address operator, address tokenHolder) external view returns (bool); - function send(address to, uint256 amount, bytes data) external; - function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external; + function send(address to, uint256 amount, bytes calldata data) external; + function operatorSend( + address from, + address to, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; - function burn(uint256 amount, bytes data) external; - function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external; + function burn(uint256 amount, bytes calldata data) external; + function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external; event Sent( address indexed operator, @@ -108,7 +114,7 @@ The `view` functions detailed below MUST be implemented. **`name` function** ``` solidity - function name() external view returns (string) +function name() external view returns (string memory) ``` Get the name of the token, e.g., `"MyToken"`. @@ -118,7 +124,7 @@ Get the name of the token, e.g., `"MyToken"`. **`symbol` function** ``` solidity -function symbol() external view returns (string) +function symbol() external view returns (string memory) ``` Get the symbol of the token, e.g., `"MYT"`. @@ -248,7 +254,7 @@ Token contracts MAY implement other functions to manage *operators*. **`defaultOperators` function** ``` solidity -function defaultOperators() external view returns (address[]) +function defaultOperators() external view returns (address[] memory) ``` Get the list of *default operators* as defined by the token contract. @@ -373,7 +379,7 @@ Token contracts MAY implement other functions to send tokens. **`send` function** ``` solidity -function send(address to, uint256 amount, bytes data) external +function send(address to, uint256 amount, bytes calldata data) external ``` Send the `amount` of tokens from the address `msg.sender` to the address `to`. @@ -388,7 +394,7 @@ The *operator* and the *token holder* MUST both be the `msg.sender`. **`operatorSend` function** ``` solidity -function operatorSend(address from, address to, uint256 amount, bytes data, bytes operatorData) external +function operatorSend(address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` Send the `amount` of tokens on behalf of the address `from` to the address `to`. @@ -525,7 +531,7 @@ Token contracts MAY implement other functions to burn tokens. **`burn` function** ``` solidity -function burn(uint256 amount, bytes data) external; +function burn(uint256 amount, bytes calldata data) external ``` Burn the `amount` of tokens from the address `msg.sender`. @@ -539,7 +545,7 @@ The *operator* and the *token holder* MUST both be the `msg.sender`. **`operatorBurn` function** ``` solidity -function operatorBurn(address from, uint256 amount, bytes data, bytes operatorData) external; +function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` Burn the `amount` of tokens on behalf of the address `from`. @@ -569,8 +575,8 @@ interface ERC777TokensSender { address from, address to, uint256 amount, - bytes data, - bytes operatorData + bytes calldata userData, + bytes calldata operatorData ) external; } ``` @@ -580,7 +586,7 @@ interface ERC777TokensSender { **`tokensToSend`** ``` solidity -function tokensToSend(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) external +function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external ``` Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. @@ -626,8 +632,8 @@ interface ERC777TokensRecipient { address from, address to, uint256 amount, - bytes data, - bytes operatorData + bytes calldata data, + bytes calldata operatorData ) external; } ``` @@ -642,7 +648,7 @@ If the *recipient* is a contract, which has not registered an `ERC777TokensRecip **`tokensReceived`** ``` solidity -function tokensReceived(address operator, address from, address to, uint256 amount, bytes data, bytes operatorData) external +function tokensReceived(address operator, address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. @@ -780,14 +786,12 @@ The [repository with the reference implementation][0xjac/ERC777] contains all th The GitHub repository [0xjac/ERC777] contains the [reference implementation]. The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. - ## Copyright Copyright and related rights waived via [CC0]. [operators]: #operators - [ERC20]: https://eips.ethereum.org/EIPS/eip-20 [ERC777]: https://eips.ethereum.org/EIPS/eip-777 [ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 From 822dc9d73f5bf7629a1a7fda5f7358f7e83d41cf Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 25 Mar 2019 02:29:02 +0100 Subject: [PATCH 113/431] Automatically merged updates to draft EIP(s) 1820 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1820.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md index fc07fc8b..758e645f 100644 --- a/EIPS/eip-1820.md +++ b/EIPS/eip-1820.md @@ -8,7 +8,7 @@ review-period-end: 2019-04-04 type: Standards Track category: ERC requires: 165, 214 -created: 2018-03-04 +created: 2019-03-04 replaces: 820 --- From f357d88854e386f4dbccd58e759e8369e153d50f Mon Sep 17 00:00:00 2001 From: Fabian Vogelsteller Date: Mon, 25 Mar 2019 22:13:00 +0100 Subject: [PATCH 114/431] Automatically merged updates to draft EIP(s) 725 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-725.md | 297 ++++++++++++++---------------------------------- 1 file changed, 86 insertions(+), 211 deletions(-) diff --git a/EIPS/eip-725.md b/EIPS/eip-725.md index ee0b8c9b..063a0674 100644 --- a/EIPS/eip-725.md +++ b/EIPS/eip-725.md @@ -10,283 +10,158 @@ created: 2017-10-02 --- ## Simple Summary -A proxy contract for key management and execution, to establish a Blockchain identity. +A standard interface for a simple proxy account. ## Abstract -The following describes standard functions for a unique identity for humans, groups, objects and machines. -This identity can hold keys to sign actions (transactions, documents, logins, access, etc), and claims, which are attested from third parties (issuers) and self-attested ([#ERC735](https://github.com/ethereum/EIPs/issues/735)), as well as a proxy function, to act directly on the blockchain. + +The following describes standard functions for a unique identifiable proxy account to be used by humans, groups, organisations, objects and machines. The proxy has 2 abilities: (1) it can execute arbitrary contract calls, and (2) it can hold arbitrary data through a generic key/value store. One of these keys should hold the owner of the contract. The owner may be an address or a key manager contract for more complex management logic. Most importantly, this contract should be the reference point for a long-lasting identifiable profiles. ## Motivation -This standardized identity interface will allow Dapps, smart contracts and third parties to check the validity of a person, organization, object or machine through 2 steps as described in the function XXX. Trust is here transferred to the issuers of claims. - -The most important functions to verify an identity are: `XXX` - -The most important functions to manage an identity are: `XXX` - - -## Definitions - -- `keys`: Keys are public keys from either external accounts, or contracts' addresses. -- `claim issuer`: is another smart contract or external account, which issues claims about this identity. The claim issuer can be an identity contract itself. -- `claim`: For details about claims see [#ERC735](https://github.com/ethereum/EIPs/issues/735) - +Standardizing a minimal interface for an proxy account allows third parties to interact with various proxy accounts contracts in a consistent manner. +the benefit is a persistent account that is independed from single keys and can attach an arbitrary amount of information to verifiy, or enhance the accounts purpose. ## Specification -### Key Management +### Methods -Keys are cryptographic public keys, or contract addresses associated with this identity. -The structure should be as follows: - -- `key`: A public key owned by this identity - - `purpose`: `uint256` The key purpose. e.g., 1 = MANAGEMENT, 2 = ACTION, 3 = CLAIM, 4 = ENCRYPTION - - `keyType`: The type of key used, which would be a `uint256` for different key types. e.g. 1 = ECDSA, 2 = RSA, etc. - - `key`: `bytes32` The public key. // for non-hex and long keys, its the Keccak256 hash of the key +#### owner +Returns the current owner ```js -struct Key { - uint256 purpose; - uint256 keyType; - bytes32 key; -} +function address public owner; ``` -#### getKey +#### changeOwner -Returns the full key data, if present in the identity. +Changes the current owner. MUST only be called by the current owner of the contract. -``` js -function getKey(bytes32 _key) constant returns(uint256 purpose, uint256 keyType, bytes32 key); +```js +function changeOwner(address _owner); ``` -#### keyHasPurpose +**Triggers Event:** [OwnerChanged](#ownerchanged) -Returns `TRUE` if a key is present and has the given purpose. If the key is not present it returns `FALSE`. +#### getData -``` js -function keyHasPurpose(bytes32 _key, uint256 purpose) constant returns(bool exists); +Returns the data at the specified key. + +```js +function getData(bytes32 _key) external view returns (bytes _value); ``` +#### setData -#### getKeysByPurpose +Sets the data at a specific key. MUST only be called by the current owner of the contract. -Returns an array of public key bytes32 held by this identity. +**Triggers Event:** [DataChanged](#datachanged) -``` js -function getKeysByPurpose(uint256 _purpose) constant returns(bytes32[] keys); +```js +function setData(bytes32 _key, bytes _value) external; ``` - -#### addKey - -Adds a `_key` to the identity. The `_purpose` specifies the purpose of the key. Initially, we propose four purposes: - -- `1`: MANAGEMENT keys, which can manage the identity -- `2`: ACTION keys, which perform actions in this identity's name (signing, logins, transactions, etc.) -- `3`: CLAIM signer keys, used to sign claims on other identities which need to be revocable. -- `4`: ENCRYPTION keys, used to encrypt data e.g. hold in claims. - -MUST only be done by keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval. - -**Triggers Event:** [KeyAdded](#keyadded) - -``` js -function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) returns (bool success) -``` - - -#### removeKey - -Removes `_key` from the identity. - -MUST only be done by keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval. - -**Triggers Event:** [KeyRemoved](#keyremoved) - -``` js -function removeKey(bytes32 _key, uint256 _purpose) returns (bool success) -``` - - --------------------------------------------------------- - -### Identity usage - - #### execute -Executes an action on other contracts, or itself, or a transfer of ether. -SHOULD require `approve` to be called with one or more keys of purpose `1` or `2` to approve this execution. +Executes an action on other contracts or a transfer of the blockchains native cryptocurrency. MUST only be called by the current owner of the contract. -Execute COULD be used as the only accessor for `addKey`, `removeKey` and `replaceKey` and `removeClaim`. - -**Returns `executionId`:** SHOULD be sent to the `approve` function, to approve or reject this execution. - -**Triggers Event:** [ExecutionRequested](#executionrequested) -**Triggers on direct execution Event:** [Executed](#executed) - -``` js -function execute(address _to, uint256 _value, bytes _data) returns (uint256 executionId) +```js +function execute(uint256 _operationType, address _to, uint256 _value, bytes _data) external; ``` +The `operationType` should represent the assembly operation as follows: +- `0` for `call` +- `1` for `create` -#### approve - -Approves an execution or claim addition. -This SHOULD require `n` of `m` approvals of keys purpose `1`, if the `_to` of the execution is the identity contract itself, to successfully approve an execution. -And COULD require `n` of `m` approvals of keys purpose `2`, if the `_to` of the execution is another contract, to successfully approve an execution. - -**Triggers Event:** [Approved](#approved) -**Triggers on successfull execution Event:** [Executed](#executed) -**Triggers on successfull claim addition Event:** [ClaimAdded](#claimadded) - -``` js -function approve(uint256 _id, bool _approve) returns (bool success) -``` - - --------------------------------------------------------- - - -### Identity verification - -Requires: [ERC 735](https://github.com/ethereum/EIPs/issues/735) - -##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED: - -#### addClaim - -This SHOULD create a pending claim, which SHOULD be approved or rejected by `n` of `m` `approve` calls from keys of purpose `1`. - -Only Events: -**Triggers if the claim is new Event and approval process exists:** [ClaimRequested](#claimrequested) -**Triggers if the claim index existed Event:** [ClaimChanged](https://github.com/ethereum/EIPs/issues/735) - - -#### removeClaim - -MUST only be done by the `issuer` of the claim, or keys of purpose `1`, or the identity itself. If it's the identity itself, the approval process will determine its approval. - - --------------------------------------------------------- - +Others may be added in the future. Inspired by [ERC1077](https://eips.ethereum.org/EIPS/eip-1077) and [Gnosis](https://github.com/gnosis/safe-contracts/blob/master/contracts/Enum.sol#L7) ### Events -#### KeyAdded +#### DataChanged -MUST be triggered when `addKey` was successfully called. +MUST be triggered when `setData` was successfully called. -``` js -event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) +```js +event DataChanged(bytes32 indexed key, bytes value); +``` + +#### ContractCreated + +MUST be triggered when `execute` creates a new contract using the `_operationType` `1`. + +```js +event ContractCreated(address indexed contractAddress); +``` + +#### OwnerChanged + +MUST be triggered when `changeOwner` was successfully called. + +```js +event OwnerChanged(address indexed ownerAddress); ``` -#### KeyRemoved +### Ownership -MUST be triggered when `removeKey` was successfully called. +This contract is controlled by the owner. The owner can be a smart contract or an address, or itself. -``` js -event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType) -``` +### Data keys +Data keys, should be the keccak256 hash of a type name. +e.g. `myNewKeyType` is `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4` +#### Multiple keys of the same type -#### ExecutionRequested +Multiple keys for the same key type must add a `keyTypeName-1` at the end of the key type. -MUST be triggered when `execute` was successfully called. - -``` js -event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data) -``` - - -#### Executed - -MUST be triggered when `approve` was called and the execution was successfully approved. - -``` js -event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data) -``` - - -#### Approved - -MUST be triggered when `approve` was successfully called. - -``` js -event Approved(uint256 indexed executionId, bool approved) -``` - -##### The following changes to [ERC 735](https://github.com/ethereum/EIPs/issues/735) are REQUIRED: - -#### ClaimRequested - -MUST be triggered when `addClaim` was successfully called. - - -#### ClaimAdded - -MUST be triggered when `approve` was called and the claim was successfully added. - - -## Constraints - -- A claim can only be one type per type per issuer. +This would looks as follows for `myNewKeyType`: +version 0 `myNewKeyType`: `0xa94996022594f93c34a730df0ae89d1ecd69dff98c17d0387e69ce58346323a4` +version 1 `myNewKeyType-1`: `0xb6dace1ed14874742c4d1b8cd9b270305176f769e0ae22118a02c2db4e620f29` +version 2 `myNewKeyType-2`: `0x6cc96a01de588f4550e8c3a821aed065ae7897f8dfb61836c78c0389e499d9ed` +... +Anyone that would like to standardize a new data key should make a pull request to update the table below. +| Name | Description | Key | value | +| --- | --- | --- | --- | +| owner | The owner of the proxy account | 0x0000000000000000000000000000000000000000000000000000000000000000 | left padded owner address, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` | +| 735 | The proxy accounts claim holder contract (per [ERC735](https://github.com/ethereum/EIPs/issues/735)) | 0xb0f23aea7d77ce19f9393243a7b50a3bcaac893c7d68a5a309dea7cacf035fd0 | left padded address of the claim holder contract, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` | +| 780 | The proxy accounts claim holder contract (per [ERC735](https://github.com/ethereum/EIPs/issues/735)) | 0xdaf52dba5981246bcf8fd7c6b00dce587fdcf5e2a95b281eea95dcd1376afdcd | left padded address of the claim registry contract, e.g. `0x000000000000000000000000de0B295669a9FD93d5F28D9Ec85E40f4cb697BAe` | ## Rationale -This specification was chosen to allow most flexibility and experimentation around identity. By having each identity in a separate contract it allows for cross identity compatibility, but at the same time extra and altered functionality for new use cases. -The main critic of this standard is the verification where each identity that issues a claim, also should have a separate CLAIM signing key attached. While [#ERC780](https://github.com/ethereum/EIPs/issues/780) uses a standardized registry to assign claims to addresses. -Both systems could work in conjunction and should be explored. -While also off-chain claims using DID verifiable claims and merkle tries can be added as claims and should be explored. +The purpose of an identity proxy is to allow an entity to exist as a first-class citizen in Ethereum, with the ability to execute arbitrary contract calls. At that same time the proxy account should be managed by an arbitrary simple or complex logic. -The rationale of this standard is to function as an open and very flexible container for identity. +It also opens up the possibility of [meta transactions](https://medium.com/@austin_48503/ethereum-meta-transactions-90ccf0859e84), where a third party can send a transaction to the owner contract, that then verifies the execution permission based on a signed message. + +It further allows any information to be attached to that proxy accounts which can be in the forms of claims via [ERC735](https://github.com/ethereum/EIPs/issues/735) or [ERC780](https://github.com/ethereum/EIPs/issues/780), or any arbitrary new systems and protocols. + +This specification was chosen to allow the most flexibility and experimentation around verifiable manageable accounts. ## Implementation -- [DID resolver specification](https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-spring2018/blob/master/topics-and-advance-readings/DID-Method-erc725.md) -- [Implementation by mirceapasoi](https://github.com/mirceapasoi/erc725-735) -- [Implementation by Nick Poulden](https://github.com/OriginProtocol/identity-playground), interface at: https://erc725.originprotocol.com/ +- [Implementation by ERC725Alliance](https://github.com/ERC725Alliance/erc725/tree/master/contracts/contracts) ### Solidity Interface ```js -pragma solidity ^0.4.18; +pragma solidity ^0.5.4; -contract ERC725 { +interface ERC725 { + event DataChanged(bytes32 indexed key, bytes32 indexed value); + event OwnerChanged(address indexed ownerAddress); + event ContractCreated(address indexed contractAddress); - uint256 constant MANAGEMENT_KEY = 1; - uint256 constant ACTION_KEY = 2; - uint256 constant CLAIM_SIGNER_KEY = 3; - uint256 constant ENCRYPTION_KEY = 4; + // address public owner; - event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType); - event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType); - event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); - event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); - event Approved(uint256 indexed executionId, bool approved); - - struct Key { - uint256 purpose; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc. - uint256 keyType; // e.g. 1 = ECDSA, 2 = RSA, etc. - bytes32 key; - } - - function getKey(bytes32 _key) public constant returns(uint256 purpose, uint256 keyType, bytes32 key); - function keyHasPurpose(bytes32 _key, uint256 _purpose) public constant returns (bool exists); - function getKeysByPurpose(uint256 _purpose) public constant returns (bytes32[] keys); - function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success); - function removeKey(bytes32 _key, uint256 _purpose) public returns (bool success); - function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId); - function approve(uint256 _id, bool _approve) public returns (bool success); + function changeOwner(address _owner) external; + function getData(bytes32 _key) external view returns (bytes32 _value); + function setData(bytes32 _key, bytes32 _value) external; + function execute(uint256 _operationType, address _to, uint256 _value, bytes calldata _data) external; } ``` From d970b2385eb1bf668c486c39eafcee2829808e02 Mon Sep 17 00:00:00 2001 From: Fabian Vogelsteller Date: Mon, 25 Mar 2019 22:24:01 +0100 Subject: [PATCH 115/431] Automatically merged updates to draft EIP(s) 725 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-725.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-725.md b/EIPS/eip-725.md index 063a0674..c69731a5 100644 --- a/EIPS/eip-725.md +++ b/EIPS/eip-725.md @@ -1,7 +1,7 @@ --- eip: 725 -title: Proxy Identity -author: Fabian Vogelsteller (@frozeman) +title: Proxy Account +author: Fabian Vogelsteller (@frozeman), Tyler Yasaka (@tyleryasaka) discussions-to: https://github.com/ethereum/EIPs/issues/725 status: Draft type: Standards Track @@ -31,7 +31,7 @@ the benefit is a persistent account that is independed from single keys and can Returns the current owner ```js -function address public owner; +address public owner; ``` #### changeOwner From 9e4283608c5e0e8a6934e412c6afc19cd74b9b6d Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 26 Mar 2019 01:21:07 +0100 Subject: [PATCH 116/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 430 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 328 insertions(+), 102 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index f76f4b68..348569cf 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -18,21 +18,40 @@ This EIP defines standard interfaces and behaviors for token contracts. This standard defines a new way to interact with a token contract while remaining backward compatible with [ERC20]. -It defines advanced features to interact with tokens. Namely, *operators* to send tokens on behalf of another address—contract or regular account—and send/receive *hooks* to offer token holders more control over their tokens. +It defines advanced features to interact with tokens. +Namely, *operators* to send tokens on behalf of another address—contract or regular account—and +send/receive *hooks* to offer token holders more control over their tokens. -It takes advantage of [ERC1820] to find out whether and where to notify contracts and regular addresses when they receive tokens as well as to allow compatibility with already-deployed contracts. +It takes advantage of [ERC1820] to find out whether and where to notify contracts and regular addresses +when they receive tokens as well as to allow compatibility with already-deployed contracts. ## Motivation -This standard tries to improve the widely used [ERC20] token standard. The main advantages of this standard are: +This standard tries to improve the widely used [ERC20] token standard. +The main advantages of this standard are: 1. Uses the same philosophy as Ether in that tokens are sent with `send(dest, value, data)`. -2. Both contracts and regular addresses can control and reject which token they send by registering a `tokensToSend` hook. (Rejection is done by `revert`ing in the hook function.) -3. Both contracts and regular addresses can control and reject which token they receive by registering a `tokensReceived` hook. (Rejection is done by `revert`ing in the hook function.) -4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. -5. The token holder can "authorize" and "revoke" operators which can send tokens on their behalf. These operators are intended to be verified contracts such as an exchange, a cheque processor or an automatic charging system. -6. Every token transaction contains `data` and `operatorData` bytes fields to be used freely to pass data from the token holder and the operator, respectively. -7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function by deploying a proxy contract implementing the `tokensReceived` hook for the wallet. + +2. Both contracts and regular addresses can control and reject which token they send + by registering a `tokensToSend` hook. + (Rejection is done by `revert`ing in the hook function.) + +3. Both contracts and regular addresses can control and reject which token they receive + by registering a `tokensReceived` hook. + (Rejection is done by `revert`ing in the hook function.) + +4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, + unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. + +5. The token holder can "authorize" and "revoke" operators which can send tokens on their behalf. + These operators are intended to be verified contracts + such as an exchange, a cheque processor or an automatic charging system. + +6. Every token transaction contains `data` and `operatorData` bytes fields + to be used freely to pass data from the token holder and the operator, respectively. + +7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function + by deploying a proxy contract implementing the `tokensReceived` hook for the wallet. ## Specification @@ -93,7 +112,8 @@ the `keccak256` hash of `ERC777Token` as the interface hash and `0x0` as the imp When interacting with the token contract, all amounts and balances MUST be unsigned integers. I.e. Internally, all values are stored as a denomination of 1E-18 of a token. -The display denomination—to display any amount to the end user—MUST be 1018 of the internal denomination. +The display denomination—to display any amount to the end user—MUST +be 1018 of the internal denomination. In other words, the internal denomination is similar to a wei and the display denomination is similar to an ether. @@ -105,7 +125,7 @@ the contract MUST be called with an amount of `300,000,000,000,000,000` (0.3&tim User Interfaces which are generated programmatically from the ABI of the token contract MAY use and display the internal denomination. -But this MUST be made clear, for example by displaying the `uint256` type. +But this MUST be made clear, for example by displaying the `uint256` type. #### **View Functions** @@ -139,10 +159,11 @@ function totalSupply() external view returns (uint256) Get the total number of minted tokens. -*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as returned by the `balanceOf` function. - -*NOTE*: The total supply MUST be equal to the sum of all the minted tokens as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. +*NOTE*: The total supply MUST be equal to the sum of the balances of all addresses—as +returned by the `balanceOf` function. +*NOTE*: The total supply MUST be equal to the sum of all the minted tokens +as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. > **returns:** Total supply of tokens currently in circulation. @@ -169,55 +190,94 @@ function granularity() external view returns (uint256) Get the smallest part of the token that's not divisible. -In other words, the granularity is the smallest number of tokens (in the basic unit) which MAY be minted, sent or burned at any time. +In other words, the granularity is the smallest number of tokens (in the basic unit) +which MAY be minted, sent or burned at any time. The following rules MUST be applied regarding the *granularity*: - The *granularity* value MUST be set at creation time. -- The *granularity* value MUST NOT be changed ever. -- The *granularity* value MUST be greater or equal to `1`. -- Any minting, send or burning of tokens MUST be a multiple of the *granularity* value. -- Any operation that would result in a balance that's not a multiple of the *granularity* value MUST be considered invalid, and the transaction MUST `revert`. -*NOTE*: Most of the tokens SHOULD be fully partitionable. I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token. +- The *granularity* value MUST NOT be changed ever. + +- The *granularity* value MUST be greater or equal to `1`. + +- Any minting, send or burning of tokens MUST be a multiple of the *granularity* value. + +- Any operation that would result in a balance that's not a multiple of the *granularity* value + MUST be considered invalid, and the transaction MUST `revert`. + +*NOTE*: Most of the tokens SHOULD be fully partition-able. +I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token. > **returns:** The smallest non-divisible part of the token. -*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, defined under the [operators] for consistency. +*NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, +defined under the [operators] for consistency. *[ERC20] compatibility requirement*: -The decimals of the token MUST always be `18`. For a *pure* ERC777 token the [ERC20] `decimals` function is OPTIONAL, and its existence SHALL NOT be relied upon when interacting with the token contract. (The decimal value of `18` is implied.) For an [ERC20] compatible token, the `decimals` function is REQUIRED and MUST return `18`. (In [ERC20], the `decimals` function is OPTIONAL. If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`. Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.) +The decimals of the token MUST always be `18`. +For a *pure* ERC777 token the [ERC20] `decimals` function is OPTIONAL, +and its existence SHALL NOT be relied upon when interacting with the token contract. +(The decimal value of `18` is implied.) +For an [ERC20] compatible token, the `decimals` function is REQUIRED and MUST return `18`. +(In [ERC20], the `decimals` function is OPTIONAL. +If the function is not present, the `decimals` value is not clearly defined and may be assumed to be `0`. +Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] compatible tokens.) #### **Operators** An `operator` is an address which is allowed to send and burn tokens on behalf of some *token holder*. -When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted. The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively. +When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted. +The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) +MUST be the addresses of the *operator* and the *token holder* respectively. -When a *token holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. The `RevokedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) MUST be the addresses of the *operator* and the *token holder* respectively. +When a *token holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. +The `RevokedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) +MUST be the addresses of the *operator* and the *token holder* respectively. *NOTE*: A *token holder* MAY have multiple *operators* at the same time. -The token MAY define *default operators*. A *default operator* is an implicitly authorized *operator* for all *token holders*. `AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*. The rules below apply to *default operators*: +The token MAY define *default operators*. +A *default operator* is an implicitly authorized *operator* for all *token holders*. +`AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*. +The rules below apply to *default operators*: - The token contract MUST define *default operators* at creation time. + - The *default operators* MUST be invariants. I.e., the token contract MUST NOT add or remove *default operators* ever. + - `AuthorizedOperator` events MUST NOT be emitted when defining *default operators*. -- A *token holder* MUST be allowed revoke a *default operator* (unless the *token holder* is the *default operator* in question). + +- A *token holder* MUST be allowed revoke a *default operator* + (unless the *token holder* is the *default operator* in question). + - A *token holder* MUST be allowed to re-authorize a previously revoked *default operator*. -- When a *default operator* is explicitly authorized or revoked for a specific *token holder*, an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted. + +- When a *default operator* is explicitly authorized or revoked for a specific *token holder*, + an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted. The following rules apply to any *operator*: - An address MUST always be an *operator* for itself. Hence an address MUST NOT ever be revoked as its own *operator*. + - If an address is an *operator* for a *token holder*, `isOperatorFor` MUST return `true`. + - If an address is not an *operator* for a *token holder*, `isOperatorFor` MUST return `false`. -- The token contract MUST emit an `AuthorizedOperator` event with the correct values when a *token holder* authorizes an address as its *operator* as defined in the [`AuthorizedOperator` Event][authorizedoperator]. -- The token contract MUST emit a `RevokedOperator` event with the correct values when a *token holder* revokes an address as its *operator* as defined in the [`RevokedOperator` Event][revokedoperator]. -*NOTE*: A *token holder* MAY authorize an already authorized *operator*. An `AuthorizedOperator` MUST be emitted each time. +- The token contract MUST emit an `AuthorizedOperator` event with the correct values + when a *token holder* authorizes an address as its *operator* as defined in the + [`AuthorizedOperator` Event][authorizedoperator]. -*NOTE*: A *token holder* MAY revoke an already revoked *operator*. A `RevokedOperator` MUST be emitted each time. +- The token contract MUST emit a `RevokedOperator` event with the correct values + when a *token holder* revokes an address as its *operator* as defined in the + [`RevokedOperator` Event][revokedoperator]. + +*NOTE*: A *token holder* MAY authorize an already authorized *operator*. +An `AuthorizedOperator` MUST be emitted each time. + +*NOTE*: A *token holder* MAY revoke an already revoked *operator*. +A `RevokedOperator` MUST be emitted each time. **`AuthorizedOperator` event** @@ -233,7 +293,6 @@ Indicates the authorization of `operator` as an *operator* for `tokenHolder`. > `operator`: Address which became an *operator* of `tokenHolder`. > `tokenHolder`: Address of a token holder which authorized the `operator` address as an *operator*. - **`RevokedOperator` event** ``` solidity @@ -248,7 +307,8 @@ Indicates the revocation of `operator` as an *operator* for `tokenHolder`. > `operator`: Address which was revoked as an *operator* of `tokenHolder`. > `tokenHolder`: Address of a token holder which revoked the `operator` address as an *operator*. -The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below MUST be implemented to manage *operators*. +The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below +MUST be implemented to manage *operators*. Token contracts MAY implement other functions to manage *operators*. **`defaultOperators` function** @@ -271,7 +331,10 @@ function authorizeOperator(address operator) external Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf. -*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to authorize the token holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). +*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. +This right SHALL NOT be revoked. +Hence this function MUST `revert` if it is called to authorize the token holder (`msg.sender`) +as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). > **parameters** > `operator`: Address to set as an *operator* for `msg.sender`. @@ -284,7 +347,10 @@ function revokeOperator(address operator) external Remove the right of the `operator` address to be an *operator* for `msg.sender` and to send and burn tokens on its behalf. -*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to revoke the token holder (`msg.sender`) as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). +*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. +This right SHALL NOT be revoked. +Hence this function MUST `revert` if it is called to revoke the token holder (`msg.sender`) +as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). > **parameters** > `operator`: Address to rescind as an *operator* for `msg.sender`. @@ -303,28 +369,48 @@ Indicate whether the `operator` address is an *operator* of the `tokenHolder` ad > > **returns:** `true` if `operator` is an *operator* of `tokenHolder` and `false` otherwise. -*NOTE*: To know which addresses are *operators* for a given *token holder*, one MUST call `isOperatorFor` with the *token holder* for each *default operator* and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *token holder* in question. +*NOTE*: To know which addresses are *operators* for a given *token holder*, +one MUST call `isOperatorFor` with the *token holder* for each *default operator* +and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *token holder* in question. #### **Sending Tokens** -When an *operator* sends an `amount` of tokens from a *token holder* to a *recipient* with the associated `data` and `operatorData`, the token contract MUST apply the following rules: +When an *operator* sends an `amount` of tokens from a *token holder* to a *recipient* +with the associated `data` and `operatorData`, the token contract MUST apply the following rules: - Any authorized *operator* MAY send tokens to any *recipient* (except to `0x0`). + - The balance of the *token holder* MUST be decreased by the `amount`. + - The balance of the *recipient* MUST be increased by the `amount`. -- The balance of the *token holder* MUST be greater or equal to the `amount`—such that its resulting balance is greater or equal to zero (`0`) after the send. + +- The balance of the *token holder* MUST be greater or equal to the `amount`—such + that its resulting balance is greater or equal to zero (`0`) after the send. + - The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent]. + - The *operator* MAY include information in the `operatorData`. -- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. -- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. -- The `data` and `operatorData` MUST be immutable during the entire send process—hence the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event. + +- The token contract MUST call the `tokensToSend` hook of the *token holder* + if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. + +- The token contract MUST call the `tokensReceived` hook of the *recipient* + if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. + +- The `data` and `operatorData` MUST be immutable during the entire send process—hence + the same `data` and `operatorData` MUST be used to call both hooks and emit the `Sent` event. The token contract MUST `revert` when sending in any of the following cases: - The *operator* address is not an authorized operator for the *token holder*. -- The resulting *token holder* balance or *recipient* balance after the send is not a multiple of the *granularity* defined by the token contract. + +- The resulting *token holder* balance or *recipient* balance after the send + is not a multiple of the *granularity* defined by the token contract. + - The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. + - The address of the *token holder* or the *recipient* is `0x0`. + - Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`). The token contract MAY send tokens from many *token holders*, to many *recipients*, or both. In this case: @@ -335,25 +421,35 @@ The token contract MAY send tokens from many *token holders*, to many *recipient - A `Sent` event MUST be emitted for every *token holder* and *recipient* pair with the corresponding amount for each pair. - The sum of all the amounts from the `Sent` event MUST be equal to the total sent `amount`. -*NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*: the intended *recipient* and the fee *recipient*. +*NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*: +the intended *recipient* and the fee *recipient*. -*NOTE*: Transfer of tokens MAY be chained. For example, if a contract upon receiving tokens sends them further to another address. In this case, the previous send rules apply to each send, in order. +*NOTE*: Transfer of tokens MAY be chained. +For example, if a contract upon receiving tokens sends them further to another address. +In this case, the previous send rules apply to each send, in order. *NOTE*: Sending an amount of zero (`0`) tokens is valid and MUST be treated as a regular send. *Implementation Requirement*: - The token contract MUST call the `tokensToSend` hook *before* updating the state. - The token contract MUST call the `tokensReceived` hook *after* updating the state. -I.e., `tokensToSend` MUST be called first, then the balances MUST be updated to reflect the send, and finally `tokensReceived` MUST be called *afterward*. Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send. +I.e., `tokensToSend` MUST be called first, +then the balances MUST be updated to reflect the send, +and finally `tokensReceived` MUST be called *afterward*. +Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send +and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send. *NOTE*: The `data` field contains information provided by the token holder—similar to the data field in a regular ether send transaction. -The `tokensToSend()` hook, the `tokensReceived()`, or both +The `tokensToSend()` hook, the `tokensReceived()`, or both MAY use the information to decide if they wish to reject the transaction. *NOTE*: The `operatorData` field is analogous to the `data` field except it SHALL be provided by the *operator*. -The `operatorData` MUST only be provided by the *operator*. It is intended more for logging purposes and particular cases. (Examples include payment references, cheque numbers, countersignatures and more.) In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. +The `operatorData` MUST only be provided by the *operator*. +It is intended more for logging purposes and particular cases. +(Examples include payment references, cheque numbers, countersignatures and more.) +In most of the cases the recipient would ignore the `operatorData`, or at most, it would log the `operatorData`. **`Sent` event** @@ -399,11 +495,18 @@ function operatorSend(address from, address to, uint256 amount, bytes calldata d Send the `amount` of tokens on behalf of the address `from` to the address `to`. -The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the `from` (*token holder*) used for the send MUST be `msg.sender` (the `operator`). +The *operator* MUST be `msg.sender`. +The value of `from` MAY be `0x0`, +then the `from` (*token holder*) used for the send MUST be `msg.sender` (the `operator`). -*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the send process MUST `revert`. +*Reminder*: If the *operator* address is not an authorized operator of the `from` address, +then the send process MUST `revert`. -*NOTE*: `from` and `msg.sender` MAY be the same address. I.e., an address MAY call `operatorSend` for itself. This call MUST be equivalent to `send` with the addition that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `send` function). +*NOTE*: `from` and `msg.sender` MAY be the same address. +I.e., an address MAY call `operatorSend` for itself. +This call MUST be equivalent to `send` with the addition +that the *operator* MAY specify an explicit value for `operatorData` +(which cannot be done with the `send` function). > **parameters** > `from`: Token holder (or `0x0` to set `from` to `msg.sender`). @@ -414,17 +517,29 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the #### **Minting Tokens** -Minting tokens is the act of producing new tokens. [ERC777] intentionally does not define specific functions to mint tokens. This intent comes from the wish not to limit the use of the [ERC777] standard as the minting process is generally specific for every token. +Minting tokens is the act of producing new tokens. +[ERC777] intentionally does not define specific functions to mint tokens. +This intent comes from the wish not to limit the use of the [ERC777] standard +as the minting process is generally specific for every token. Nonetheless, the rules below MUST be respected when minting for a *recipient*: - Tokens MAY be minted for any *recipient* address. + - The total supply MUST be increased by the amount of tokens minted. + - The balance of `0x0` MUST NOT be decreased. + - The balance of the *recipient* MUST be increased by the amount of tokens minted. + - The token contract MUST emit a `Minted` event with the correct values as defined in the [`Minted` Event][minted]. -- The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. -- The `data` and `operatorData` MUST be immutable during the entire mint process—hence the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. + +- The token contract MUST call the `tokensReceived` hook of the *recipient* + if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. + +- The `data` and `operatorData` MUST be immutable during the entire mint process—hence + the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. + - The `data` field MUST be empty. The token contract MUST `revert` when minting in any of the following cases: @@ -433,10 +548,15 @@ The token contract MUST `revert` when minting in any of the following cases: - The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. - The address of the *recipient* is `0x0`. -*NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting for the amount of the initial supply to the address(es) receiving the initial supply. This means one or more `Minted` events must be emitted and the `tokensReceived` hook of the recipient(s) MUST be called. +*NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting +for the amount of the initial supply to the address(es) receiving the initial supply. +This means one or more `Minted` events must be emitted +and the `tokensReceived` hook of the recipient(s) MUST be called. *[ERC20] compatibility requirement*: -While a `Sent` event MUST NOT be emitted when minting, if the token contract is [ERC20] backward compatible, a `Transfer` event with the `from` parameter set to `0x0` SHOULD be emitted as defined in the [ERC20] standard. +While a `Sent` event MUST NOT be emitted when minting, +if the token contract is [ERC20] backward compatible, +a `Transfer` event with the `from` parameter set to `0x0` SHOULD be emitted as defined in the [ERC20] standard. The token contract MAY mint tokens for multiple *recipients* at once. In this case: @@ -448,7 +568,7 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca *NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint. *NOTE*: The `operatorData` field contains information provided by the *operator*—similar -to the data field in a regular ether send transaction. +to the data field in a regular ether send transaction. The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction. **`Minted` event** @@ -470,27 +590,46 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` #### **Burning Tokens** -Burning tokens is the act of destroying existing tokens. [ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`). These functions facilitate the integration of the burning process in wallets and dapps. However, the token contract MAY prevent some or all *token holders* from burning tokens for any reason. The token contract MAY also define other functions to burn tokens. +Burning tokens is the act of destroying existing tokens. +[ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`). +These functions facilitate the integration of the burning process in wallets and dapps. +However, the token contract MAY prevent some or all *token holders* from burning tokens for any reason. +The token contract MAY also define other functions to burn tokens. The rules below MUST be respected when burning the tokens of a *token holder*: - Tokens MAY be burned from any *token holder* address. + - The total supply MUST be decreased by the amount of tokens burned. + - The balance of `0x0` MUST NOT be increased. + - The balance of the *token holder* MUST be decreased by amount of tokens burned. + - The token contract MUST emit a `Burned` event with the correct values as defined in the [`Burned` Event][burned]. -- The token contract MUST call the `tokensToSend` hook of the *token holder* if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. -- The `operatorData` MUST be immutable during the entire burn process—hence the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. + +- The token contract MUST call the `tokensToSend` hook of the *token holder* + if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. + +- The `operatorData` MUST be immutable during the entire burn process—hence + the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. The token contract MUST `revert` when burning in any of the following cases: - The *operator* address is not an authorized operator for the *token holder*. -- The resulting *token holder* balance after the burn is not a multiple of the *granularity* defined by the token contract. -- The balance of *token holder* is inferior to the amount of tokens to burn (i.e., resulting in a negative balance for the *token holder*). + +- The resulting *token holder* balance after the burn is not a multiple of the *granularity* + defined by the token contract. + +- The balance of *token holder* is inferior to the amount of tokens to burn + (i.e., resulting in a negative balance for the *token holder*). + - The address of the *token holder* is `0x0`. *[ERC20] compatibility requirement*: -While a `Sent` event MUST NOT be emitted when burning; if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted. The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice. +While a `Sent` event MUST NOT be emitted when burning; +if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted. +The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice. The token contract MAY burn tokens for multiple *token holders* at once. In this case: @@ -550,9 +689,12 @@ function operatorBurn(address from, uint256 amount, bytes calldata data, bytes c Burn the `amount` of tokens on behalf of the address `from`. -The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the `from` (*token holder*) used for the burn MUST be `msg.sender` (the `operator`). +The *operator* MUST be `msg.sender`. +The value of `from` MAY be `0x0`, +then the `from` (*token holder*) used for the burn MUST be `msg.sender` (the `operator`). -*Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`. +*Reminder*: If the *operator* address is not an authorized operator of the `from` address, +then the burn process MUST `revert`. > **parameters** > `from`: Token holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`). @@ -560,13 +702,20 @@ The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, then the > `data`: Information provided by the *token holder*. > `operatorData`: Information provided by the *operator*. -*NOTE*: The *operator* MAY pass any information via `operatorData`. The `operatorData` MUST only be provided by the *operator*. +*NOTE*: The *operator* MAY pass any information via `operatorData`. +The `operatorData` MUST only be provided by the *operator*. -*NOTE*: `from` and `msg.sender` MAY be the same address. I.e., an address MAY call `operatorBurn` for itself. This call MUST be equivalent to `burn` with the addition that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `burn` function). +*NOTE*: `from` and `msg.sender` MAY be the same address. +I.e., an address MAY call `operatorBurn` for itself. +This call MUST be equivalent to `burn` +with the addition that the *operator* MAY specify an explicit value for `operatorData` +(which cannot be done with the `burn` function). #### **`ERC777TokensSender` And The `tokensToSend` Hook** -The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. +The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. +Any address (regular or contract) wishing to be notified of token debits from their address +MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. ``` solidity interface ERC777TokensSender { @@ -581,7 +730,10 @@ interface ERC777TokensSender { } ``` -*NOTE*: A regular address MAY register a different address—the address of a contract—implementing the interface on its behalf. A contract MAY register either its address or the address of another contract but said address MUST implement the interface on its behalf. +*NOTE*: A regular address MAY register a different address—the address of a contract—implementing +the interface on its behalf. +A contract MAY register either its address or the address of another contract +but said address MUST implement the interface on its behalf. **`tokensToSend`** @@ -589,7 +741,8 @@ interface ERC777TokensSender { function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external ``` -Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. +Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address +by the `operator` address. *NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process. @@ -604,26 +757,44 @@ Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` addr The following rules apply when calling the `tokensToSend` hook: - The `tokensToSend` hook MUST be called every time the balance is decremented. + - The `tokensToSend` hook MUST be called *before* the state is updated—i.e. *before* the balance is decremented. + - `operator` MUST be the address which triggered the decrease of the balance. + - `from` MUST be the address of the *token holder* whose balance is decreased. + - `to` MUST be the address of the *recipient* whose balance is increased for a send. + - `to` MUST be `0x0` for a burn. + - `amount` MUST be the number of tokens the *token holder* balance is decreased by. + - `data` MUST contain the extra information provided by the *token holder* (if any) for a send. -- `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any). -- The *token holder* MAY block a decrease of its balance by `revert`ing. (I.e., reject the withdrawal of tokens from its account.) + +- `operatorData` MUST contain the extra information provided by the address + which triggered the decrease of the balance (if any). + +- The *token holder* MAY block a decrease of its balance by `revert`ing. + (I.e., reject the withdrawal of tokens from its account.) *NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensSender`. -*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. Hence the `ERC777TokensSender` MUST expect to be called by different token contracts. The `msg.sender` of the `tokensToSend` call is expected to be the address of the token contract. +*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. +Hence the `ERC777TokensSender` MUST expect to be called by different token contracts. +The `msg.sender` of the `tokensToSend` call is expected to be the address of the token contract. *[ERC20] compatibility requirement*: -This hook takes precedence over [ERC20] and MUST be called (if registered) when calling [ERC20]'s `transfer` and `transferFrom` event. When called from a `transfer`, `operator` MUST be the same value as the `from`. When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. +This hook takes precedence over [ERC20] and MUST be called (if registered) +when calling [ERC20]'s `transfer` and `transferFrom` event. +When called from a `transfer`, `operator` MUST be the same value as the `from`. +When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. #### **`ERC777TokensRecipient` And The `tokensReceived` Hook** -The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*. Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. +The `tokensReceived` hook notifies of any increment of the balance (send and mint) for a given *recipient*. +Any address (regular or contract) wishing to be notified of token credits to their address +MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. ``` solidity interface ERC777TokensRecipient { @@ -638,12 +809,16 @@ interface ERC777TokensRecipient { } ``` -If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation; the token contract: +If the *recipient* is a contract, which has not registered an `ERC777TokensRecipient` implementation; +then the token contract: - MUST `revert` if the `tokensReceived` hook is called from a mint or send call. - SHOULD accept if the `tokensReceived` hook is called from an ERC20 `transfer` or `transferFrom` call. -*NOTE*: A regular address MAY register a different address—the address of a contract—implementing the interface on its behalf. A contract MUST register either its address or the address of another contract but said address MUST implement the interface on its behalf. +*NOTE*: A regular address MAY register a different address—the address of a contract—implementing +the interface on its behalf. +A contract MUST register either its address or the address of another contract +but said address MUST implement the interface on its behalf. **`tokensReceived`** @@ -651,7 +826,8 @@ If the *recipient* is a contract, which has not registered an `ERC777TokensRecip function tokensReceived(address operator, address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external ``` -Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address by the `operator` address. +Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address +by the `operator` address. *NOTE*: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process. @@ -666,61 +842,92 @@ Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` ad The following rules apply when calling the `tokensReceived` hook: - The `tokensReceived` hook MUST be called every time the balance is incremented. + - The `tokensReceived` hook MUST be called *after* the state is updated—i.e. *after* the balance is incremented. + - `operator` MUST be the address which triggered the increase of the balance. + - `from` MUST be the address of the *token holder* whose balance is decreased for a send. + - `from` MUST be `0x0` for a mint. + - `to` MUST be the address of the *recipient* whose balance is increased. + - `amount` MUST be the number of tokens the *recipient* balance is increased by. -- `operatorData` MUST contain the extra information provided by the address which triggered the increase of the balance (if any). +- `operatorData` MUST contain the extra information provided by the address + which triggered the increase of the balance (if any). - The *token holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.) *NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensRecipient`. -*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. Hence the `ERC777TokensRecipient` MUST expect to be called by different token contracts. The `msg.sender` of the `tokensReceived` call is expected to be the address of the token contract. +*NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. +Hence the `ERC777TokensRecipient` MUST expect to be called by different token contracts. +The `msg.sender` of the `tokensReceived` call is expected to be the address of the token contract. *[ERC20] compatibility requirement*: -This hook takes precedence over [ERC20] and MUST be called (if registered) when calling [ERC20]'s `transfer` and `transferFrom` event. When called from a `transfer`, `operator` MUST be the same value as the `from`. When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. +This hook takes precedence over [ERC20] and MUST be called (if registered) +when calling [ERC20]'s `transfer` and `transferFrom` event. +When called from a `transfer`, `operator` MUST be the same value as the `from`. +When called from a `transferFrom`, `operator` MUST be the address which issued the `transferFrom` call. #### **Note On Gas Consumption** -Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens—using [`eth_estimateGas`][eth_estimateGas]—to avoid running out of gas during the transaction. +Dapps and wallets SHOULD first estimate the gas required when sending, minting, or burning tokens—using +[`eth_estimateGas`][eth_estimateGas]—to avoid running out of gas during the transaction. ### Logo -| **Image** |  ![beige logo] |  ![white logo] |  ![light grey logo] |  ![dark grey logo] |  ![black logo][black logo] | -|----------:|:---------:|:---------:|:------------:|:-----------:|:---------:| -| **Color** | beige | white | light grey | dark grey | black | -| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` | +| **Image** | ![beige logo] | ![white logo] | ![light grey logo] | ![dark grey logo] | ![black logo] | +|----------:|:-------------:|:-------------:|:------------------:|:-----------------:|:-------------:| +| **Color** | beige | white | light grey | dark grey | black | +| **Hex** | `#C99D66` | `#FFFFFF` | `#EBEFF0` | `#3C3C3D` | `#000000` | -The logo MAY be used, modified and adapted to promote valid [ERC777] token implementations and [ERC777] compliant technologies such as wallets and dapps. +The logo MAY be used, modified and adapted to promote valid [ERC777] token implementations +and [ERC777] compliant technologies such as wallets and dapps. [ERC777] token contract authors MAY create a specific logo for their token based on this logo. -The logo MUST NOT be used to advertise, promote or associate in any way technology—such as tokens—which is not [ERC777] compliant. +The logo MUST NOT be used to advertise, promote or associate in any way technology—such +as tokens—which is not [ERC777] compliant. -The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] folder in `SVG` and `PNG` formats. The `PNG` version of the logo offers a few sizes in pixels. If needed, other sizes MAY be created by converting from `SVG` into `PNG`. +The logo for the standard can be found in the [`/assets/eip-777/logo`][logos] folder in `SVG` and `PNG` formats. +The `PNG` version of the logo offers a few sizes in pixels. +If needed, other sizes MAY be created by converting from `SVG` into `PNG`. ## Rationale -This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. It avoids the problems and vulnerabilities of [EIP223]. +This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. +It avoids the problems and vulnerabilities of [EIP223]. -It goes a step further by allowing *operators* (generally contracts) which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. Finally, it adds hooks to provide further control to *token holders* over their tokens. Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks. +It goes a step further by allowing *operators* (generally contracts) +which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. +Finally, it adds hooks to provide further control to *token holders* over their tokens. +Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts +without having to be redeployed thanks proxy contracts implementing the hooks. ## Backward Compatibility This EIP does not introduce backward incompatibilities and is backward compatible with the older [ERC20] token standard. -This EIP does not use `transfer` and `transferFrom` and uses `send` and `operatorSend` to avoid confusion and mistakes when deciphering which token standard is being used. +This EIP does not use `transfer` and `transferFrom` and uses `send` and `operatorSend` +to avoid confusion and mistakes when deciphering which token standard is being used. -This standard allows the implementation of [ERC20] functions `transfer`, `transferFrom`, `approve` and `allowance` alongside to make a token fully compatible with [ERC20]. +This standard allows the implementation of [ERC20] functions `transfer`, `transferFrom`, `approve` and `allowance` +alongside to make a token fully compatible with [ERC20]. -The token MAY implement `decimals()` for backward compatibility with [ERC20]. If implemented, it MUST always return `18`. +The token MAY implement `decimals()` for backward compatibility with [ERC20]. +If implemented, it MUST always return `18`. -Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data (such as the mapping of balances) overlap without problems. Note however that the following functions are mandatory in [ERC777] and MUST be implemented: `name`, `symbol` `balanceOf` and `totalSupply` (`decimals` is not part of the [ERC777] standard). +Therefore a token contract MAY implement both [ERC20] and [ERC777] in parallel. +The specification of the `view` functions (such as `name`, `symbol`, `balanceOf`, `totalSupply`) and internal data +(such as the mapping of balances) overlap without problems. +Note however that the following functions are mandatory in [ERC777] and MUST be implemented: +`name`, `symbol` `balanceOf` and `totalSupply` +(`decimals` is not part of the [ERC777] standard). -The state-modifying functions from both standards are decoupled and can operate independently from each other. Note that [ERC20] functions SHOULD be limited to only being called from old contracts. +The state-modifying functions from both standards are decoupled and can operate independently from each other. +Note that [ERC20] functions SHOULD be limited to only being called from old contracts. If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC1820]. @@ -734,10 +941,16 @@ Unregistering implies calling the `setInterfaceImplementer` with the token contr the `keccak256` hash of `ERC20Token` as the interface hash and `0x0` as the implementer. (See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.) -The difference for new contracts implementing [ERC20] is that `tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC1820] if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. If any hook is implemented, it MUST be called. Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. - -The table below summarizes the different actions the token contract MUST take when sending, minting and transferring token via [ERC777] and [ERC20]: +The difference for new contracts implementing [ERC20] is that +`tokensToSend` and `tokensReceived` hooks take precedence over [ERC20]. +Even with an [ERC20] `transfer` and `transferFrom` call, the token contract MUST check via [ERC1820] +if the `from` and the `to` address implement `tokensToSend` and `tokensReceived` hook respectively. +If any hook is implemented, it MUST be called. +Note that when calling [ERC20] `transfer` on a contract, if the contract does not implement `tokensReceived`, +the `transfer` call SHOULD still be accepted even if this means the tokens will probably be locked. +The table below summarizes the different actions the token contract MUST take +when sending, minting and transferring token via [ERC777] and [ERC20]:
    Author{% include authorlist.html authors=page.author %}
    Discussions-To{{ page["discussions-to"] | xml_escape }}
    Status{{ page.status | xml_escape }}
    Status{{ page.status | xml_escape }} + {% if page.review-period-end != undefined %} + (review ends {{ page.review-period-end | xml_escape }}) + {% endif %} +
    Type{{ page.type | xml_escape }}
    Category{{ page.category | xml_escape }}
    @@ -772,11 +985,23 @@ The table below summarizes the different actions the token contract MUST take wh
    -There is no particular action to take if `tokensToSend` is not implemented. The transfer MUST proceed and only be canceled if another condition is not respected such as lack of funds or a `revert` in `tokensReceived` (if present). +There is no particular action to take if `tokensToSend` is not implemented. +The transfer MUST proceed and only be canceled if another condition is not respected +such as lack of funds or a `revert` in `tokensReceived` (if present). -During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC1820], the token contract SHOULD emit a `Transfer` event for minting and burning and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard). During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted. +During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. +Furthermore, if the token contract declares that it implements `ERC20Token` via [ERC1820], +the token contract SHOULD emit a `Transfer` event for minting and burning +and MUST emit a `Transfer` event for sending (as specified in the [ERC20] standard). +During an [ERC20]'s `transfer` or `transferFrom` functions, a valid `Sent` event MUST be emitted. -Hence for any movement of tokens, two events MAY be emitted: an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burned` (depending on the type of movement). Third-party developers MUST be careful not to consider both events as separate movements. As a general rule, if an application considers the token as an ERC20 token, then only the `Transfer` event MUST be taken into account. If the application considers the token as an ERC777 token, then only the `Sent`, `Minted` and `Burned` events MUST be considered. +Hence for any movement of tokens, two events MAY be emitted: +an [ERC20] `Transfer` and an [ERC777] `Sent`, `Minted` or `Burned` (depending on the type of movement). +Third-party developers MUST be careful not to consider both events as separate movements. +As a general rule, if an application considers the token as an ERC20 token, +then only the `Transfer` event MUST be taken into account. +If the application considers the token as an ERC777 token, +then only the `Sent`, `Minted` and `Burned` events MUST be considered. ## Test Cases @@ -784,7 +1009,8 @@ The [repository with the reference implementation][0xjac/ERC777] contains all th ## Implementation -The GitHub repository [0xjac/ERC777] contains the [reference implementation]. The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. +The GitHub repository [0xjac/ERC777] contains the [reference implementation]. +The reference implementation is also available via [npm][npm/erc777] and can be installed with `npm install erc777`. ## Copyright From 4eb6eab9cb109ca53f2340f2cfc3f16affa1d37c Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 26 Mar 2019 01:34:30 +0100 Subject: [PATCH 117/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 215 ++++++++++++++++++++++++------------------------ 1 file changed, 108 insertions(+), 107 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 348569cf..33469c6f 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -43,12 +43,12 @@ The main advantages of this standard are: 4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. -5. The token holder can "authorize" and "revoke" operators which can send tokens on their behalf. +5. The holder can "authorize" and "revoke" operators which can send tokens on their behalf. These operators are intended to be verified contracts such as an exchange, a cheque processor or an automatic charging system. 6. Every token transaction contains `data` and `operatorData` bytes fields - to be used freely to pass data from the token holder and the operator, respectively. + to be used freely to pass data from the holder and the operator, respectively. 7. It is backward compatible with wallets that do not contain the `tokensReceived` hook function by deploying a proxy contract implementing the `tokensReceived` hook for the wallet. @@ -62,11 +62,11 @@ interface ERC777Token { function name() external view returns (string memory); function symbol() external view returns (string memory); function totalSupply() external view returns (uint256); - function balanceOf(address tokenHolder) external view returns (uint256); + function balanceOf(address holder) external view returns (uint256); function granularity() external view returns (uint256); function defaultOperators() external view returns (address[] memory); - function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + function isOperatorFor(address operator, address holder) external view returns (bool); function authorizeOperator(address operator) external; function revokeOperator(address operator) external; @@ -92,8 +92,8 @@ interface ERC777Token { ); event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); - event AuthorizedOperator(address indexed operator, address indexed tokenHolder); - event RevokedOperator(address indexed operator, address indexed tokenHolder); + event AuthorizedOperator(address indexed operator, address indexed holder); + event RevokedOperator(address indexed operator, address indexed holder); } ``` The token contract MUST implement the above interface. @@ -170,17 +170,17 @@ as defined in all the `Minted` events minus the sum of all the burned tokens as **`balanceOf` function** ``` solidity -function balanceOf(address tokenHolder) external view returns (uint256) +function balanceOf(address holder) external view returns (uint256) ``` -Get the balance of the account with address `tokenHolder`. +Get the balance of the account with address `holder`. The balance MUST be zero (`0`) or higher. > **parameters** -> `tokenHolder`: Address for which the balance is returned. +> `holder`: Address for which the balance is returned. > -> **returns:** Amount of tokens held by `tokenHolder` in the token contract. +> **returns:** Amount of tokens held by `holder` in the token contract. **`granularity` function** @@ -226,20 +226,20 @@ Hence for compatibility reasons, `decimals` MUST be implemented for [ERC20] comp #### **Operators** -An `operator` is an address which is allowed to send and burn tokens on behalf of some *token holder*. +An `operator` is an address which is allowed to send and burn tokens on behalf of some *holder*. -When an address becomes an *operator* for a *token holder*, an `AuthorizedOperator` event MUST be emitted. -The `AuthorizedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) -MUST be the addresses of the *operator* and the *token holder* respectively. +When an address becomes an *operator* for a *holder*, an `AuthorizedOperator` event MUST be emitted. +The `AuthorizedOperator`'s `operator` (topic 1) and `holder` (topic 2) +MUST be the addresses of the *operator* and the *holder* respectively. -When a *token holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. -The `RevokedOperator`'s `operator` (topic 1) and `tokenHolder` (topic 2) -MUST be the addresses of the *operator* and the *token holder* respectively. +When a *holder* revokes an *operator*, a `RevokedOperator` event MUST be emitted. +The `RevokedOperator`'s `operator` (topic 1) and `holder` (topic 2) +MUST be the addresses of the *operator* and the *holder* respectively. -*NOTE*: A *token holder* MAY have multiple *operators* at the same time. +*NOTE*: A *holder* MAY have multiple *operators* at the same time. The token MAY define *default operators*. -A *default operator* is an implicitly authorized *operator* for all *token holders*. +A *default operator* is an implicitly authorized *operator* for all *holders*. `AuthorizedOperator` events MUST NOT be emitted when defining the *default operators*. The rules below apply to *default operators*: @@ -249,63 +249,63 @@ The rules below apply to *default operators*: - `AuthorizedOperator` events MUST NOT be emitted when defining *default operators*. -- A *token holder* MUST be allowed revoke a *default operator* - (unless the *token holder* is the *default operator* in question). +- A *holder* MUST be allowed revoke a *default operator* + (unless the *holder* is the *default operator* in question). -- A *token holder* MUST be allowed to re-authorize a previously revoked *default operator*. +- A *holder* MUST be allowed to re-authorize a previously revoked *default operator*. -- When a *default operator* is explicitly authorized or revoked for a specific *token holder*, +- When a *default operator* is explicitly authorized or revoked for a specific *holder*, an `AuthorizedOperator` or `RevokedOperator` event (respectively) MUST be emitted. The following rules apply to any *operator*: - An address MUST always be an *operator* for itself. Hence an address MUST NOT ever be revoked as its own *operator*. -- If an address is an *operator* for a *token holder*, `isOperatorFor` MUST return `true`. +- If an address is an *operator* for a *holder*, `isOperatorFor` MUST return `true`. -- If an address is not an *operator* for a *token holder*, `isOperatorFor` MUST return `false`. +- If an address is not an *operator* for a *holder*, `isOperatorFor` MUST return `false`. - The token contract MUST emit an `AuthorizedOperator` event with the correct values - when a *token holder* authorizes an address as its *operator* as defined in the + when a *holder* authorizes an address as its *operator* as defined in the [`AuthorizedOperator` Event][authorizedoperator]. - The token contract MUST emit a `RevokedOperator` event with the correct values - when a *token holder* revokes an address as its *operator* as defined in the + when a *holder* revokes an address as its *operator* as defined in the [`RevokedOperator` Event][revokedoperator]. -*NOTE*: A *token holder* MAY authorize an already authorized *operator*. +*NOTE*: A *holder* MAY authorize an already authorized *operator*. An `AuthorizedOperator` MUST be emitted each time. -*NOTE*: A *token holder* MAY revoke an already revoked *operator*. +*NOTE*: A *holder* MAY revoke an already revoked *operator*. A `RevokedOperator` MUST be emitted each time. **`AuthorizedOperator` event** ``` solidity -event AuthorizedOperator(address indexed operator, address indexed tokenHolder) +event AuthorizedOperator(address indexed operator, address indexed holder) ``` -Indicates the authorization of `operator` as an *operator* for `tokenHolder`. +Indicates the authorization of `operator` as an *operator* for `holder`. *NOTE*: This event MUST NOT be emitted outside of an *operator* authorization process. > **parameters** -> `operator`: Address which became an *operator* of `tokenHolder`. -> `tokenHolder`: Address of a token holder which authorized the `operator` address as an *operator*. +> `operator`: Address which became an *operator* of `holder`. +> `holder`: Address of a holder which authorized the `operator` address as an *operator*. **`RevokedOperator` event** ``` solidity -event RevokedOperator(address indexed operator, address indexed tokenHolder) +event RevokedOperator(address indexed operator, address indexed holder) ``` -Indicates the revocation of `operator` as an *operator* for `tokenHolder`. +Indicates the revocation of `operator` as an *operator* for `holder`. *NOTE*: This event MUST NOT be emitted outside of an *operator* revocation process. > **parameters** -> `operator`: Address which was revoked as an *operator* of `tokenHolder`. -> `tokenHolder`: Address of a token holder which revoked the `operator` address as an *operator*. +> `operator`: Address which was revoked as an *operator* of `holder`. +> `holder`: Address of a holder which revoked the `operator` address as an *operator*. The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below MUST be implemented to manage *operators*. @@ -331,9 +331,9 @@ function authorizeOperator(address operator) external Set a third party `operator` address as an *operator* of `msg.sender` to send and burn tokens on its behalf. -*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. +*NOTE*: The *holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. -Hence this function MUST `revert` if it is called to authorize the token holder (`msg.sender`) +Hence this function MUST `revert` if it is called to authorize the holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). > **parameters** @@ -345,11 +345,12 @@ as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). function revokeOperator(address operator) external ``` -Remove the right of the `operator` address to be an *operator* for `msg.sender` and to send and burn tokens on its behalf. +Remove the right of the `operator` address to be an *operator* for `msg.sender` +and to send and burn tokens on its behalf. -*NOTE*: The *token holder* (`msg.sender`) is always an *operator* for itself. +*NOTE*: The *holder* (`msg.sender`) is always an *operator* for itself. This right SHALL NOT be revoked. -Hence this function MUST `revert` if it is called to revoke the token holder (`msg.sender`) +Hence this function MUST `revert` if it is called to revoke the holder (`msg.sender`) as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). > **parameters** @@ -358,41 +359,41 @@ as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). **`isOperatorFor` function** ``` solidity -function isOperatorFor(address operator, address tokenHolder) external view returns (bool) +function isOperatorFor(address operator, address holder) external view returns (bool) ``` -Indicate whether the `operator` address is an *operator* of the `tokenHolder` address. +Indicate whether the `operator` address is an *operator* of the `holder` address. > **parameters** -> `operator`: Address which may be an *operator* of `tokenHolder`. -> `tokenHolder`: Address of a token holder which may have the `operator` address as an *operator*. +> `operator`: Address which may be an *operator* of `holder`. +> `holder`: Address of a holder which may have the `operator` address as an *operator*. > -> **returns:** `true` if `operator` is an *operator* of `tokenHolder` and `false` otherwise. +> **returns:** `true` if `operator` is an *operator* of `holder` and `false` otherwise. -*NOTE*: To know which addresses are *operators* for a given *token holder*, -one MUST call `isOperatorFor` with the *token holder* for each *default operator* -and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *token holder* in question. +*NOTE*: To know which addresses are *operators* for a given *holder*, +one MUST call `isOperatorFor` with the *holder* for each *default operator* +and parse the `AuthorizedOperator`, and `RevokedOperator` events for the *holder* in question. #### **Sending Tokens** -When an *operator* sends an `amount` of tokens from a *token holder* to a *recipient* +When an *operator* sends an `amount` of tokens from a *holder* to a *recipient* with the associated `data` and `operatorData`, the token contract MUST apply the following rules: - Any authorized *operator* MAY send tokens to any *recipient* (except to `0x0`). -- The balance of the *token holder* MUST be decreased by the `amount`. +- The balance of the *holder* MUST be decreased by the `amount`. - The balance of the *recipient* MUST be increased by the `amount`. -- The balance of the *token holder* MUST be greater or equal to the `amount`—such +- The balance of the *holder* MUST be greater or equal to the `amount`—such that its resulting balance is greater or equal to zero (`0`) after the send. - The token contract MUST emit a `Sent` event with the correct values as defined in the [`Sent` Event][sent]. - The *operator* MAY include information in the `operatorData`. -- The token contract MUST call the `tokensToSend` hook of the *token holder* - if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. +- The token contract MUST call the `tokensToSend` hook of the *holder* + if the *holder* registers an `ERC777TokensSender` implementation via [ERC1820]. - The token contract MUST call the `tokensReceived` hook of the *recipient* if the *recipient* registers an `ERC777TokensRecipient` implementation via [ERC1820]. @@ -402,23 +403,23 @@ with the associated `data` and `operatorData`, the token contract MUST apply the The token contract MUST `revert` when sending in any of the following cases: -- The *operator* address is not an authorized operator for the *token holder*. +- The *operator* address is not an authorized operator for the *holder*. -- The resulting *token holder* balance or *recipient* balance after the send +- The resulting *holder* balance or *recipient* balance after the send is not a multiple of the *granularity* defined by the token contract. - The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. -- The address of the *token holder* or the *recipient* is `0x0`. +- The address of the *holder* or the *recipient* is `0x0`. - Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`). -The token contract MAY send tokens from many *token holders*, to many *recipients*, or both. In this case: +The token contract MAY send tokens from many *holders*, to many *recipients*, or both. In this case: -- The previous send rules MUST apply to all the *token holders* and all the *recipients*. +- The previous send rules MUST apply to all the *holders* and all the *recipients*. - The sum of all the balances incremented MUST be equal to the total sent `amount`. - The sum of all the balances decremented MUST be equal to the total sent `amount`. -- A `Sent` event MUST be emitted for every *token holder* and *recipient* pair with the corresponding amount for each pair. +- A `Sent` event MUST be emitted for every *holder* and *recipient* pair with the corresponding amount for each pair. - The sum of all the amounts from the `Sent` event MUST be equal to the total sent `amount`. *NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*: @@ -439,7 +440,7 @@ and finally `tokensReceived` MUST be called *afterward*. Thus a `balanceOf` call within `tokensToSend` returns the balance of the address *before* the send and a `balanceOf` call within `tokensReceived` returns the balance of the address *after* the send. -*NOTE*: The `data` field contains information provided by the token holder—similar +*NOTE*: The `data` field contains information provided by the *holder*—similar to the data field in a regular ether send transaction. The `tokensToSend()` hook, the `tokensReceived()`, or both MAY use the information to decide if they wish to reject the transaction. @@ -463,10 +464,10 @@ Indicate a send of `amount` of tokens from the `from` address to the `to` addres > **parameters** > `operator`: Address which triggered the send. -> `from`: Token holder. +> `from`: Holder. > `to`: Token recipient. > `amount`: Number of tokens to send. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. The `send` and `operatorSend` functions described below MUST be implemented to send tokens. @@ -480,12 +481,12 @@ function send(address to, uint256 amount, bytes calldata data) external Send the `amount` of tokens from the address `msg.sender` to the address `to`. -The *operator* and the *token holder* MUST both be the `msg.sender`. +The *operator* and the *holder* MUST both be the `msg.sender`. > **parameters** > `to`: Token recipient. > `amount`: Number of tokens to send. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. **`operatorSend` function** @@ -497,7 +498,7 @@ Send the `amount` of tokens on behalf of the address `from` to the address `to`. The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, -then the `from` (*token holder*) used for the send MUST be `msg.sender` (the `operator`). +then the `from` (*holder*) used for the send MUST be `msg.sender` (the `operator`). *Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the send process MUST `revert`. @@ -509,10 +510,10 @@ that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `send` function). > **parameters** -> `from`: Token holder (or `0x0` to set `from` to `msg.sender`). +> `from`: Holder (or `0x0` to set `from` to `msg.sender`). > `to`: Token recipient. > `amount`: Number of tokens to send. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. #### **Minting Tokens** @@ -585,7 +586,7 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` > `operator`: Address which triggered the mint. > `to`: Token recipient. > `amount`: Number of tokens minted. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. #### **Burning Tokens** @@ -593,54 +594,54 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` Burning tokens is the act of destroying existing tokens. [ERC777] explicitly defines two functions to burn tokens (`burn` and `operatorBurn`). These functions facilitate the integration of the burning process in wallets and dapps. -However, the token contract MAY prevent some or all *token holders* from burning tokens for any reason. +However, the token contract MAY prevent some or all *holders* from burning tokens for any reason. The token contract MAY also define other functions to burn tokens. -The rules below MUST be respected when burning the tokens of a *token holder*: +The rules below MUST be respected when burning the tokens of a *holder*: -- Tokens MAY be burned from any *token holder* address. +- Tokens MAY be burned from any *holder* address. - The total supply MUST be decreased by the amount of tokens burned. - The balance of `0x0` MUST NOT be increased. -- The balance of the *token holder* MUST be decreased by amount of tokens burned. +- The balance of the *holder* MUST be decreased by amount of tokens burned. - The token contract MUST emit a `Burned` event with the correct values as defined in the [`Burned` Event][burned]. -- The token contract MUST call the `tokensToSend` hook of the *token holder* - if the *token holder* registers an `ERC777TokensSender` implementation via [ERC1820]. +- The token contract MUST call the `tokensToSend` hook of the *holder* + if the *holder* registers an `ERC777TokensSender` implementation via [ERC1820]. - The `operatorData` MUST be immutable during the entire burn process—hence the same `operatorData` MUST be used to call the `tokensToSend` hook and emit the `Burned` event. The token contract MUST `revert` when burning in any of the following cases: -- The *operator* address is not an authorized operator for the *token holder*. +- The *operator* address is not an authorized operator for the *holder*. -- The resulting *token holder* balance after the burn is not a multiple of the *granularity* +- The resulting *holder* balance after the burn is not a multiple of the *granularity* defined by the token contract. -- The balance of *token holder* is inferior to the amount of tokens to burn - (i.e., resulting in a negative balance for the *token holder*). +- The balance of *holder* is inferior to the amount of tokens to burn + (i.e., resulting in a negative balance for the *holder*). -- The address of the *token holder* is `0x0`. +- The address of the *holder* is `0x0`. *[ERC20] compatibility requirement*: While a `Sent` event MUST NOT be emitted when burning; if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted. The [ERC20] standard does not define the concept of burning tokens, but this is a commonly accepted practice. -The token contract MAY burn tokens for multiple *token holders* at once. In this case: +The token contract MAY burn tokens for multiple *holders* at once. In this case: -- The previous burn rules MUST apply to each *token holders*. +- The previous burn rules MUST apply to each *holders*. - The sum of all the balances decremented MUST be equal to the total burned amount. -- A `Burned` event MUST be emitted for every *token holder* with the corresponding amount for each *token holder*. +- A `Burned` event MUST be emitted for every *holder* with the corresponding amount for each *holder*. - The sum of all the amounts from the `Burned` event MUST be equal to the total burned `amount`. *NOTE*: Burning an amount of zero (`0`) tokens is valid and MUST be treated as a regular burn. -*NOTE*: The `data` field contains information provided by the token holder—similar +*NOTE*: The `data` field contains information provided by the holder—similar to the data field in a regular ether send transaction. The `tokensToSend()` hook, the `tokensReceived()`, or both MAY use the information to decide if they wish to reject the transaction. @@ -659,9 +660,9 @@ Indicate the burning of `amount` of tokens from the `from` address by the `opera > **parameters** > `operator`: Address which triggered the burn. -> `from`: Token holder whose tokens are burned. +> `from`: Holder whose tokens are burned. > `amount`: Number of tokens burned. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. The `burn` and `operatorBurn` functions described below MUST be implemented to burn tokens. @@ -675,11 +676,11 @@ function burn(uint256 amount, bytes calldata data) external Burn the `amount` of tokens from the address `msg.sender`. -The *operator* and the *token holder* MUST both be the `msg.sender`. +The *operator* and the *holder* MUST both be the `msg.sender`. > **parameters** > `amount`: Number of tokens to burn. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. **`operatorBurn` function** @@ -691,15 +692,15 @@ Burn the `amount` of tokens on behalf of the address `from`. The *operator* MUST be `msg.sender`. The value of `from` MAY be `0x0`, -then the `from` (*token holder*) used for the burn MUST be `msg.sender` (the `operator`). +then the `from` (*holder*) used for the burn MUST be `msg.sender` (the `operator`). *Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`. > **parameters** -> `from`: Token holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`). +> `from`: Holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`). > `amount`: Number of tokens to burn. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. *NOTE*: The *operator* MAY pass any information via `operatorData`. @@ -713,7 +714,7 @@ with the addition that the *operator* MAY specify an explicit value for `operato #### **`ERC777TokensSender` And The `tokensToSend` Hook** -The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *token holder*. +The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *holder*. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. @@ -748,10 +749,10 @@ by the `operator` address. > **parameters** > `operator`: Address which triggered the balance decrease (through sending or burning). -> `from`: *token holder*. +> `from`: *holder*. > `to`: *token recipient* for a send and `0x` for a burn. -> `amount`: Number of tokens the *token holder* balance is decreased by. -> `data`: Information provided by the *token holder*. +> `amount`: Number of tokens the *holder* balance is decreased by. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. The following rules apply when calling the `tokensToSend` hook: @@ -762,23 +763,23 @@ The following rules apply when calling the `tokensToSend` hook: - `operator` MUST be the address which triggered the decrease of the balance. -- `from` MUST be the address of the *token holder* whose balance is decreased. +- `from` MUST be the address of the *holder* whose balance is decreased. - `to` MUST be the address of the *recipient* whose balance is increased for a send. - `to` MUST be `0x0` for a burn. -- `amount` MUST be the number of tokens the *token holder* balance is decreased by. +- `amount` MUST be the number of tokens the *holder* balance is decreased by. -- `data` MUST contain the extra information provided by the *token holder* (if any) for a send. +- `data` MUST contain the extra information provided by the *holder* (if any) for a send. - `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any). -- The *token holder* MAY block a decrease of its balance by `revert`ing. +- The *holder* MAY block a decrease of its balance by `revert`ing. (I.e., reject the withdrawal of tokens from its account.) -*NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensSender`. +*NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensSender`. *NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. Hence the `ERC777TokensSender` MUST expect to be called by different token contracts. @@ -833,10 +834,10 @@ by the `operator` address. > **parameters** > `operator`: Address which triggered the balance increase (through sending or minting). -> `from`: *token holder* for a send and `0x` for a mint. +> `from`: *holder* for a send and `0x` for a mint. > `to`: *token recipient*. > `amount`: Number of tokens the *recipient* balance is increased by. -> `data`: Information provided by the *token holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. The following rules apply when calling the `tokensReceived` hook: @@ -847,7 +848,7 @@ The following rules apply when calling the `tokensReceived` hook: - `operator` MUST be the address which triggered the increase of the balance. -- `from` MUST be the address of the *token holder* whose balance is decreased for a send. +- `from` MUST be the address of the *holder* whose balance is decreased for a send. - `from` MUST be `0x0` for a mint. @@ -857,9 +858,9 @@ The following rules apply when calling the `tokensReceived` hook: - `operatorData` MUST contain the extra information provided by the address which triggered the increase of the balance (if any). -- The *token holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.) +- The *holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.) -*NOTE*: Multiple *token holders* MAY use the same implementation of `ERC777TokensRecipient`. +*NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensRecipient`. *NOTE*: An address can register at most one implementation at any given time for all [ERC777] tokens. Hence the `ERC777TokensRecipient` MUST expect to be called by different token contracts. @@ -902,7 +903,7 @@ It avoids the problems and vulnerabilities of [EIP223]. It goes a step further by allowing *operators* (generally contracts) which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. -Finally, it adds hooks to provide further control to *token holders* over their tokens. +Finally, it adds hooks to provide further control to *holders* over their tokens. Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts without having to be redeployed thanks proxy contracts implementing the hooks. From 0d9dde0ee78eeac90913a44c9e9705d889969c5e Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 26 Mar 2019 02:06:08 +0100 Subject: [PATCH 118/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 33469c6f..521d2482 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -190,18 +190,19 @@ function granularity() external view returns (uint256) Get the smallest part of the token that's not divisible. -In other words, the granularity is the smallest number of tokens (in the basic unit) +In other words, the granularity is the smallest number of tokens (in the internal denomination) which MAY be minted, sent or burned at any time. The following rules MUST be applied regarding the *granularity*: - The *granularity* value MUST be set at creation time. -- The *granularity* value MUST NOT be changed ever. +- The *granularity* value MUST NOT be changed, ever. - The *granularity* value MUST be greater or equal to `1`. -- Any minting, send or burning of tokens MUST be a multiple of the *granularity* value. +- Any amount of tokens (in the internal denomination) minted, sent or burnt + MUST be a multiple of the *granularity* value. - Any operation that would result in a balance that's not a multiple of the *granularity* value MUST be considered invalid, and the transaction MUST `revert`. @@ -714,7 +715,7 @@ with the addition that the *operator* MAY specify an explicit value for `operato #### **`ERC777TokensSender` And The `tokensToSend` Hook** -The `tokensToSend` hook notifies of any decrement of balance (send and burn) for a given *holder*. +The `tokensToSend` hook notifies of any request to decrement the balance (send and burn) for a given *holder*. Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. @@ -742,7 +743,7 @@ but said address MUST implement the interface on its behalf. function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external ``` -Notify a send or burn (if `to` is `0x0`) of `amount` tokens from the `from` address to the `to` address +Notify a request to send or burn (if `to` is `0x0`) an `amount` tokens from the `from` address to the `to` address by the `operator` address. *NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process. From 8293a96a299c30663655b698536da4023fd29df0 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Tue, 26 Mar 2019 23:59:38 -0400 Subject: [PATCH 119/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index e289d8a6..b5709d9c 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -281,7 +281,7 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo #### Localization -Metadata localization should be standardized to increase presentation uniformity accross all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. +Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. #### JSON Schema From 55b9d9ecf1b6b7669d2189fe429bf920e4547bef Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 27 Mar 2019 00:02:57 -0400 Subject: [PATCH 120/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index b5709d9c..1b2d3513 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -38,7 +38,7 @@ pragma solidity ^0.5.2; /** @title ERC-1155 Multi Token Standard - @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md + @dev See https://eips.ethereum.org/EIPS/eip-1155 Note: The ERC-165 identifier for this interface is 0xd9b67a26. */ interface ERC1155 /* is ERC165 */ { @@ -191,7 +191,7 @@ The string format of the substituted hexadecimal ID MUST be lowercase alphanumer ### Metadata Extensions -The following optional extensions can be identified with the (ERC-165 Standard Interface Detection)[https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md]. +The following optional extensions can be identified with the (ERC-165 Standard Interface Detection)[https://eips.ethereum.org/EIPS/eip-165]. Changes to the URI MUST emit the `URI` event if the change can be expressed with an event. If the optional ERC1155Metadata_URI extension is included, the value returned by this function SHOULD be used to retrieve values for which no event was emitted. The function MUST return the same value as the event if it was emitted. @@ -367,7 +367,7 @@ fr.json: ## Approval -The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface](https://github.com/ethereum/EIPs/issues/1761) is suggested. +The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) is suggested. ## Rationale @@ -421,7 +421,7 @@ Approval The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It enables frictionless interaction with exchange and trade contracts. -Restricting approval to a certain set of Token IDs, quantities or other rules may be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface](https://github.com/ethereum/EIPs/issues/1761) which is compatible with ERC-1155. +Restricting approval to a certain set of Token IDs, quantities or other rules may be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) which is compatible with ERC-1155. @@ -484,16 +484,16 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok ## References **Standards** -- [ERC-721 Non-Fungible Token Standard](https://raw.githubusercontent.com/ethereum/EIPs/master/EIPS/eip-721.md) -- [ERC-165 Standard Interface Detection](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md) -- [ERC-1538 Transparent Contract Standard](https://github.com/ethereum/EIPs/issues/1538) +- [ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721) +- [ERC-165 Standard Interface Detection](https://eips.ethereum.org/EIPS/eip-165) +- [ERC-1538 Transparent Contract Standard (DRAFT)](https://github.com/ethereum/EIPs/issues/1538) - [JSON Schema](https://json-schema.org/) - [RFC 2119 Key words for use in RFCs to Indicate Requirement Levels](https://www.ietf.org/rfc/rfc2119.txt) **Implementations** - [ERC-1155 Reference Implementation](https://github.com/enjin/erc-1155) - [Horizon Games - Multi-Token Standard](https://github.com/horizon-games/multi-token-standard) -- [Enjin Coin](https://enjincoin.io) ([github](https://github.com/enjin)) +- [Enjin Coin](https://enjincoin.io) ([GitHub](https://github.com/enjin)) - [The Sandbox - Dual ERC-1155/721 Contract](https://github.com/pixowl/thesandbox-contracts/tree/master/src/Asset) **Articles & Discussions** From d91d055682842030385f57e2d8578a731d6967e9 Mon Sep 17 00:00:00 2001 From: Nick Mudge Date: Thu, 28 Mar 2019 03:18:45 -0400 Subject: [PATCH 121/431] Create eip-1538.md (#1879) --- EIPS/eip-1538.md | 473 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 EIPS/eip-1538.md diff --git a/EIPS/eip-1538.md b/EIPS/eip-1538.md new file mode 100644 index 00000000..5a003c17 --- /dev/null +++ b/EIPS/eip-1538.md @@ -0,0 +1,473 @@ +--- +eip: 1538 +title: Transparent Contract Standard +author: Nick Mudge +status: Draft +type: Standards Track +category: ERC +created: 2018-10-31 +--- + + +## Simple Summary + +This standard provides a contract architecture that makes upgradeable contracts flexible, unlimited in size, and transparent. + +A transparent contract publicly documents the full history of all changes made to it. + +All changes to a transparent contract are reported in a standard format. + +## Abstract + +A transparent contract is a proxy contract design pattern that provides the following: + +1. A way to add, replace and remove multiple functions of a contract atomically (at the same time). +1. Standard events to show what functions are added, replaced and removed from a contract, and why the changes are made. +2. A standard way to query a contract to discover and retrieve information about all functions exposed by it. +3. Solves the 24KB maximum contract size limitation, making the maximum contract size of a transparent contract practically unlimited. This standard makes the worry about contract size a thing of the past. +4. Enables an upgradeable contract to become immutable in the future if desired. + +## Motivation + +A fundamental benefit of Ethereum contracts is that their code is immutable, thereby acquiring trust by trustlessness. People do not have to trust others if it is not possible for a contract to be changed. + +However, a fundamental problem with trustless contracts that cannot be changed is that they cannot be changed. + +#### Bugs + +Bugs and security vulnerabilities are unwittingly written into immutable contracts that ruin them. + +#### Improvements + +Immutable, trustless contracts cannot be improved, resulting in increasingly inferior contracts over time. + +Contract standards evolve, new ones come out. People, groups and organizations learn over time what people want and what is better and what should be built next. Contracts that cannot be improved not only hold back the authors that create them, but everybody who uses them. + +#### Upgradeable Contracts vs. Centralized Private Database +Why have an upgradeable contract instead of a centralized, private, mutable database? +Here are some reasons: +1. Because of the openness of storage data and verified code, it is possible to show a provable history of trustworthiness. +2. Because of the openness, bad behavior can be spotted and reported when it happens. +3. Independent security and domain experts can review the change history of contracts and vouch for their history of trustworthiness. +4. It is possible for an upgradeable contract to become immutable and trustless. +5. An upgradeable contract can have parts of it that are not upgradeable and so are partially immutable and trustless. + +#### Immutability + +In some cases immutable, trustless contracts are the right fit. This is the case when a contract is only needed for a short time or it is known ahead of time that there will never be any reason to change or improve it. + +### Middle Ground + +Transparent contracts provide a middle ground between immutable trustless contracts that can't be improved and upgradeable contracts that can't be trusted. + +### Purposes + +1. Create upgradeable contracts that earn trust by showing a provable history of trustworthiness. +2. Document the development of contracts so their development and change is provably public and can be understood. +3. Create upgradeable contracts that can become immutable in the future if desired. +4. Create contracts that are not limited by a max size. + +### Benefits & Use Cases +This standard is for use cases that benefit from the following: +1. The ability to add, replace or remove multiple functions of a contract atomically (at the same time). +2. Each time a function is added, replaced or removed, it is documented with events. +3. Build trust over time by showing all changes made to a contract. +4. Unlimited contract size. +5. The ability to query information about functions currently supported by the contract. +6. One contract address that provides all needed functionality and never needs to be replaced by another contract address. +7. The ability for a contract to be upgradeable for a time, and then become immutable. +8. Add trustless guarantees to a contract with "unchangeable functions". + +### New Software Possibilities + +This standard enables a form of contract version control software to be written. + +Software and user interfaces can be written to filter the `FunctionUpdate` and `CommitMessage` events of a contract address. Such software can show the full history of changes of any contract that implements this standard. + +User interfaces and software can also use this standard to assist or automate changes of contracts. + +## Specification + + +> **Note:** +The solidity `delegatecall` opcode enables a contract to execute a function from another contract, but it is executed as if the function was from the calling contract. Essentially `delegatecall` enables a contract to "borrow" another contract's function. Functions executed with `delegatecall` affect the storage variables of the calling contract, not the contract where the functions are defined. + +### General Summary + +A transparent contract delegates or forwards function calls to it to other contracts using `delegatecode`. + +A transparent contract has an `updateContract` function that enables multiple functions to be added, replaced or removed. + +An event is emitted for every function that is added, replaced or removed so that all changes to a contract can be tracked in a standard way. + +A transparent contract is a contract that implements and complies with the design points below. + +### Terms + +1. In this standard a **delegate contract** is a contract that a transparent contract fallback function forwards function calls to using `delegatecall`. +2. In this standard an **unchangeable function** is a function that is defined directly in a transparent contract and so cannot be replaced or removed. + +### Design Points + +A contract is a transparent contract if it implements the following design points: + +1. A transparent contract is a contract that contains a fallback function, a constructor, and zero or more unchangeable functions that are defined directly within it. +2. The constructor of a transparent contract associates the `updateContract` function with a contract that implements the ERC1538 interface. The `updateContract` function can be an "unchangeable function" that is defined directly in the transparent contract or it can be defined in a delegate contract. Other functions can also be associated with contracts in the constructor. +3. After a transparent contract is deployed functions are added, replaced and removed by calling the `updateContract` function. +4. The `updateContract` function associates functions with contracts that implement those functions, and emits the `CommitMessage` and `FunctionUpdate` events that document function changes. +5. The `FunctionUpdate` event is emitted for each function that is added, replaced or removed. The `CommitMessage` event is emitted one time for each time the `updateContract` function is called and is emitted after any `FunctionUpdate` events are emitted. +6. The `updateContract` function can take a list of multiple function signatures in its `_functionSignatures` parameter and so add/replace/remove multiple functions at the same time. +7. When a function is called on a transparent contract it executes immediately if it is an "unchangeable function". Otherwise the fallback function is executed. The fallback function finds the delegate contract associated with the function and executes the function using `delegatecall`. If there is no delegate contract for the function then execution reverts. +8. The source code of a transparent contract and all delegate contracts used by it are publicly viewable and verified. + +The transparent contract address is the address that users interact with. The transparent contract address never changes. Only delegate addresses can change by using the `updateContracts` function. + +Typically some kind of authentication is needed for adding/replacing/removing functions from a transparent contract, **however the scheme for authentication or ownership is not part of this standard**. + +### Example + +Here is an example of an implementation of a transparent contract. Please note that the example below is an **example only. It is not the standard**. A contract is a transparent contract when it implements and complies with the design points listed above. + +```solidity +pragma solidity ^0.5.7; + +contract ExampleTransparentContract { + // owner of the contract + address internal contractOwner; + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + // maps functions to the delegate contracts that execute the functions + // funcId => delegate contract + mapping(bytes4 => address) internal delegates; + + // maps each function signature to its position in the funcSignatures array. + // signature => index+1 + mapping(bytes => uint256) internal funcSignatureToIndex; + + event CommitMessage(string message); + event FunctionUpdate(bytes4 indexed functionId, address indexed oldDelegate, address indexed newDelegate, string functionSignature); + + // this is an example of an "unchangeable function". + // return the delegate contract address for the supplied function signature + function delegateAddress(string calldata _functionSignature) external view returns(address) { + require(funcSignatureToIndex[bytes(_functionSignature)] != 0, "Function signature not found."); + return delegates[bytes4(keccak256(bytes(_functionSignature)))]; + } + + // add a function using the updateContract function + // this is an internal helper function + function addFunction(address _erc1538Delegate, address contractAddress, string memory _functionSignatures, string memory _commitMessage) internal { + // 0x03A9BCCF == bytes4(keccak256("updateContract(address,string,string)")) + bytes memory funcdata = abi.encodeWithSelector(0x03A9BCCF, contractAddress, _functionSignatures, _commitMessage); + bool success; + assembly { + success := delegatecall(gas, _erc1538Delegate, add(funcdata, 0x20), mload(funcdata), funcdata, 0) + } + require(success, "Adding a function failed"); + } + + constructor(address _erc1538Delegate) public { + contractOwner = msg.sender; + emit OwnershipTransferred(address(0), msg.sender); + + // adding ERC1538 updateContract function + bytes memory signature = "updateContract(address,string,string)"; + bytes4 funcId = bytes4(keccak256(signature)); + delegates[funcId] = _erc1538Delegate; + emit FunctionUpdate(funcId, address(0), _erc1538Delegate, string(signature)); + emit CommitMessage("Added ERC1538 updateContract function at contract creation"); + + // associate "unchangeable functions" with this transparent contract address + // prevents function selector clashes with delegate contract functions + // uses the updateContract function + string memory functions = "delegateAddress(string)"; + addFunction(_erc1538Delegate, address(this), functions, "Associating unchangeable functions"); + + // adding ERC1538Query interface functions + functions = "functionByIndex(uint256)functionExists(string)delegateAddresses()delegateFunctionSignatures(address)functionById(bytes4)functionBySignature(string)functionSignatures()totalFunctions()"; + // "0x01234567891011121314" is an example address of an ERC1538Query delegate contract + addFunction(_erc1538Delegate, 0x01234567891011121314, functions, "Adding ERC1538Query functions"); + + // additional functions could be added at this point + } + + // Making the fallback function payable makes it work for delegate contract functions + // that are payable and not payable. + function() external payable { + // Delegate every function call to a delegate contract + address delegate = delegates[msg.sig]; + require(delegate != address(0), "Function does not exist."); + assembly { + let ptr := mload(0x40) + calldatacopy(ptr, 0, calldatasize) + let result := delegatecall(gas, delegate, ptr, calldatasize, 0, 0) + let size := returndatasize + returndatacopy(ptr, 0, size) + switch result + case 0 {revert(ptr, size)} + default {return (ptr, size)} + } + } +} +``` +As can be seen in the above example, every function call is delegated to a delegate contract, unless the function is defined directly in the transparent contract (making it an unchangeable function). + +The constructor function adds the `updateContract` function to the transparent contract, which is then used to add other functions to the transparent contract. + +Each time a function is added to a transparent contract the events `CommitMessage` and `FunctionUpdate` are emitted to document exactly what functions where added or replaced and why. + +The delegate contract that implements the `updateContract` function implements the following interface: +### ERC1538 Interface + +```solidity +pragma solidity ^0.5.7; + +/// @title ERC1538 Transparent Contract Standard +/// @dev Required interface +/// Note: the ERC-165 identifier for this interface is 0x61455567 +interface ERC1538 { + /// @dev This emits when one or a set of functions are updated in a transparent contract. + /// The message string should give a short description of the change and why + /// the change was made. + event CommitMessage(string message); + + /// @dev This emits for each function that is updated in a transparent contract. + /// functionId is the bytes4 of the keccak256 of the function signature. + /// oldDelegate is the delegate contract address of the old delegate contract if + /// the function is being replaced or removed. + /// oldDelegate is the zero value address(0) if a function is being added for the + /// first time. + /// newDelegate is the delegate contract address of the new delegate contract if + /// the function is being added for the first time or if the function is being + /// replaced. + /// newDelegate is the zero value address(0) if the function is being removed. + event FunctionUpdate( + bytes4 indexed functionId, + address indexed oldDelegate, + address indexed newDelegate, + string functionSignature + ); + + /// @notice Updates functions in a transparent contract. + /// @dev If the value of _delegate is zero then the functions specified + /// in _functionSignatures are removed. + /// If the value of _delegate is a delegate contract address then the functions + /// specified in _functionSignatures will be delegated to that address. + /// @param _delegate The address of a delegate contract to delegate to or zero + /// to remove functions. + /// @param _functionSignatures A list of function signatures listed one after the other + /// @param _commitMessage A short description of the change and why it is made + /// This message is passed to the CommitMessage event. + function updateContract(address _delegate, string calldata _functionSignatures, string calldata _commitMessage) external; +} +``` +### Function Signatures String Format + +The text format for the `_functionSignatures` parameter is simply a string of function signatures. For example: `"myFirstFunction()mySecondFunction(string)"` This format is easy to parse and is concise. + +Here is an example of calling the `updateContract` function that adds the ERC721 standard functions to a transparent contract: +```javascript +functionSignatures = "approve(address,uint256)balanceOf(address)getApproved(uint256)isApprovedForAll(address,address)ownerOf(uint256)safeTransferFrom(address,address,uint256)safeTransferFrom(address,address,uint256,bytes)setApprovalForAll(address,bool)transferFrom(address,address,uint256)" +tx = await transparentContract.updateContract(erc721Delegate.address, functionSignatures, "Adding ERC721 functions"); +``` + +### Removing Functions + +Functions are removed by passing `address(0)` as the first argument to the `updateContract` function. The list of functions that are passed in are removed. + +### Source Code Verification + +The transparent contract source code and the source code for the delegate contracts should be verified in a provable way by a third party source such as etherscan.io. + + +### Function Selector Clash +A function selector clash occurs when a function is added to a contract that hashes to the same four-byte hash as an existing function. This is unlikely to occur but should be prevented in the implementation of the `updateContract` function. See the [reference implementation of ERC1538](https://github.com/mudgen/transparent-contracts-erc1538) to see an example of how function clashes can be prevented. + +### ERC1538Query + +Optionally, the function signatures of a transparent contract can be stored in an array in the transparent contract and queried to get what functions the transparent contract supports and what their delegate contract addresses are. + +The following is an optional interface for querying function information from a transparent contract: + +```solidity +pragma solidity ^0.5.7; + +interface ERC1538Query { + + /// @notice Gets the total number of functions the transparent contract has. + /// @return The number of functions the transparent contract has, + /// not including the fallback function. + function totalFunctions() external view returns(uint256); + + /// @notice Gets information about a specific function + /// @dev Throws if `_index` >= `totalFunctions()` + /// @param _index The index position of a function signature that is stored in an array + /// @return The function signature, the function selector and the delegate contract address + function functionByIndex(uint256 _index) + external + view + returns( + string memory functionSignature, + bytes4 functionId, + address delegate + ); + + /// @notice Checks to see if a function exists + /// @param The function signature to check + /// @return True if the function exists, false otherwise + function functionExists(string calldata _functionSignature) external view returns(bool); + + /// @notice Gets all the function signatures of functions supported by the transparent contract + /// @return A string containing a list of function signatures + function functionSignatures() external view returns(string memory); + + /// @notice Gets all the function signatures supported by a specific delegate contract + /// @param _delegate The delegate contract address + /// @return A string containing a list of function signatures + function delegateFunctionSignatures(address _delegate) external view returns(string memory); + + /// @notice Gets the delegate contract address that supports the given function signature + /// @param The function signature + /// @return The delegate contract address + function delegateAddress(string calldata _functionSignature) external view returns(address); + + /// @notice Gets information about a function + /// @dev Throws if no function is found + /// @param _functionId The id of the function to get information about + /// @return The function signature and the contract address + function functionById(bytes4 _functionId) + external + view + returns( + string memory signature, + address delegate + ); + + /// @notice Get all the delegate contract addresses used by the transparent contract + /// @return An array of all delegate contract addresses + function delegateAddresses() external view returns(address[] memory); +} +``` + +See the [reference implementation of ERC1538](https://github.com/mudgen/transparent-contracts-erc1538) to see how this is implemented. + +The text format for the list of function signatures returned from the `delegateFunctionSignatures` and `functionSignatures` functions is simply a string of function signatures. Here is an example of such a string: `"approve(address,uint256)balanceOf(address)getApproved(uint256)isApprovedForAll(address,address)ownerOf(uint256)safeTransferFrom(address,address,uint256)safeTransferFrom(address,address,uint256,bytes)setApprovalForAll(address,bool)transferFrom(address,address,uint256)"` + +### How To Deploy A Transparent Contract +1. Create and deploy to a blockchain a contract that implements the ERC1538 interface. You can skip this step if there is already such a contract deployed to the blockchain. +2. Create your transparent contract with a fallback function as given above. Your transparent contract also needs a constructor that adds the `updateContract` function. +3. Deploy your transparent contract to a blockchain. Pass in the address of the ERC1538 delegate contract to your constructor if it requires it. + +See the [reference implementation](https://github.com/mudgen/transparent-contracts-erc1538) for examples of these contracts. + +### Wrapper Contract for Delegate Contracts that Depend on Other Delegate Contracts +In some cases some delegate contracts may need to call external/public functions that reside in other delegate contracts. A convenient way to solve this problem is to create a contract that contains empty implementations of functions that are needed and import and extend this contract in delegate contracts that call functions from other delegate contracts. This enables delegate contracts to compile without having to provide implementations of the functions that are already given in other delegate contracts. This is a way to save gas, prevent reaching the max contract size limit, and prevent duplication of code. This strategy was given by @amiromayer. [See his comment for more information.](https://github.com/ethereum/EIPs/issues/1538#issuecomment-451985155) Another way to solve this problem is to use assembly to call functions provided by other delegate contracts. + +### Decentralized Authority +It is possible to extend this standard to add consensus functionality such as an approval function that multiple different people call to approve changes before they are submitted with the `updateContract` function. Changes only go into effect when the changes are fully approved. The `CommitMessage` and ` FunctionUpdate` events should only be emitted when changes go into effect. + +## Security +> This standard refers to **owner(s)** as one or more individuals that have the power to add/replace/remove functions of an upgradeable contract. + +### General + +The owners(s) of an upgradeable contract have the ability to alter, add or remove data from the contract's data storage. Owner(s) of a contract can also execute any arbitrary code in the contract on behalf of any address. Owners(s) can do these things by adding a function to the contract that they call to execute arbitrary code. This is an issue for upgradeable contracts in general and is not specific to transparent contracts. + +>**Note:** The design and implementation of contract ownership is **not** part of this standard. The examples given in this standard and in the reference implementation are just **examples** of how it could be done. + +### Unchangeable Functions + +"Unchangeable functions" are functions defined in a transparent contract itself and not in a delegate contract. The owner(s) of a transparent contract are not able to replace these functions. The use of unchangeable functions is limited because in some cases they can still be manipulated if they read or write data to the storage of the transparent contract. Data read from the transparent contract's storage could have been altered by the owner(s) of the contract. Data written to the transparent contract's storage can be undone or altered by the owner(s) of the contract. + +In some cases unchangeble functions add trustless guarantees to a transparent contract. + +### Transparency + +Contracts that implement this standard emit an event every time a function is added, replaced or removed. This enables people and software to monitor the changes to a contract. If any bad acting function is added to a contract then it can be seen. To comply with this standard all source code of a transparent contract and delegate contracts must be publicly available and verified. + +Security and domain experts can review the history of change of any transparent contract to detect any history of foul play. + +## Rationale + + +### String of Function Signatures Instead of bytes4[] Array of Function Selectors + +The `updateContract` function takes a `string` list of functions signatures as an argument instead of a `bytes4[]` array of function selectors for three reasons: + +1. Passing in function signatures enables the implementation of `updateContract` to prevent selector clashes. +2. A major part of this standard is to make upgradeable contracts more transparent by making it easier to see what has changed over time and why. When a function is added, replaced or removed its function signature is included in the FunctionUpdate event that is emitted. This makes it relatively easy to write software that filters the events of a contract to display to people what functions have been added/removed and changed over time without needing access to the source code or ABI of the contract. If only four-byte function selectors were provided this would not be possible. +3. By looking at the source code of a transparent contract it is not possible to see all the functions that it supports. This is why the ERC1538Query interface exists, so that people and software have a way to look up and examine or show all functions currently supported by a transparent contract. Function signatures are used so that ERC1538Query functions can show them. + +### Gas Considerations + +Delegating function calls does have some gas overhead. This is mitigated in two ways: +1. Delegate contracts can be small, reducing gas costs. Because it costs more gas to call a function in a contract with many functions than a contract with few functions. +2. Because transparent contracts do not have a max size limitation it is possible to add gas optimizing functions for use cases. For example someone could use a transparent contract to implement the ERC721 standard and implement batch transfer functions from the [ERC1412 standard](https://github.com/ethereum/EIPs/issues/1412) to help reduce gas (and make batch transfers more convenient). + +### Storage + +The standard does not specify how data is stored or organized by a transparent contract. But here are some suggestions: + +**Inherited Storage** + +1. The storage variables of a transparent contract consist of the storage variables defined in the transparent contract source code and the source code of delegate contracts that have been added. + +2. A delegate contract can use any storage variable that exists in a transparent contract as long as it defines within it all the storage variables that exist, in the order that they exist, up to and including the ones being used. + +3. A delegate contract can create new storage variables as long as it has defined, in the same order, all storage variables that exist in the transparent contract. + +Here is a simple way inherited storage could be implemented: + +1. Create a storage contract that contains the storage variables that your transparent contract and delegate contracts will use. +2. Make your delegate contracts inherit the storage contract. +3. If you want to add a new delegate contract that adds new storage variables then create a new storage contract that adds the new storage variables and inherits from the old storage contract. Use your new storage contract with your new delegate contract. +4. Repeat steps 2 or 3 for every new delegate contract. + + +**Unstructured Storage** + +Assembly is used to store and read data at specific storage locations. An advantage to this approach is that previously used storage locations don't have to be defined or mentioned in a delegate contract if they aren't used by it. + +**Eternal Storage** + +Data can be stored using a generic API based on the type of data. [See ERC930 for more information.](https://github.com/ethereum/EIPs/issues/930) + +### Becoming Immutable +It is possible to make a transparent contract become immutable. This is done by calling the `updateContract` function to remove the `updateContract` function. With this gone it is no longer possible to add, replace and remove functions. + +### Versions of Functions + +Software or a user can verify what version of a function is called by getting the delegate contract address of the function. This can be done by calling the `delegateAddress` function from the ERC1538Query interface if it is implemented. This function takes a function signature as an argument and returns the delegate contract address where it is implemented. + +### Best Practices, Tools and More Information + +> More information, tools, tutorials and best practices concerning transparent contracts need to be developed and published. + +Below is a growing list of articles concerning transparent contracts and their use. If you have an article about transparent contracts you would like to share then please submit a comment to this issue about it to get it added. + +[ERC1538: Future Proofing Smart Contracts and Tokens](https://coinjournal.net/erc1538-future-proofing-smart-contacts-and-tokens/) + +[The ERC1538 improving towards the “transparent contract” standard](https://www.crypto-economy.net/en/ethereum-eth-erc1538-transparent-contract-standard/) + +### Inspiration + +This standard was inspired by ZeppelinOS's implementation of [Upgradeability with vtables](https://github.com/zeppelinos/labs/tree/master/upgradeability_with_vtable). + +This standard was also inspired by the design and implementation of the [Mokens contract](https://etherscan.io/address/0xc1eab49cf9d2e23e43bcf23b36b2be14fc2f8838#code) from the [Mokens project](https://github.com/Mokens/MIPs/blob/master/MIPS/mip-2-Goals-and-Objectives.md). The Mokens contract has been [upgraded to implement this standard](https://etherscan.io/address/0x0ac5637fe62ec14fd9e237a81a9679d4adef701f#code). + + +## Backwards Compatibility + +This standard makes a contract compatible with future standards and functionality because new functions can be added and existing functions can be replaced or removed. + +This standard future proofs a contract. + +## Implementation + +A reference implementation of this standard is given in the [transparent-contracts-erc1538](https://github.com/mudgen/transparent-contracts-erc1538) repository. + + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 3296e251e709ac5fc34980232266a88d88b7a3e1 Mon Sep 17 00:00:00 2001 From: Nick Mudge Date: Thu, 28 Mar 2019 15:50:05 -0400 Subject: [PATCH 122/431] Automatically merged updates to draft EIP(s) 1538 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1538.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1538.md b/EIPS/eip-1538.md index 5a003c17..d3d895a5 100644 --- a/EIPS/eip-1538.md +++ b/EIPS/eip-1538.md @@ -2,6 +2,7 @@ eip: 1538 title: Transparent Contract Standard author: Nick Mudge +discussions-to: https://github.com/ethereum/EIPs/issues/1538 status: Draft type: Standards Track category: ERC From 1f44d543fca931188b2827c0aee89936e7d65644 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 29 Mar 2019 19:06:21 -0400 Subject: [PATCH 123/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 1b2d3513..414bcd43 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -486,7 +486,7 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok **Standards** - [ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721) - [ERC-165 Standard Interface Detection](https://eips.ethereum.org/EIPS/eip-165) -- [ERC-1538 Transparent Contract Standard (DRAFT)](https://github.com/ethereum/EIPs/issues/1538) +- [ERC-1538 Transparent Contract Standard (DRAFT)](https://eips.ethereum.org/EIPS/eip-1538) - [JSON Schema](https://json-schema.org/) - [RFC 2119 Key words for use in RFCs to Indicate Requirement Levels](https://www.ietf.org/rfc/rfc2119.txt) From 3c705535748734e22a2ecf15a10a124e1bb4ce41 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 29 Mar 2019 19:07:04 -0400 Subject: [PATCH 124/431] Automatically merged updates to draft EIP(s) 1761 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1761.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1761.md b/EIPS/eip-1761.md index 41596de7..7b4057e1 100644 --- a/EIPS/eip-1761.md +++ b/EIPS/eip-1761.md @@ -20,7 +20,7 @@ This interface is designed for use with token contracts that have an "ID" domain Sample use cases for scopes: -* A company may represent it's fleet of vehicles on the blockchain and it could create a scope for each regional office. +* A company may represent its fleet of vehicles on the blockchain and it could create a scope for each regional office. * Game developers could share an [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) contract where each developer manages tokens under a specified scope. * Tokens of different value could be split into separate scopes. High-value tokens could be kept in smaller separate scopes while low-value tokens might be kept in a shared scope. Users would approve the entire low-value token scope to a third-party smart contract, exchange, or other application without concern about losing their high-value tokens in the event of a problem. From 9f55d755aad8c51128c83b0a6d5588f20ec843eb Mon Sep 17 00:00:00 2001 From: Witek Date: Fri, 29 Mar 2019 16:28:04 -0700 Subject: [PATCH 125/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 60 ++++-------------------------------------------- 1 file changed, 5 insertions(+), 55 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 414bcd43..b310a3a1 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -141,7 +141,6 @@ interface ERC1155 /* is ERC165 */ { function isApprovedForAll(address _owner, address _operator) external view returns (bool); } ``` - ## ERC-1155 Token Receiver @@ -276,9 +275,6 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo } ``` -
    -Localization - #### Localization Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. @@ -363,76 +359,44 @@ fr.json: } ``` -
    - ## Approval The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) is suggested. ## Rationale -
    - -Metadata Choices +### Metadata Choices The `symbol` function (found in the ERC-20 and ERC-721 standards) was not included as we do not believe this is a globally useful piece of data to identify a generic virtual item / asset and are also prone to collisions. Short-hand symbols are used in tickers and currency trading, but they aren't as useful outside of that space. The `name` function (for human-readable asset names, on-chain) was removed from the standard to allow the Metadata JSON to be the definitive asset name and reduce duplication of data. This also allows localization for names, which would otherwise be prohibitively expensive if each language string was stored on-chain, not to mention bloating the standard interface. While this decision may add a small burden on implementers to host a JSON file containing metadata, we believe any serious implementation of ERC-1155 will already utilize JSON Metadata. -
    - -
    - -Upgrades +### Upgrades The requirement to emit `TransferSingle` or `TransferBatch` on balance change implies that a valid implementation of ERC-1155 redeploying to a new contract address MUST emit events from the new contract address to replicate the deprecated contract final state. It is valid to only emit a minimal number of events to reflect only the final balance and omit all the transactions that led to that state. The event emit requirement is to ensure that the current state of the contract can always be traced only through events. To alleviate the need to emit events when changing contract address, consider using the proxy pattern, such as described in ERC-1538. This will also have the added benefit of providing a stable contract address for users. -
    - -
    - -Design decision: Supporting non-batch +### Design decision: Supporting non-batch The standard supports `safeTransferFrom` and `onERC1155Received` functions because they are significantly cheaper for single token-type transfers, which is arguably a common use case. -
    - -
    - -Design decision: Safe transfers only +### Design decision: Safe transfers only The standard only supports safe-style transfers, making it possible for receiver contracts to depend on `onERC1155Received` or `onERC1155BatchReceived` function to be always called at the end of a transfer. -
    - -
    - -Guaranteed log trace +### Guaranteed log trace As the Ethereum ecosystem continues to grow, many dapps are relying on traditional databases and explorer API services to retrieve and categorize data. The ERC-1155 standard guarantees that event logs emitted by the smart contract will provide enough data to create an accurate record of all current token balances. A database or explorer may listen to events and be able to provide indexed and categorized searches of every ERC-1155 token in the contract. -
    - -
    - -Approval - ### Approval The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It enables frictionless interaction with exchange and trade contracts. Restricting approval to a certain set of Token IDs, quantities or other rules may be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) which is compatible with ERC-1155. -
    - ## Usage This standard can be used to represent multiple token types for an entire domain. Both Fungible and Non-Fungible tokens can be stored in the same smart-contract. -
    - -Batch Operations - ### Batch Transfers The `safeBatchTransferFrom` function allows for batch transfers of multiple token ids and values. The design of ERC-1155 makes batch transfers possible without the need for a wrapper contract, as with existing token standards. This reduces gas costs when more than one token type is included in a batch transfer, as compared to single transfers with multiple transactions. @@ -443,24 +407,12 @@ Another advantage of standardized batch transfers is the ability for a smart con The `balanceOfBatch` function allows clients to retrieve balances of multiple owners and token ids with a single call. -
    - -
    - -Enumeration - ### Enumerating from events In order to keep storage requirements light for contracts implementing ERC-1155, enumeration (discovering the IDs and values of tokens) must be done using event logs. It is RECOMMENDED that clients such as exchanges and blockchain explorers maintain a local database containing the Token ID, Supply, and URI at the minimum. This can be built from each TransferSingle, TransferBatch, and URI event, starting from the block the smart contract was deployed until the latest block. ERC-1155 contracts must therefore carefully emit TransferSingle or TransferBatch events in any instance where tokens are created, minted, or destroyed. -
    - -
    - -Non-Fungible Tokens - ### Non-Fungible Tokens The following strategy is an example of how to mix fungible and non-fungible tokens together in the same contract. The top 128 bits of the uint256 `_id` parameter in any ERC-1155 function could represent the base token ID, while the bottom 128 bits might be used for any extra data passed to the contract. @@ -479,8 +431,6 @@ balanceOf(baseToken, msg.sender); // Get balance of the base token balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible token index ``` -
    - ## References **Standards** From 0eabc510290797aa6cc6c8d3054564bc2f542a3b Mon Sep 17 00:00:00 2001 From: Witek Date: Fri, 29 Mar 2019 17:19:18 -0700 Subject: [PATCH 126/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index b310a3a1..6c7ace88 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -34,7 +34,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S **Smart contracts implementing the ERC-1155 standard MUST implement the `ERC1155` and `ERC165` interfaces.** ```solidity -pragma solidity ^0.5.2; +pragma solidity ^0.5.7; /** @title ERC-1155 Multi Token Standard @@ -147,7 +147,7 @@ interface ERC1155 /* is ERC165 */ { Smart contracts **MUST** implement this interface to accept transfers. ```solidity -pragma solidity ^0.5.2; +pragma solidity ^0.5.7; interface ERC1155TokenReceiver { /** @@ -195,7 +195,7 @@ The following optional extensions can be identified with the (ERC-165 Standard I Changes to the URI MUST emit the `URI` event if the change can be expressed with an event. If the optional ERC1155Metadata_URI extension is included, the value returned by this function SHOULD be used to retrieve values for which no event was emitted. The function MUST return the same value as the event if it was emitted. ```solidity -pragma solidity ^0.5.2; +pragma solidity ^0.5.7; /** Note: The ERC-165 identifier for this interface is 0x0e89341c. From d3078681fc124320a6330c9e9f5b2d6c874e6a00 Mon Sep 17 00:00:00 2001 From: Noel Maersk Date: Mon, 1 Apr 2019 20:34:45 +0300 Subject: [PATCH 127/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 5e98aebf..b870dd1e 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -15,9 +15,9 @@ In the 21st century, on a blockchain circulating billions of ETH, formal specifi ## Abstract -EVM code is currently difficult to statically analyze, hobbling critical tools for preventing the many expensive bugs our blockchain has experienced. Further, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to reduce the need for precompiles and otherwise meet the network's long-term demands. This proposal identifies dynamic jumps as a major reason for these issues, and proposes changes to the EVM specification to address the problem, making further efforts towards a safer and more performant the EVM possible. +EVM code is currently difficult to statically analyze, hobbling critical tools for preventing the many expensive bugs our blockchain has experienced. Further, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to reduce the need for precompiles and otherwise meet the network's long-term demands. This proposal identifies dynamic jumps as a major reason for these issues, and proposes changes to the EVM specification to address the problem, making further efforts towards a safer and more performant EVM possible. -We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. And well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. +We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. Well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. ## Motivation @@ -31,7 +31,7 @@ Absent dynamic jumps code can be statically analyzed in linear time. Static ana The result is that all of the following validations and optimizations can be done at deployment time with **linear** **`(n)`** **or** **near-linear** **`(n log n)`** **time complexity** * The absence of most exceptional halting states can be validated. -* The maximum use of resources can be sometimes be calculated. +* The maximum use of resources can sometimes be calculated. * Bytecode can be compiled to machine code. * Compilation can optimize use of smaller registers. * Compilation can optimize injection of gas metering. From d581674317b1f980f3cee1231b2ef597cc1fd7f4 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Mon, 1 Apr 2019 13:41:47 -0400 Subject: [PATCH 128/431] Automatically merged updates to draft EIP(s) 1155 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 6c7ace88..76efb625 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -27,7 +27,7 @@ Tokens standards like ERC-20 and ERC-721 require a separate contract to be deplo New functionality is possible with this design, such as transferring multiple token types at once, saving on transaction costs. Trading (escrow / atomic swaps) of multiple tokens can be built on top of this standard and it removes the need to "approve" individual token contracts separately. It is also easy to describe and mix multiple fungible or non-fungible token types in a single contract. -# Specification +## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. @@ -47,7 +47,7 @@ interface ERC1155 /* is ERC165 */ { Operator MUST be msg.sender. When minting/creating tokens, the `_from` field MUST be set to `0x0` When burning/destroying tokens, the `_to` field MUST be set to `0x0` - The total value transferred from address 0x0 minus the total value transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID. + The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value); @@ -57,7 +57,7 @@ interface ERC1155 /* is ERC165 */ { Operator MUST be msg.sender. When minting/creating tokens, the `_from` field MUST be set to `0x0` When burning/destroying tokens, the `_to` field MUST be set to `0x0` - The total value transferred from address 0x0 minus the total value transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID. + The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values); @@ -142,7 +142,7 @@ interface ERC1155 /* is ERC165 */ { } ``` -## ERC-1155 Token Receiver +### ERC-1155 Token Receiver Smart contracts **MUST** implement this interface to accept transfers. @@ -182,13 +182,13 @@ interface ERC1155TokenReceiver { } ``` -## Metadata +### Metadata The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/780000000000001e000000000000000000000000000000000000000000000000.json` if the client is referring to token ID `780000000000001e000000000000000000000000000000000000000000000000`. The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix. -### Metadata Extensions +#### Metadata Extensions The following optional extensions can be identified with the (ERC-165 Standard Interface Detection)[https://eips.ethereum.org/EIPS/eip-165]. @@ -211,7 +211,7 @@ interface ERC1155Metadata_URI { } ``` -### ERC-1155 Metadata URI JSON Schema +#### ERC-1155 Metadata URI JSON Schema This JSON schema is loosely based on the "ERC721 Metadata JSON Schema", but includes optional formatting to allow for ID substitution by clients. If the string `{id}` exists in any JSON value, it MUST be replaced with the actual token ID, by all client software that follows this standard. @@ -275,11 +275,11 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo } ``` -#### Localization +##### Localization -Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content may be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. +Metadata localization should be standardized to increase presentation uniformity accross all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content MAY be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. -#### JSON Schema +##### JSON Schema ```json { @@ -328,7 +328,7 @@ Metadata localization should be standardized to increase presentation uniformity } ``` -#### Localized Sample +##### Localized Sample Base URI: ```json @@ -359,7 +359,7 @@ fr.json: } ``` -## Approval +### Approval The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) is suggested. @@ -391,7 +391,7 @@ As the Ethereum ecosystem continues to grow, many dapps are relying on tradition The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. It enables frictionless interaction with exchange and trade contracts. -Restricting approval to a certain set of Token IDs, quantities or other rules may be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) which is compatible with ERC-1155. +Restricting approval to a certain set of Token IDs, quantities or other rules MAY be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface](https://github.com/ethereum/EIPs/issues/1761) which is compatible with ERC-1155. ## Usage From 9b41cbc7a7b034db92fa3e0bef39e429e1a96253 Mon Sep 17 00:00:00 2001 From: Tim Beiko Date: Mon, 1 Apr 2019 17:11:06 -0400 Subject: [PATCH 129/431] Updated README and index.html to be consistent with EIP-1 (#1896) * Updated README to be consistent with EIP-1 Update README to be consistent with EIP and this PR: https://github.com/ethereum/EIPs/pull/1858/ * Updated index.html Updated index.html to use the same definitions as the readme. --- README.md | 8 ++++---- index.html | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index abc1aab8..c313bcde 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,11 @@ When you believe your EIP is mature and ready to progress past the draft phase, - **For all other EIPs**, open a PR changing the state of your EIP to 'Final'. An editor will review your draft and ask if anyone objects to its being finalised. If the editor decides there is no rough consensus - for instance, because contributors point out significant issues with the EIP - they may close the PR and request that you fix the issues in the draft before trying again. # EIP Status Terms -* **Draft** - an EIP that is undergoing rapid iteration and changes -* **Last Call** - an EIP that is done with its initial iteration and ready for review by a wide audience -* **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author +* **Draft** - an EIP that is undergoing rapid iteration and changes. +* **Last Call** - an EIP that is done with its initial iteration and ready for review by a wide audience. +* **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP wil move to final. * **Final (non-Core)** - an EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. -* **Final (Core)** - an EIP that the Core Devs have decide to implement and release in a future hard fork or has already been released in a hard fork +* **Final (Core)** - an EIP that the Core Devs have decided to implement and release in a future hard fork or has already been released in a hard fork. * **Deferred** - an EIP that is not being considered for immediate adoption. May be reconsidered in the future for a subsequent hard fork. # Preferred Citation Format diff --git a/index.html b/index.html index 8eb533ad..079dd092 100644 --- a/index.html +++ b/index.html @@ -14,9 +14,11 @@ title: Home

    EIP status terms

      -
    • Draft - an EIP that is open for consideration.
    • -
    • Accepted - an EIP that is planned for immediate adoption, i.e. expected to be included in the next hard fork (for Core/Consensus layer EIPs).
    • -
    • Final - an EIP that has been adopted in a previous hard fork (for Core/Consensus layer EIPs).
    • +
    • Draft - an EIP that is open for consideration and is undergoing rapid iteration and changes.
    • +
    • Last Call - an EIP that is done with its initial iteration and ready for review by a wide audience.
    • +
    • Accepted - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP wil move to final.
    • +
    • Final (non-Core) - an EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author.
    • +
    • Final (Core) - an EIP that the Core Devs have decided to implement and release in a future hard fork or has already been released in a hard fork.
    • Deferred an EIP that is not being considered for immediate adoption. May be reconsidered in the future for a subsequent hard fork.
    From d053eb66921c5915f3e16d72c7566289e2d7c151 Mon Sep 17 00:00:00 2001 From: Richard Meissner Date: Tue, 2 Apr 2019 01:01:33 +0200 Subject: [PATCH 130/431] EIP-1344: Add chain id opcode (#1344) * Add chain id opcode * Update EIP number * Update file name * Add discussion-to --- EIPS/eip-1344.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 EIPS/eip-1344.md diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md new file mode 100644 index 00000000..e0b8db3c --- /dev/null +++ b/EIPS/eip-1344.md @@ -0,0 +1,16 @@ +--- +eip: 1344 +title: ChainID opcode +author: Richard Meissner (@rmeissner) +discussions-to: https://ethereum-magicians.org/t/add-chain-id-opcode-for-replay-protection-when-handling-signed-messages-in-contracts/1131 +category: Core +type: Standards Track +status: Draft +created: 2018-08-22 +--- + ### Specification + Adds a new opcode at 0x46, which takes 0 stack arguments. It will return the chain id of the chain where the block was mined. It should cost 2 gas (G_base) to execute this opcode. + ### Motivation + [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain id to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures. + The current approach proposed by [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) is to specify the chain id on compile time. Using this approach will result in problems after a hardfork. + By adding the opcode it would be possible to access the current chain id and validate signatures based on that. From 5b57472484ca31c9d902cccbe298f15a15f32ce2 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 2 Apr 2019 15:35:24 +0200 Subject: [PATCH 131/431] New design for EIP-1702 --- EIPS/eip-1702.md | 108 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 23 deletions(-) diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index 4402560d..5d97a665 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -11,57 +11,119 @@ created: 2017-12-30 ## Abstract -This defines a method of hard forking while maintaining the exact functionality of existing account by allowing multiple versions of the virtual machines to execute in the same block. This is also useful to define future account state structures when we introduce the on-chain WebAssembly virtual machine. +This defines a method of hard forking while maintaining the exact +functionality of existing account by allowing multiple versions of the +virtual machines to execute in the same block. This is also useful to +define future account state structures when we introduce the on-chain +WebAssembly virtual machine. ## Motivation -By allowing account versioning, we can execute different virtual machine for contracts created at different times. This allows breaking features to be implemented while making sure existing contracts work as expected. +By allowing account versioning, we can execute different virtual +machine for contracts created at different times. This allows breaking +features to be implemented while making sure existing contracts work +as expected. -Note that this specification might not apply to all hard forks. We have emergency hard forks in the past due to network attacks. Whether they should maintain existing account compatibility should be evaluated in individual basis. If the attack can only be executed once against some particular contracts, then the scheme defined here might still be applicable. Otherwise, having a plain emergency hard fork might still be a good idea. +Note that this specification might not apply to all hard forks. We +have emergency hard forks in the past due to network attacks. Whether +they should maintain existing account compatibility should be +evaluated in individual basis. If the attack can only be executed once +against some particular contracts, then the scheme defined here might +still be applicable. Otherwise, having a plain emergency hard fork +might still be a good idea. ## Specification ### Account State -After the first hard fork using this scheme, newly created account state stored in the world state trie is changed to become a five-item RLP encoding: `nonce`, `balance`, `storageRoot`, `codeHash` and `version`. The `version` field defines that when a contract call transaction or `CALL` opcode is executed against this contract, which version of the virtual machine should be used. Four-item RLP encoding account state are considered to have the `version` 0. +Re-define account state stored in the world state trie to have 5 +items: `nonce`, `balance`, `storageRoot`, `codeHash`, and +`version`. The newly added field `version` is a 256-bit integer. When +`version` is zero, the account is RLP-encoded with the first 4 +items. When `version` is not zero, the account is RLP-encoded with 5 +items. -`CREATE`/`CREATE2` opcode, the contract creation transaction, and a normal call which initialize a new account, would only deploy accounts of the newest version. +### Contract Deployment -The behavior of `CALLCODE` and `DELEGATECALL` are not affected by the hard fork -- they would fetch the contract code (even if the contract is deployed in a newer version) and still use the virtual machine version defined in the current contract (or in the case of within the input of contract creation transaction or `CREATE` opcode, the newest virtual machine version) to execute the code. +In Ethereum, a contract has a deployment method, either by a contract +creation transaction, or by another contract. If we regard this +deployment method a contract's *parent*, then we find them forming a +family of contracts, with the *root* being a contract creation +transaction. -If a message call transaction creates a new account, the newly created account will have the newest account version number in the network. +We let a family of contracts to always have the same `version`. That +is, `CREATE` and `CREATE2` will always deploy contract that has the +same `version` as the calling `address`. -Precompiled contracts, once created, use the given account version. If the account does not exist yet, newest version of the VM is used (as in the standard message call transaction). This is made so that VMs do not need full permission of the state trie but only with in the smart contract boundary. It is expected that once a precompiled contract is created, its behavior will not change. +### Validation -### Gas Boundary +A new phrase, *validation* is added to contract deployment (by +`CREATE` / `CREATE2` opcodes, or by contract creation +transaction). When `version` is `0`, the phrase does nothing and +always succeeds. Future VM versions can define additional validation +that has to be passed. -With the boundary between the VM and the blockchain, we don't consider there're additional gas cost involved. VM used defines the gas table applied. As examples, intrinsic gas only applies to actual transactions so only the newest ones are used. `CALL` and `CREATE` will use the old gas cost as the opcode gas cost, and once switched to the new VM, use the new gas cost from there. +If the validation phrase fails, deployment does not proceed and return +out-of-gas. -## Example +### Contract Execution -Consider we would like to have the REVERT opcode hard fork in Ethereum Classic using this scheme. After the hard fork, we have: +VM version used in contract execution is determined via calling +`address` (`I_a` in yellow paper). Precompiled contract does not have +version. -* Existing accounts are still of four-item RLP encoding. When a transaction has `to` field pointing to them, they're executed using version 0 of EVM. REVERT is the same as INVALID and consumes all the gases. -* A new contract creation transaction is executed using version 1 virtual machine, and would only create version 1 account on the blockchain. When executing them, it uses version 1 of EVM and REVERT uses the new behavior. -* When a version 0 account issues a CALL to version 1 account, sub-execution of the version 1 account uses the version 1 virtual machine. -* When a version 1 account issues a CALL to version 0 account, sub-execution of the version 0 account uses the version 0 vritual machine. -* When a version 0 account issues a CREATE, it always uses the newest version of the virtual machine, so it only creates version 1 new accounts. +### Contract Creation Transaction + +Define `LATEST_VERSION` in a hard fork to be the latest supported VM +version. A contract creation transaction is always executed in +`LATEST_VERSION`. Before a contract creation transaction is executed, +run *validation* on the contract creation code. If it does not pass, +return out-of-gas. + +#### Alternative Design for Contract Creation Transaction + +This provides an alternative design that allows contract to be created +in multiple versions. + +Add an additional field `version` (256-bit integer) in contract +creation transaction. So it becomes `nonce`, `gasprice`, `startgas`, +`to`, `value`, `data`, `v`, `r`, `s`, `version`. When signing or +recovering, sign ten items, with `v`, `r`, `s` as defined by EIP-155. + +The transaction would be executed in `version` supplied. If `version` +is not supported or *validation* does not pass, return out-of-gas. ## Discussions ### Performance -Currently nearly all full node implementations uses config parameters to decide which virtual machine version to use. Switching vitual machine version is simply an operation that changes a pointer using a different set of config parameters. As a result, this scheme has nearly zero impact to performance. +Currently nearly all full node implementations uses config parameters +to decide which virtual machine version to use. Switching vitual +machine version is simply an operation that changes a pointer using a +different set of config parameters. As a result, this scheme has +nearly zero impact to performance. ### Smart Contract Boundary and Formal Verification -Many current efforts are on-going for getting smart contracts formally verified. However, for any hard fork that introduces new opcodes or change behaviors of existing opcodes would break the verification of an existing contract has previously be formally verified. Using the scheme described here, we define the boundary of how a smart contract interacts with the blockchain and it might help the formal verification efforts: +Many current efforts are on-going for getting smart contracts formally +verified. However, for any hard fork that introduces new opcodes or +change behaviors of existing opcodes would break the verification of +an existing contract has previously be formally verified. Using the +scheme described here, we define the boundary of how a smart contract +interacts with the blockchain and it might help the formal +verification efforts: -* A smart contract has only immutable access to information of blockchain account balances and codes. +* A smart contract has only immutable access to information of + blockchain account balances and codes. * A smart contract has only immutable access of block information. -* A smart contract or a contract creation transaction can modify only its own storage and codes. -* A smart contract can only interact with the blockchain in a mutable way using `CALL` or `CREATE`. +* A smart contract or a contract creation transaction can modify only + its own storage and codes. +* A smart contract can only interact with the blockchain in a mutable + way using `CALL` or `CREATE`. ### WebAssembly -This scheme can also be helpful when we deploy on-chain WebAssembly virtual machine. In that case, WASM contracts and EVM contracts can co-exist and the execution boundary and interaction model are clearly defined as above. +This scheme can also be helpful when we deploy on-chain WebAssembly +virtual machine. In that case, WASM contracts and EVM contracts can +co-exist and the execution boundary and interaction model are clearly +defined as above. From 4ce895610c32163b38e9f64e42d70b338b36b9e2 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 2 Apr 2019 21:29:11 +0200 Subject: [PATCH 132/431] Automatically merged updates to draft EIP(s) 1702 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1702.md | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index 5d97a665..cccb70e7 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -69,8 +69,7 @@ out-of-gas. ### Contract Execution VM version used in contract execution is determined via calling -`address` (`I_a` in yellow paper). Precompiled contract does not have -version. +`address` (`I_a` in yellow paper). ### Contract Creation Transaction @@ -93,6 +92,14 @@ recovering, sign ten items, with `v`, `r`, `s` as defined by EIP-155. The transaction would be executed in `version` supplied. If `version` is not supported or *validation* does not pass, return out-of-gas. +### Precompiled Contract and Externally-owned Address + +Precompiled contracts and externally-owned addresses do not have +`version`. If a message-call transaction or `CALL` / `CALLCODE` / +`STATICCALL` / `DELEGATECALL` touches a new externally-owned address +or a non-existing precompiled contract address, it is always created +with `version` field being `0`. + ## Discussions ### Performance @@ -103,24 +110,6 @@ machine version is simply an operation that changes a pointer using a different set of config parameters. As a result, this scheme has nearly zero impact to performance. -### Smart Contract Boundary and Formal Verification - -Many current efforts are on-going for getting smart contracts formally -verified. However, for any hard fork that introduces new opcodes or -change behaviors of existing opcodes would break the verification of -an existing contract has previously be formally verified. Using the -scheme described here, we define the boundary of how a smart contract -interacts with the blockchain and it might help the formal -verification efforts: - -* A smart contract has only immutable access to information of - blockchain account balances and codes. -* A smart contract has only immutable access of block information. -* A smart contract or a contract creation transaction can modify only - its own storage and codes. -* A smart contract can only interact with the blockchain in a mutable - way using `CALL` or `CREATE`. - ### WebAssembly This scheme can also be helpful when we deploy on-chain WebAssembly From 917dcdbb560a4fdc3920e33d61e8574742cbf1df Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 3 Apr 2019 00:46:15 +0200 Subject: [PATCH 133/431] Automatically merged updates to draft EIP(s) 1702 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1702.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index cccb70e7..714092cb 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -55,6 +55,29 @@ We let a family of contracts to always have the same `version`. That is, `CREATE` and `CREATE2` will always deploy contract that has the same `version` as the calling `address`. +#### Alternative Design + +This provides an alternative design that allows `CREATE` and `CREATE2` +to deploy contract whose version are different compared with *parent*. + +The client maintains a mapping `V` of currently supported version +prefix (for example, `\0asm`) to `version` number. All version +prefixes have the invariant that given any prefix in mapping `a` and +`b`, `a` is not `b`'s prefix. + +If the `version` of caller (determined by `I_a`) is zero, then +`CREATE` and `CREATE2` will always deploy contract with version zero. + +If the `version` of caller (determined by `I_a`) is not zero, do the +following checks and operations, and return out-of-gas if any of it +fails: + +* Check that the code starts with an prefix in `V`, with `version` + number. +* Use `version`'s validation procedure to validate the *whole* code + (with prefix). +* Deploy the contract with `version`. + ### Validation A new phrase, *validation* is added to contract deployment (by @@ -79,7 +102,7 @@ version. A contract creation transaction is always executed in run *validation* on the contract creation code. If it does not pass, return out-of-gas. -#### Alternative Design for Contract Creation Transaction +#### Alternative Design This provides an alternative design that allows contract to be created in multiple versions. From a44b8df4569c47496e2e4460237db4d56be12dd6 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 3 Apr 2019 00:57:08 +0200 Subject: [PATCH 134/431] Automatically merged updates to draft EIP(s) 1702 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1702.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index 714092cb..57f58262 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -57,26 +57,28 @@ same `version` as the calling `address`. #### Alternative Design -This provides an alternative design that allows `CREATE` and `CREATE2` -to deploy contract whose version are different compared with *parent*. +This provides an alternative design that allows `CREATE`, `CREATE2` +and contract creation transaction to deploy contract whose version are +different. The client maintains a mapping `V` of currently supported version prefix (for example, `\0asm`) to `version` number. All version prefixes have the invariant that given any prefix in mapping `a` and -`b`, `a` is not `b`'s prefix. +`b`, `a` is not `b`'s prefix. Version numbers in `V` cannot be zero. -If the `version` of caller (determined by `I_a`) is zero, then -`CREATE` and `CREATE2` will always deploy contract with version zero. +Apply the following cause on contract deployment for all `CREATE`, +`CREATE2` and contract deployment transaction. -If the `version` of caller (determined by `I_a`) is not zero, do the -following checks and operations, and return out-of-gas if any of it -fails: - -* Check that the code starts with an prefix in `V`, with `version` - number. -* Use `version`'s validation procedure to validate the *whole* code - (with prefix). -* Deploy the contract with `version`. +* If the `version` of caller (determined by `I_a`) is zero, then + `CREATE` and `CREATE2` will always deploy contract with version zero. +* If the `version` of caller (determined by `I_a`) is not zero, do the + following checks and operations, and return out-of-gas if any of it + fails: + * Check that the code starts with an prefix in `V`, with `version` + number. + * Use `version`'s validation procedure to validate the *whole* code + (with prefix). + * Deploy the contract with `version`. ### Validation From 56061ff0f83e0d0f4de112728102eb5651e3a65b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 3 Apr 2019 14:35:14 +0200 Subject: [PATCH 135/431] Automatically merged updates to draft EIP(s) 1702 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1702.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index 57f58262..1dc088d2 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -9,6 +9,11 @@ category: Core created: 2017-12-30 --- +## Simple Summary + +Introduce account versioning for smart contracts so upgrading the VM +or introducing new VMs can be easier. + ## Abstract This defines a method of hard forking while maintaining the exact @@ -125,6 +130,42 @@ Precompiled contracts and externally-owned addresses do not have or a non-existing precompiled contract address, it is always created with `version` field being `0`. +## Rationale + +This introduces account versioning via a new RLP item in account +state. The first design above gets account versioning by making the +contract *family* always have the same version. In this way, versions +are only needed to be provided by contract creation transaction, and +there is no restrictions on formats of code for any version. If we +want to support multiple newest VMs (for example, EVM and WebAssembly +running together), then this requires alternative design in contract +creation transaction section + +The second design above requires new versions of VMs follow a +formatting -- that it always has a prefix. In this way, the version +can be derived from the prefix, thus allowing a contract *family* to +have multiple versions. It also makes it so that we can pin contract +creation transaction using only one VM version, and it can deploy +other VM versions. + +Alternatively, account versioning can also be done through: + +* **EIP-1707** and **EIP-1712**: This makes an account's versioning + soly dependent on its code header prefix. If with only EIP-1707, it + is not possible to certify any code is valid, because current VM + allows treating code as data. This can be fixed by EIP-1712, but the + drawback is that it's potentially backward incompatible. +* **EIP-1891**: Instead of writing version field into account RLP + state, we write it in a separate contract. This can accomplish the + same thing as this EIP and potentially reduces code complexity, but + the drawback is that every code execution will require an additional + trie traversal, which impacts performance. + +## Backwards Compatibility + +Account versioning is fully backwards compatible, and it does not +change how current contracts are executed. + ## Discussions ### Performance @@ -141,3 +182,7 @@ This scheme can also be helpful when we deploy on-chain WebAssembly virtual machine. In that case, WASM contracts and EVM contracts can co-exist and the execution boundary and interaction model are clearly defined as above. + +## Test Cases and Implementations + +To be added. From eb4cb61530c8610031bcab475473fc0c54af667c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 3 Apr 2019 18:54:07 +0200 Subject: [PATCH 136/431] EIP-778: address review feedback (#1906) --- EIPS/eip-778.md | 60 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/EIPS/eip-778.md b/EIPS/eip-778.md index 7d0135d0..72d33157 100644 --- a/EIPS/eip-778.md +++ b/EIPS/eip-778.md @@ -37,10 +37,10 @@ be able to determine which record is newer. The components of a node record are: - `signature`: cryptographic signature of record contents -- `seq`: The sequence number, a 64 bit integer. Nodes should increase the number whenever - the record changes and republish the record. +- `seq`: The sequence number, a 64-bit unsigned integer. Nodes should increase the number + whenever the record changes and republish the record. - The remainder of the record consists of arbitrary key/value pairs, which must be sorted - by key. + by key. Keys must be unique. A record's signature is made and validated according to an *identity scheme*. The identity scheme is also responsible for deriving a node's address in the DHT. @@ -53,9 +53,9 @@ records larger than this size. Records are signed and encoded as follows: - content = rlp(seq) || rlp(k) || rlp(v) || ... - signature = rlp(sign(rlp_list(content))) - record = rlp_list(signature || content) + content = [seq, k, v, ...] + signature = sign(content) + record = [signature, seq, k, v, ...] ### Key/Value Pairs @@ -67,19 +67,20 @@ preferred. The following keys are pre-defined: | `id` | name of identity scheme, e.g. "v4" | | `secp256k1` | compressed secp256k1 public key, 33 bytes | | `ip` | IP address, 4 or 16 bytes | -| `tcp` | TCP port | -| `udp` | UDP port | +| `tcp` | TCP port, big endian integer | +| `udp` | UDP port, big endian integer | ### "v4" Identity Scheme This specification defines a single scheme to be used as the default. The "v4" scheme is -backwards-compatible with the cryptosystem used by Node Discovery Protocol v4. +backwards-compatible with the cryptosystem used by Node Discovery v4. - To sign record `content` with this scheme, apply the keccak256 hash function (as used by the EVM) to `content`, then create a signature of the hash. The resulting 64-byte - signature is encoded as the concatenation of the `r` and `s` signature values. + signature is encoded as the concatenation of the `r` and `s` signature values (the + recovery ID `v` is omitted). - To verify a record, check that the signature was made by the public key in the - "secp256k1" key/value pair. + "secp256k1" key/value pair of the record. - To derive a node address, take the keccak256 hash of the uncompressed public key. # Rationale @@ -98,6 +99,43 @@ in size-constrained protocols such as DNS. A record containing a IPv4 address, w using the "v4" scheme occupies roughly 120 bytes, leaving plenty of room for additional metadata. +# Test Vectors + +Example (valid) record: + +```text +f884b8407098ad865b00a582051940cb9cf36836572411a4727878307701 +1599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11 +df72ecf1145ccb9c01826964827634826970847f00000189736563703235 +366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1 +400f3258cd31388375647082765f +``` + +The raw RLP structure of this record is: + +```text +[ + 7098ad865b00a582051940cb9cf36836572411a47278783077011599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11df72ecf1145ccb9c, + 01, + "id", + "v4", + "ip", + 7f000001, + "secp256k1", + 03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138, + "udp", + 765f, +] +``` + +The record contains sequence number `1`. + +A v4 enode URL containing the same information (but no signature or sequence number): + +```text +enode://ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd31387574077f301b421bc84df7266c44e9e6d569fc56be00812904767bf5ccd1fc7f@127.0.0.1:0?discport=30303 +``` + # Copyright Copyright and related rights waived via CC0. From 024bd6070dc14472d4f2cf099262eb9e36fc9040 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Wed, 3 Apr 2019 10:07:55 -0700 Subject: [PATCH 137/431] EIP-1898: Add blockhash as option for some JSON-RPC methods (#1898) --- EIPS/eip-1898.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 EIPS/eip-1898.md diff --git a/EIPS/eip-1898.md b/EIPS/eip-1898.md new file mode 100644 index 00000000..7ea8da1a --- /dev/null +++ b/EIPS/eip-1898.md @@ -0,0 +1,70 @@ +--- +eip: 1898 +title: Add `blockHash` to JSON-RPC methods which accept a default block parameter. +author: Charles Cooper (@charles-cooper) +type: Standards Track +category: Interface +status: Draft +created: 2019-04-01 +requires: 234 +--- + +## Simple Summary + +For JSON-RPC methods which currently accept a default block parameter, additionally allow the parameter to be a block hash. + +## Abstract + +This EIP can be considered a generalization of [EIP-234](https://github.com/ethereum/EIPs/blob/d053eb66921c5915f3e16d72c7566289e2d7c151/EIPS/eip-234.md). It would enable clients to unambiguously specify the block they want to query for certain JSON-RPC methods, even if the block is not in the canonical chain. This allows clients to maintain a coherent picture of blockchain state that they are interested in, even in the presence of reorgs, without requiring that the node maintain a persistent connection with the client or store any client-specific state. + +## Specification + +The following JSON-RPC methods are affected: +- `eth_getBalance` +- `eth_getStorageAt` +- `eth_getTransactionCount` +- `eth_getCode` +- `eth_call` +- `eth_getProof` + +The following options, quoted from the [JSON-RPC spec](https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter), are currently possible for the defaultBlock parameter: +> - HEX String - an integer block number +> - String "earliest" for the earliest/genesis block +> - String "latest" - for the latest mined block +> - String "pending" - for the pending state/transactions + +Since there is no way to clearly distinguish between a DATA parameter and a QUANTITY parameter, this EIP proposes a new scheme for the block parameter. The following option is additionally allowed: +- OBJECT + - `blockNumber`: QUANTITY - a block number + - `blockHash`: DATA - a block hash + +To maintain backwards compatibility, the block number may be specified either as a hex string or using the new block parameter scheme. In other words, the following are equivalent for the default block parameter: +- `"earliest"` +- `"0x0"` +- `{ "blockNumber": "0x0" }` +- `{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" }` (hash of the genesis block on the Ethereum main chain) + +## Rationale + +Currently, the state-querying JSON-RPC methods specified above have no option to unambiguously specify which block to query the state for. This can cause issues for applications which need to make multiple calls to the RPC. For instance, a wallet which just executed a transfer may want to display the balances of both the sender and recipient. If there is a re-org in between when the balance of the sender is queried via `eth_getBalance` and when the balance of the recipient is queried, the balances may not reconcile. As a slightly more complicated example, the UI for a decentralized exchange (which hosts orders on-chain) may walk a list of orders by calling `eth_call` for each of them to get the order data. Another type of use case is where an application needs to make a decision based on multiple pieces of state, e.g. a payout predicated on simultaneous ownership of two NFTs. + +In order to ensure that the state is coherent (i.e., `eth_call` was called with exactly the same block for every call), the application may currently use one of several strategies: +- Decide on a block number to use (e.g., the latest block number known to the application). After each `eth_call` using that block number, call `eth_getBlockByNumber`, also with that block number. If the block hash does not match the known hash for that block number, rollback the current activity and retry from the beginning. This adds `O(n)` invocations as baseline overhead and another `O(n)` invocations for every retry needed. Moreover, there is no way to detect the (unlikely but possible) case that the relevant block was reorged out before `eth_call`, and then reorged back in before `eth_getBlockByNumber`. +- Rely on logs, which *can* be queried unambiguously thanks to the `blockHash` parameter. However, this requires semantic support from the smart contract; if the smart contract does not emit appropriate events, the client will not be able to reconstruct the specific state it is interested in. +- Rely on non-standard extensions like `parity_subscribe`. This requires a persistent connection between the client and node (via IPC or websockets), increases coupling between the client and the node, and cannot handle use cases where there are dependencies between invocations of `eth_call`, for example, walking a linked list. + +Allowing `eth_call` and friends to unambiguously specify the block to be queried give the application developer a robust and intuitive way to solve these problems. Multiple sequential queries will query the same state, enabling the application developer to not worry about inconsistencies in their view of the blockchain state. + +## Backwards Compatibility + +Backwards compatible. + +## Test Cases + +## Implementation + +None yet. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 4e169dcb6e1d237c9f2e75eb347efb3c94b54f74 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Wed, 3 Apr 2019 19:22:52 +0200 Subject: [PATCH 138/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 521d2482..f2b4c8bf 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -292,7 +292,7 @@ Indicates the authorization of `operator` as an *operator* for `holder`. > **parameters** > `operator`: Address which became an *operator* of `holder`. -> `holder`: Address of a holder which authorized the `operator` address as an *operator*. +> `holder`: Address of a *holder* which authorized the `operator` address as an *operator*. **`RevokedOperator` event** @@ -306,7 +306,7 @@ Indicates the revocation of `operator` as an *operator* for `holder`. > **parameters** > `operator`: Address which was revoked as an *operator* of `holder`. -> `holder`: Address of a holder which revoked the `operator` address as an *operator*. +> `holder`: Address of a *holder* which revoked the `operator` address as an *operator*. The `defaultOperators`, `authorizeOperator`, `revokeOperator` and `isOperatorFor` functions described below MUST be implemented to manage *operators*. @@ -367,7 +367,7 @@ Indicate whether the `operator` address is an *operator* of the `holder` address > **parameters** > `operator`: Address which may be an *operator* of `holder`. -> `holder`: Address of a holder which may have the `operator` address as an *operator*. +> `holder`: Address of a *holder* which may have the `operator` address as an *operator*. > > **returns:** `true` if `operator` is an *operator* of `holder` and `false` otherwise. @@ -465,9 +465,9 @@ Indicate a send of `amount` of tokens from the `from` address to the `to` addres > **parameters** > `operator`: Address which triggered the send. -> `from`: Holder. -> `to`: Token recipient. -> `amount`: Number of tokens to send. +> `from`: *Holder* whose tokens were sent. +> `to`: Recipient of the tokens. +> `amount`: Number of tokens sent. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. @@ -485,7 +485,7 @@ Send the `amount` of tokens from the address `msg.sender` to the address `to`. The *operator* and the *holder* MUST both be the `msg.sender`. > **parameters** -> `to`: Token recipient. +> `to`: Recipient of the tokens. > `amount`: Number of tokens to send. > `data`: Information provided by the *holder*. @@ -497,10 +497,6 @@ function operatorSend(address from, address to, uint256 amount, bytes calldata d Send the `amount` of tokens on behalf of the address `from` to the address `to`. -The *operator* MUST be `msg.sender`. -The value of `from` MAY be `0x0`, -then the `from` (*holder*) used for the send MUST be `msg.sender` (the `operator`). - *Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the send process MUST `revert`. @@ -511,8 +507,8 @@ that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `send` function). > **parameters** -> `from`: Holder (or `0x0` to set `from` to `msg.sender`). -> `to`: Token recipient. +> `from`: *Holder* whose tokens are being sent. +> `to`: Recipient of the tokens. > `amount`: Number of tokens to send. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. @@ -585,9 +581,9 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` > **parameters** > `operator`: Address which triggered the mint. -> `to`: Token recipient. +> `to`: Recipient of the tokens. > `amount`: Number of tokens minted. -> `data`: Information provided by the *holder*. +> `data`: MUST be empty. > `operatorData`: Information provided by the *operator*. #### **Burning Tokens** @@ -661,7 +657,7 @@ Indicate the burning of `amount` of tokens from the `from` address by the `opera > **parameters** > `operator`: Address which triggered the burn. -> `from`: Holder whose tokens are burned. +> `from`: *Holder* whose tokens were burned. > `amount`: Number of tokens burned. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. @@ -691,15 +687,11 @@ function operatorBurn(address from, uint256 amount, bytes calldata data, bytes c Burn the `amount` of tokens on behalf of the address `from`. -The *operator* MUST be `msg.sender`. -The value of `from` MAY be `0x0`, -then the `from` (*holder*) used for the burn MUST be `msg.sender` (the `operator`). - *Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`. > **parameters** -> `from`: Holder whose tokens will be burned (or `0x0` to set `from` to `msg.sender`). +> `from`: *Holder* whose tokens will be burned. > `amount`: Number of tokens to burn. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. @@ -750,8 +742,8 @@ by the `operator` address. > **parameters** > `operator`: Address which triggered the balance decrease (through sending or burning). -> `from`: *holder*. -> `to`: *token recipient* for a send and `0x` for a burn. +> `from`: *Holder* whose tokens were sent. +> `to`: Recipient of the tokens for a send (or `0x0` for a burn). > `amount`: Number of tokens the *holder* balance is decreased by. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. @@ -835,8 +827,8 @@ by the `operator` address. > **parameters** > `operator`: Address which triggered the balance increase (through sending or minting). -> `from`: *holder* for a send and `0x` for a mint. -> `to`: *token recipient*. +> `from`: *Holder* whose tokens were sent (or `0x0` for a mint). +> `to`: Recipient of the tokens. > `amount`: Number of tokens the *recipient* balance is increased by. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. From e86ff4d817668f62352952332faad21029605c8f Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 3 Apr 2019 12:39:56 -0600 Subject: [PATCH 139/431] EIP-1872: Ethereum Network Upgrade Windows (#1872) --- EIPS/eip-1872.md | 217 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 EIPS/eip-1872.md diff --git a/EIPS/eip-1872.md b/EIPS/eip-1872.md new file mode 100644 index 00000000..8ef9e265 --- /dev/null +++ b/EIPS/eip-1872.md @@ -0,0 +1,217 @@ +--- +eip: 1872 +title: Ethereum Network Upgrade Windows +author: Danno Ferrin (@shemnon) +discussions-to: https://ethereum-magicians.org/t/eip-ethereum-network-upgrade-windows/ +status: Draft +type: Meta +created: 2018-03-25 +--- + +## Simple Summary + +A proposal to define a limited number of annual time windows in which network +upgrades (aka hard forks) should be performed within. Policies for scheduling +network upgrades outside these windows are also described. + +## Abstract + +Four different weeks, spaced roughly evenly throughout the year, are targeted +for network upgrades to be launched. Regular network upgrades should announce +their intention to launch in a particular window early in their process and +choose a block number four to six weeks prior to that window. If a network +upgrade is cancelled then it would be rescheduled for the next window. Not all +windows will be used. Priority upgrades outside the roadmap may be scheduled in +the third week of any month, but such use is discouraged. Critical upgrades are +scheduled as needed. + +## Motivation + +The aim of this EIP is to provide some level of regularity and predictability to +the Ethereum network upgrade/hard fork process. This will allow service +providers such as exchanges and node operators a predictable framework to +schedule activities around. This also provides a framework to regularize the +delivery of network upgrades. + +## Specification + +Scheduling is defined for three categories of network upgrades. First are +`Roadmap` network upgrades that include deliberate protocol improvements. Next +are `Priority` network updates, where there are technical reasons that +necessitate a prompt protocol change but these reasons do not present a systemic +risk to the protocol or the ecosystem. Finally, `Critical` network upgrades are +to address issues that present a systemic risk to the protocol or the ecosystem. + +### Roadmap Network Upgrades + +Roadmap network upgrades are network upgrades that are deliberate and measured +to improve the protocol and ecosystem. Historical examples are Homestead, +Byzantium, and Constantinople. + +Roadmap network upgrades should be scheduled in one of four windows: the week +with the third Wednesday in January, April, July, and October. When initiating a +network upgrade or early in the planning process a particular window should be +targeted. + +> **Note to reviewers:** The months and week chosen are to provide an initial +> recommendation and are easily modifiable prior to final call. They thread the +> needle between many third quarter and fourth quarter holidays. + +Implementors are expected to have software for a Roadmap network upgrade ready +two to four weeks prior to the upgrade. Hence a block number for the network +upgrade should be chosen four to six weeks prior to the network upgrade window. +Scheduling details such as whether this choice is made prior to or after testnet +deployment are out of scope of this EIP. + +Depending on the release cadence of Roadmap network upgrades some windows will +not be used. For example if a six month release cadence is chosen a roadmap +upgrade would not occur in adjacent upgrade windows. Hence for a six month +cadence if a roadmap upgrade occurred in April then the July window would not be +used for network upgrades. + +If a planned roadmap upgrade needs to be rescheduled then strong consideration +should be given to rescheduling the upgrade for the next window in three months +time. For the case of a six month cadence this may cause releases to be in +adjacent release windows. For a three month cadence the next network upgrade +would be merged with the current upgrade or the next network upgrade would be +delayed. + +To be compatible with the scheduled release windows the cadence of the Roadmap +Network Upgrades should be a multiple of three months. Whether it is three, six, +nine, or more month cadence is out of scope of this EIP. + +### Priority Network Upgrades + +Priority network upgrades are reserved for upgrades that require more urgency +than a roadmap network upgrade yet do not present a systemic risk to the network +or the ecosystem. To date there have been no examples of a priority upgrade. +Possible examples may include roadmap upgrades that need to occur in multiple +upgrades or for security risks that have a existing mitigation in place that +would be better served by a network upgrade. Another possible reason may be to +defuse the difficulty bomb due to postponed roadmap upgrades. + +Priority network upgrades are best launched in unused roadmap launch windows, +namely the third week of January, April, July, and October. If necessary they +may be launched in the third week of any month, but strong consideration and +preference should be given to unused roadmap launch windows. + +Priority network upgrades should be announced and a block chosen far enough in +advance so major clients implementors can release software with the needed block +number in a timely fashion. These releases should occur at least a week before +the launch window. Hence priority launch windows should be chosen two to four +weeks in advance. + +### Critical Network Upgrades + +Critical network upgrades are network upgrades that are designed to address +systemic risks to the protocol or to the ecosystem. Historical examples include +Dao Fork, Tangerine Whistle, and Spurious Dragon. + +This EIP provides neither guidance nor restrictions to the development and +deployment of these emergency hard forks. These upgrades are typically launched +promptly after a solution to the systemic risk is agreed upon between the client +implementors. + +It is recommended that such upgrades perform the minimum amount of changes +needed to address the issues that caused the need for the Critical network +upgrade and that other changes be integrated into subsequent Priority and +Roadmap network upgrades. + +### Network Upgrade Block Number Choice + +When choosing an activation block the number can be used to communicate the role +of a particular network in the Ethereum Ecosystem. Networks that serve as a +value store or are otherwise production grade have different stability concerns +than networks that serve as technology demonstration or are explicitly +designated for testing. + +To date all Mainnet activation blocks have ended in three or more zeros, +including Critical Network Upgrades. Ropsten and Kovan initially started with +three zeros but switched to palindromic numbers. Rinkeby has always had +palindromic activation blocks. Goerli has yet to perform a network upgrade. + +To continue this pattern network upgrade activation block numbers for mainnet +deployments and production grade networks should chose a number whose base 10 +representation ends with three or more zeros. + +For testnet and testing or development grades network operators are encouraged +to choose a block activation number that is a palindrome in base 10. + +Block numbers for Roadmap and Priority network upgrades should be chosen so that +it is forecast to occur relatively close to Wednesday at 12:00 UTC+0 during the +launch window. This should result in an actual block production occurring +sometime between Monday and Friday of the chosen week. + +## Rationale + +The rationale for defining launch windows is to give business running Ethereum +infrastructure a predictable schedule for when upgrades may or may not occur. +Knowing when a upgrade is not going to occur gives the businesses a clear time +frame within which to perform internal upgrades free from external changes. It +also provides a timetable for developers and IT professionals to schedule time +off against. + +## Backwards Compatibility + +Except for the specific launch windows the previous network upgrades would have +complied with these policies. Homestead, Byzantium, and Constantinople would +have been Roadmap Network Upgrades. There were no Priority Network Upgrades, +although Spurious Dragon would have been a good candidate. Dao Fork was a +Critical Network Upgrade in response to TheDao. Tangerine Whistle and Spurious +Dragon were critical upgrades in response to the Shanghai Spam Attacks. +Constantinople Fix (as it is termed in the reference tests) was in response to +the EIP-1283 security issues. + +If this policy were in place prior to Constantinople then the initial 2018 +launch would likely have been bumped to the next window after the Ropsten +testnet consensus failures. The EIP-1283 issues likely would have resulted in an +out of window upgrade because of the impact of the difficulty bomb. + + + + +## Implementation + +The windows in this EIP are expected to start after the Istanbul Network +upgrade, which is the next planned Roadmap upgrade. Istanbul is currently slated +for mainnet launch on 2019-10-16, which is compatible with the schedule in this +EIP. + +The Roadmap Upgrade windows starting with Istanbul would be as follows: + +| Block Target | Launch Week Range | +| ------------ | ------------------------ | +| 2019-10-16 | 2019-10-14 to 2019-10-18 | +| 2020-01-15 | 2020-01-13 to 2020-01-17 | +| 2020-04-15 | 2020-04-13 to 2020-04-17 | +| 2020-07-15 | 2020-07-13 to 2020-07-17 | +| 2020-10-21 | 2020-10-19 to 2020-10-23 | +| 2021-01-20 | 2021-01-18 to 2021-01-22 | +| 2021-04-21 | 2021-04-19 to 2021-04-23 | +| 2021-07-21 | 2021-07-19 to 2021-07-23 | +| 2021-10-20 | 2021-10-18 to 2021-10-22 | +| 2022-01-19 | 2022-01-17 to 2022-01-21 | +| 2022-04-20 | 2022-04-18 to 2022-04-22 | +| 2022-07-20 | 2022-07-18 to 2022-07-22 | +| 2022-10-19 | 2022-10-17 to 2022-10-21 | + +The Priority windows through next year, excluding Roadmap windows, are as +follows: + +| Block Target | Launch Week Range | +| ------------ | ------------------------ | +| 2019-11-20 | 2019-11-18 to 2019-11-22 | +| 2019-12-18 | 2019-12-16 to 2019-12-20 | +| 2020-02-19 | 2020-02-17 to 2020-02-21 | +| 2020-03-18 | 2020-03-16 to 2020-03-20 | +| 2020-05-20 | 2020-05-18 to 2020-05-22 | +| 2020-06-17 | 2020-06-15 to 2020-06-19 | +| 2020-08-19 | 2020-08-18 to 2020-08-21 | +| 2020-09-16 | 2020-09-14 to 2020-09-18 | +| 2020-11-18 | 2020-11-16 to 2020-11-20 | +| 2020-12-16 | 2020-12-14 to 2020-12-18 | + +## Copyright + +Copyright and related rights waived via +[CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 556cc58428a0044141a878ad5e68b18bc69e13f0 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Thu, 4 Apr 2019 15:08:46 +0200 Subject: [PATCH 140/431] Automatically merged updates to draft EIP(s) 1820 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1820.md | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md index 758e645f..fdaa761a 100644 --- a/EIPS/eip-1820.md +++ b/EIPS/eip-1820.md @@ -86,16 +86,16 @@ Thus solving the problem of resolving the correct registry address for different * */ pragma solidity 0.5.3; -// IV is value needed to have a vanity address starting with `0x1820`. -// IV: 87018 +// IV is value needed to have a vanity address starting with '0x1820'. +// IV: 53759 /// @dev The interface a contract MUST implement if it is the implementer of /// some (other) interface for any address other than itself. interface ERC1820ImplementerInterface { - /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not. + /// @notice Indicates whether the contract implements the interface 'interfaceHash' for the address 'addr' or not. /// @param interfaceHash keccak256 hash of the name of the interface /// @param addr Address for which the contract will implement the interface - /// @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`. + /// @return ERC1820_ACCEPT_MAGIC only if the contract implements 'interfaceHash' for the address 'addr'. function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32); } @@ -119,9 +119,9 @@ contract ERC1820Registry { /// @notice flag for each address and erc165 interface to indicate if it is cached. mapping(address => mapping(bytes4 => bool)) internal erc165Cached; - /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`. + /// @notice Indicates a contract is the 'implementer' of 'interfaceHash' for 'addr'. event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer); - /// @notice Indicates `newManager` is the address of the new manager for `addr`. + /// @notice Indicates 'newManager' is the address of the new manager for 'addr'. event ManagerChanged(address indexed addr, address indexed newManager); /// @notice Query if an address implements an interface and through which contract. @@ -129,8 +129,8 @@ contract ERC1820Registry { /// (If '_addr' is the zero address then 'msg.sender' is assumed.) /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. - /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr.address()` - /// or '0' if `_addr.address()` did not register an implementer for this interface. + /// @return The address of the contract which implements the interface '_interfaceHash' for '_addr' + /// or '0' if '_addr' did not register an implementer for this interface. function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) { address addr = _addr == address(0) ? msg.sender : _addr; if (isERC165Interface(_interfaceHash)) { @@ -147,7 +147,7 @@ contract ERC1820Registry { /// (If '_addr' is the zero address then 'msg.sender' is assumed.) /// @param _interfaceHash Keccak256 hash of the name of the interface as a string. /// E.g., 'web3.utils.keccak256("ERC777TokensRecipient")' for the 'ERC777TokensRecipient' interface. - /// @param _implementer Contract address implementing `_interfaceHash` for `_addr.address()`. + /// @param _implementer Contract address implementing '_interfaceHash' for '_addr'. function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external { address addr = _addr == address(0) ? msg.sender : _addr; require(getManager(addr) == msg.sender, "Not the manager"); @@ -164,11 +164,10 @@ contract ERC1820Registry { emit InterfaceImplementerSet(addr, _interfaceHash, _implementer); } - /// @notice Sets `_newManager.address()` as manager for `_addr.address()`. - /// The new manager will be able to call 'setInterfaceImplementer' for `_addr.address()`. + /// @notice Sets '_newManager' as manager for '_addr'. + /// The new manager will be able to call 'setInterfaceImplementer' for '_addr'. /// @param _addr Address for which to set the new manager. - /// @param _newManager Address of the new manager for `addr.address()`. - /// (Pass '0x0' to reset the manager to `_addr.address()`.) + /// @param _newManager Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.) function setManager(address _addr, address _newManager) external { require(getManager(_addr) == msg.sender, "Not the manager"); managers[_addr] = _newManager == _addr ? address(0) : _newManager; @@ -212,7 +211,7 @@ contract ERC1820Registry { // 'updateERC165Cache' with the contract address. /// @param _contract Address of the contract to check. /// @param _interfaceId ERC165 interface to check. - /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise. + /// @return True if '_contract' implements '_interfaceId', false otherwise. function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) { if (!erc165Cached[_contract][_interfaceId]) { return implementsERC165InterfaceNoCache(_contract, _interfaceId); @@ -223,7 +222,7 @@ contract ERC1820Registry { /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. /// @param _contract Address of the contract to check. /// @param _interfaceId ERC165 interface to check. - /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise. + /// @return True if '_contract' implements '_interfaceId', false otherwise. function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) { uint256 success; uint256 result; @@ -247,7 +246,7 @@ contract ERC1820Registry { /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not. /// @param _interfaceHash The hash to check. - /// @return True if `_interfaceHash` is an ERC165 interface (ending with 28 zeroes), false otherwise. + /// @return True if '_interfaceHash' is an ERC165 interface (ending with 28 zeroes), false otherwise. function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) { return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0; } @@ -284,7 +283,7 @@ contract ERC1820Registry { Below is the raw transaction which MUST be used to deploy the smart contract on any chain. ``` -0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a723058207d33f0c34a1016c7fcf5f8547cd8c09a74f837ed2564550f647531f1128056ec00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820 +0xf90a388085174876e800830c35008080b909e5608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c00291ba01820182018201820182018201820182018201820182018201820182018201820a01820182018201820182018201820182018201820182018201820182018201820 ``` The strings of `1820`'s at the end of the transaction are the `r` and `s` of the signature. @@ -323,7 +322,7 @@ This operation can be done on any chain, guaranteeing that the contract address ### Single-use Registry Deployment Account ``` -0x5808bA8E60E0367C9067b328D75C1f3d29de58cf +0xa990077c3205cbDf861e17Fa532eeB069cE9fF96 ``` This account is generated by reverse engineering it from its signature for the transaction. @@ -334,7 +333,7 @@ This way no one knows the private key, but it is known that it is the valid sign ### Registry Contract Address ``` -0x1820b744B33945482C17Dc37218C01D858EBc714 +0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 ``` The contract has the address above for every chain on which it is deployed. @@ -562,7 +561,7 @@ The contract has the address above for every chain on which it is deployed. "_addr": "Address being queried for the implementer of an interface. (If '_addr' is the zero address then 'msg.sender' is assumed.)", "_interfaceHash": "Keccak256 hash of the name of the interface as a string. E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface." }, - "return": "The address of the contract which implements the interface `_interfaceHash` for `_addr.address()` or '0' if `_addr.address()` did not register an implementer for this interface." + "return": "The address of the contract which implements the interface '_interfaceHash' for '_addr' or '0' if '_addr' did not register an implementer for this interface." }, "getManager(address)": { "params": { @@ -575,14 +574,14 @@ The contract has the address above for every chain on which it is deployed. "_contract": "Address of the contract to check.", "_interfaceId": "ERC165 interface to check." }, - "return": "True if `_contract.address()` implements `_interfaceId`, false otherwise." + "return": "True if '_contract' implements '_interfaceId', false otherwise." }, "implementsERC165InterfaceNoCache(address,bytes4)": { "params": { "_contract": "Address of the contract to check.", "_interfaceId": "ERC165 interface to check." }, - "return": "True if `_contract.address()` implements `_interfaceId`, false otherwise." + "return": "True if '_contract' implements '_interfaceId', false otherwise." }, "interfaceHash(string)": { "params": { @@ -593,14 +592,14 @@ The contract has the address above for every chain on which it is deployed. "setInterfaceImplementer(address,bytes32,address)": { "params": { "_addr": "Address for which to set the interface. (If '_addr' is the zero address then 'msg.sender' is assumed.)", - "_implementer": "Contract address implementing `_interfaceHash` for `_addr.address()`.", + "_implementer": "Contract address implementing '_interfaceHash' for '_addr'.", "_interfaceHash": "Keccak256 hash of the name of the interface as a string. E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface." } }, "setManager(address,address)": { "params": { "_addr": "Address for which to set the new manager.", - "_newManager": "Address of the new manager for `addr.address()`. (Pass '0x0' to reset the manager to `_addr.address()`.)" + "_newManager": "Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.)" } }, "updateERC165Cache(address,bytes4)": { @@ -630,7 +629,7 @@ The contract has the address above for every chain on which it is deployed. "notice": "Sets the contract which implements a specific interface for an address. Only the manager defined for that address can set it. (Each address is the manager for itself until it sets a new manager.)" }, "setManager(address,address)": { - "notice": "Sets `_newManager.address()` as manager for `_addr.address()`. The new manager will be able to call 'setInterfaceImplementer' for `_addr.address()`." + "notice": "Sets '_newManager' as manager for '_addr'. The new manager will be able to call 'setInterfaceImplementer' for '_addr'." }, "updateERC165Cache(address,bytes4)": { "notice": "Updates the cache with whether the contract implements an ERC165 interface or not." @@ -653,8 +652,8 @@ The contract has the address above for every chain on which it is deployed. }, "sources": { "./contracts/ERC1820Registry.sol": { - "content": "/* ERC1820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address (contract or regular account) can\n * register which interface it supports and which smart contract is responsible for its implementation.\n *\n * Written in 2019 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to\n * this software to the public domain worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see\n * .\n *\n * ███████╗██████╗ ██████╗ ██╗ █████╗ ██████╗ ██████╗\n * ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗\n * █████╗ ██████╔╝██║ ╚██║╚█████╔╝ █████╔╝██║██╔██║\n * ██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔═══╝ ████╔╝██║\n * ███████╗██║ ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝\n * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗\n * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝\n * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝\n * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║\n * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\n *\n */\npragma solidity 0.5.3;\n// IV is value needed to have a vanity address starting with `0x1820`.\n// IV: 87018\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC1820ImplementerInterface {\n /// @notice Indicates whether the contract implements the interface `interfaceHash` for the address `addr` or not.\n /// @param interfaceHash keccak256 hash of the name of the interface\n /// @param addr Address for which the contract will implement the interface\n /// @return ERC1820_ACCEPT_MAGIC only if the contract implements `interfaceHash` for the address `addr`.\n function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC1820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC1820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820\ncontract ERC1820Registry {\n /// @notice ERC165 Invalid ID.\n bytes4 constant internal INVALID_ID = 0xffffffff;\n /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n bytes4 constant internal ERC165ID = 0x01ffc9a7;\n /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC1820_ACCEPT_MAGIC\"));\n\n /// @notice mapping from addresses and interface hashes to their implementers.\n mapping(address => mapping(bytes32 => address)) internal interfaces;\n /// @notice mapping from addresses to their manager.\n mapping(address => address) internal managers;\n /// @notice flag for each address and erc165 interface to indicate if it is cached.\n mapping(address => mapping(bytes4 => bool)) internal erc165Cached;\n\n /// @notice Indicates a contract is the `implementer` of `interfaceHash` for `addr`.\n event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n /// @notice Indicates `newManager` is the address of the new manager for `addr`.\n event ManagerChanged(address indexed addr, address indexed newManager);\n\n /// @notice Query if an address implements an interface and through which contract.\n /// @param _addr Address being queried for the implementer of an interface.\n /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n /// @return The address of the contract which implements the interface `_interfaceHash` for `_addr.address()`\n /// or '0' if `_addr.address()` did not register an implementer for this interface.\n function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n address addr = _addr == address(0) ? msg.sender : _addr;\n if (isERC165Interface(_interfaceHash)) {\n bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0);\n }\n return interfaces[addr][_interfaceHash];\n }\n\n /// @notice Sets the contract which implements a specific interface for an address.\n /// Only the manager defined for that address can set it.\n /// (Each address is the manager for itself until it sets a new manager.)\n /// @param _addr Address for which to set the interface.\n /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n /// @param _implementer Contract address implementing `_interfaceHash` for `_addr.address()`.\n function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n address addr = _addr == address(0) ? msg.sender : _addr;\n require(getManager(addr) == msg.sender, \"Not the manager\");\n\n require(!isERC165Interface(_interfaceHash), \"Must not be an ERC165 hash\");\n if (_implementer != address(0) && _implementer != msg.sender) {\n require(\n ERC1820ImplementerInterface(_implementer)\n .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC,\n \"Does not implement the interface\"\n );\n }\n interfaces[addr][_interfaceHash] = _implementer;\n emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n }\n\n /// @notice Sets `_newManager.address()` as manager for `_addr.address()`.\n /// The new manager will be able to call 'setInterfaceImplementer' for `_addr.address()`.\n /// @param _addr Address for which to set the new manager.\n /// @param _newManager Address of the new manager for `addr.address()`.\n /// (Pass '0x0' to reset the manager to `_addr.address()`.)\n function setManager(address _addr, address _newManager) external {\n require(getManager(_addr) == msg.sender, \"Not the manager\");\n managers[_addr] = _newManager == _addr ? address(0) : _newManager;\n emit ManagerChanged(_addr, _newManager);\n }\n\n /// @notice Get the manager of an address.\n /// @param _addr Address for which to return the manager.\n /// @return Address of the manager for a given address.\n function getManager(address _addr) public view returns(address) {\n // By default the manager of an address is the same address\n if (managers[_addr] == address(0)) {\n return _addr;\n } else {\n return managers[_addr];\n }\n }\n\n /// @notice Compute the keccak256 hash of an interface given its name.\n /// @param _interfaceName Name of the interface.\n /// @return The keccak256 hash of an interface name.\n function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) {\n return keccak256(abi.encodePacked(_interfaceName));\n }\n\n /* --- ERC165 Related Functions --- */\n /* --- Developed in collaboration with William Entriken. --- */\n\n /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n /// @param _contract Address of the contract for which to update the cache.\n /// @param _interfaceId ERC165 interface for which to update the cache.\n function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(\n _contract, _interfaceId) ? _contract : address(0);\n erc165Cached[_contract][_interfaceId] = true;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not.\n // If the result is not cached a direct lookup on the contract address is performed.\n // If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n // 'updateERC165Cache' with the contract address.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise.\n function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n if (!erc165Cached[_contract][_interfaceId]) {\n return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n }\n return interfaces[_contract][_interfaceId] == _contract;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return True if `_contract.address()` implements `_interfaceId`, false otherwise.\n function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n uint256 success;\n uint256 result;\n\n (success, result) = noThrowCall(_contract, ERC165ID);\n if (success == 0 || result == 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, INVALID_ID);\n if (success == 0 || result != 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, _interfaceId);\n if (success == 1 && result == 1) {\n return true;\n }\n return false;\n }\n\n /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n /// @param _interfaceHash The hash to check.\n /// @return True if `_interfaceHash` is an ERC165 interface (ending with 28 zeroes), false otherwise.\n function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n }\n\n /// @dev Make a call on a contract without throwing if the function does not exist.\n function noThrowCall(address _contract, bytes4 _interfaceId)\n internal view returns (uint256 success, uint256 result)\n {\n bytes4 erc165ID = ERC165ID;\n\n assembly {\n let x := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(x, erc165ID) // Place signature at beginning of empty storage\n mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n success := staticcall(\n 30000, // 30k gas\n _contract, // To addr\n x, // Inputs are stored at location x\n 0x24, // Inputs are 36 (4 + 32) bytes long\n x, // Store output over input (saves space)\n 0x20 // Outputs are 32 bytes long\n )\n\n result := mload(x) // Load the result\n }\n }\n}\n", - "keccak256": "0xdb01f4b0c42ecb3a60f096b0a082411875fbbd78e87d88868975ad9d983c030d" + "content": "/* ERC1820 Pseudo-introspection Registry Contract\n * This standard defines a universal registry smart contract where any address (contract or regular account) can\n * register which interface it supports and which smart contract is responsible for its implementation.\n *\n * Written in 2019 by Jordi Baylina and Jacques Dafflon\n *\n * To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to\n * this software to the public domain worldwide. This software is distributed without any warranty.\n *\n * You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see\n * .\n *\n * ███████╗██████╗ ██████╗ ██╗ █████╗ ██████╗ ██████╗\n * ██╔════╝██╔══██╗██╔════╝███║██╔══██╗╚════██╗██╔═████╗\n * █████╗ ██████╔╝██║ ╚██║╚█████╔╝ █████╔╝██║██╔██║\n * ██╔══╝ ██╔══██╗██║ ██║██╔══██╗██╔═══╝ ████╔╝██║\n * ███████╗██║ ██║╚██████╗ ██║╚█████╔╝███████╗╚██████╔╝\n * ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚════╝ ╚══════╝ ╚═════╝\n *\n * ██████╗ ███████╗ ██████╗ ██╗███████╗████████╗██████╗ ██╗ ██╗\n * ██╔══██╗██╔════╝██╔════╝ ██║██╔════╝╚══██╔══╝██╔══██╗╚██╗ ██╔╝\n * ██████╔╝█████╗ ██║ ███╗██║███████╗ ██║ ██████╔╝ ╚████╔╝\n * ██╔══██╗██╔══╝ ██║ ██║██║╚════██║ ██║ ██╔══██╗ ╚██╔╝\n * ██║ ██║███████╗╚██████╔╝██║███████║ ██║ ██║ ██║ ██║\n * ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\n *\n */\npragma solidity 0.5.3;\n// IV is value needed to have a vanity address starting with '0x1820'.\n// IV: 53759\n\n/// @dev The interface a contract MUST implement if it is the implementer of\n/// some (other) interface for any address other than itself.\ninterface ERC1820ImplementerInterface {\n /// @notice Indicates whether the contract implements the interface 'interfaceHash' for the address 'addr' or not.\n /// @param interfaceHash keccak256 hash of the name of the interface\n /// @param addr Address for which the contract will implement the interface\n /// @return ERC1820_ACCEPT_MAGIC only if the contract implements 'interfaceHash' for the address 'addr'.\n function canImplementInterfaceForAddress(bytes32 interfaceHash, address addr) external view returns(bytes32);\n}\n\n\n/// @title ERC1820 Pseudo-introspection Registry Contract\n/// @author Jordi Baylina and Jacques Dafflon\n/// @notice This contract is the official implementation of the ERC1820 Registry.\n/// @notice For more details, see https://eips.ethereum.org/EIPS/eip-1820\ncontract ERC1820Registry {\n /// @notice ERC165 Invalid ID.\n bytes4 constant internal INVALID_ID = 0xffffffff;\n /// @notice Method ID for the ERC165 supportsInterface method (= `bytes4(keccak256('supportsInterface(bytes4)'))`).\n bytes4 constant internal ERC165ID = 0x01ffc9a7;\n /// @notice Magic value which is returned if a contract implements an interface on behalf of some other address.\n bytes32 constant internal ERC1820_ACCEPT_MAGIC = keccak256(abi.encodePacked(\"ERC1820_ACCEPT_MAGIC\"));\n\n /// @notice mapping from addresses and interface hashes to their implementers.\n mapping(address => mapping(bytes32 => address)) internal interfaces;\n /// @notice mapping from addresses to their manager.\n mapping(address => address) internal managers;\n /// @notice flag for each address and erc165 interface to indicate if it is cached.\n mapping(address => mapping(bytes4 => bool)) internal erc165Cached;\n\n /// @notice Indicates a contract is the 'implementer' of 'interfaceHash' for 'addr'.\n event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);\n /// @notice Indicates 'newManager' is the address of the new manager for 'addr'.\n event ManagerChanged(address indexed addr, address indexed newManager);\n\n /// @notice Query if an address implements an interface and through which contract.\n /// @param _addr Address being queried for the implementer of an interface.\n /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n /// @return The address of the contract which implements the interface '_interfaceHash' for '_addr'\n /// or '0' if '_addr' did not register an implementer for this interface.\n function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address) {\n address addr = _addr == address(0) ? msg.sender : _addr;\n if (isERC165Interface(_interfaceHash)) {\n bytes4 erc165InterfaceHash = bytes4(_interfaceHash);\n return implementsERC165Interface(addr, erc165InterfaceHash) ? addr : address(0);\n }\n return interfaces[addr][_interfaceHash];\n }\n\n /// @notice Sets the contract which implements a specific interface for an address.\n /// Only the manager defined for that address can set it.\n /// (Each address is the manager for itself until it sets a new manager.)\n /// @param _addr Address for which to set the interface.\n /// (If '_addr' is the zero address then 'msg.sender' is assumed.)\n /// @param _interfaceHash Keccak256 hash of the name of the interface as a string.\n /// E.g., 'web3.utils.keccak256(\"ERC777TokensRecipient\")' for the 'ERC777TokensRecipient' interface.\n /// @param _implementer Contract address implementing '_interfaceHash' for '_addr'.\n function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external {\n address addr = _addr == address(0) ? msg.sender : _addr;\n require(getManager(addr) == msg.sender, \"Not the manager\");\n\n require(!isERC165Interface(_interfaceHash), \"Must not be an ERC165 hash\");\n if (_implementer != address(0) && _implementer != msg.sender) {\n require(\n ERC1820ImplementerInterface(_implementer)\n .canImplementInterfaceForAddress(_interfaceHash, addr) == ERC1820_ACCEPT_MAGIC,\n \"Does not implement the interface\"\n );\n }\n interfaces[addr][_interfaceHash] = _implementer;\n emit InterfaceImplementerSet(addr, _interfaceHash, _implementer);\n }\n\n /// @notice Sets '_newManager' as manager for '_addr'.\n /// The new manager will be able to call 'setInterfaceImplementer' for '_addr'.\n /// @param _addr Address for which to set the new manager.\n /// @param _newManager Address of the new manager for 'addr'. (Pass '0x0' to reset the manager to '_addr'.)\n function setManager(address _addr, address _newManager) external {\n require(getManager(_addr) == msg.sender, \"Not the manager\");\n managers[_addr] = _newManager == _addr ? address(0) : _newManager;\n emit ManagerChanged(_addr, _newManager);\n }\n\n /// @notice Get the manager of an address.\n /// @param _addr Address for which to return the manager.\n /// @return Address of the manager for a given address.\n function getManager(address _addr) public view returns(address) {\n // By default the manager of an address is the same address\n if (managers[_addr] == address(0)) {\n return _addr;\n } else {\n return managers[_addr];\n }\n }\n\n /// @notice Compute the keccak256 hash of an interface given its name.\n /// @param _interfaceName Name of the interface.\n /// @return The keccak256 hash of an interface name.\n function interfaceHash(string calldata _interfaceName) external pure returns(bytes32) {\n return keccak256(abi.encodePacked(_interfaceName));\n }\n\n /* --- ERC165 Related Functions --- */\n /* --- Developed in collaboration with William Entriken. --- */\n\n /// @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n /// @param _contract Address of the contract for which to update the cache.\n /// @param _interfaceId ERC165 interface for which to update the cache.\n function updateERC165Cache(address _contract, bytes4 _interfaceId) external {\n interfaces[_contract][_interfaceId] = implementsERC165InterfaceNoCache(\n _contract, _interfaceId) ? _contract : address(0);\n erc165Cached[_contract][_interfaceId] = true;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not.\n // If the result is not cached a direct lookup on the contract address is performed.\n // If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n // 'updateERC165Cache' with the contract address.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return True if '_contract' implements '_interfaceId', false otherwise.\n function implementsERC165Interface(address _contract, bytes4 _interfaceId) public view returns (bool) {\n if (!erc165Cached[_contract][_interfaceId]) {\n return implementsERC165InterfaceNoCache(_contract, _interfaceId);\n }\n return interfaces[_contract][_interfaceId] == _contract;\n }\n\n /// @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n /// @param _contract Address of the contract to check.\n /// @param _interfaceId ERC165 interface to check.\n /// @return True if '_contract' implements '_interfaceId', false otherwise.\n function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) public view returns (bool) {\n uint256 success;\n uint256 result;\n\n (success, result) = noThrowCall(_contract, ERC165ID);\n if (success == 0 || result == 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, INVALID_ID);\n if (success == 0 || result != 0) {\n return false;\n }\n\n (success, result) = noThrowCall(_contract, _interfaceId);\n if (success == 1 && result == 1) {\n return true;\n }\n return false;\n }\n\n /// @notice Checks whether the hash is a ERC165 interface (ending with 28 zeroes) or not.\n /// @param _interfaceHash The hash to check.\n /// @return True if '_interfaceHash' is an ERC165 interface (ending with 28 zeroes), false otherwise.\n function isERC165Interface(bytes32 _interfaceHash) internal pure returns (bool) {\n return _interfaceHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;\n }\n\n /// @dev Make a call on a contract without throwing if the function does not exist.\n function noThrowCall(address _contract, bytes4 _interfaceId)\n internal view returns (uint256 success, uint256 result)\n {\n bytes4 erc165ID = ERC165ID;\n\n assembly {\n let x := mload(0x40) // Find empty storage location using \"free memory pointer\"\n mstore(x, erc165ID) // Place signature at beginning of empty storage\n mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature\n\n success := staticcall(\n 30000, // 30k gas\n _contract, // To addr\n x, // Inputs are stored at location x\n 0x24, // Inputs are 36 (4 + 32) bytes long\n x, // Store output over input (saves space)\n 0x20 // Outputs are 32 bytes long\n )\n\n result := mload(x) // Load the result\n }\n }\n}\n", + "keccak256": "0x64025ecebddb6e126a5075c1fd6c01de2840492668e2909cef7157040a9d1945" } }, "version": 1 From d702fe883538a8e769ce03df510ebf07c67c63f3 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 4 Apr 2019 18:04:05 +0200 Subject: [PATCH 141/431] EIP-1884: Repricing for trie-size-dependent opcodes (#1884) --- EIPS/eip-1884.md | 135 ++++++++++++++++++++++++++ assets/eip-1884/BALANCE-run3.png | Bin 0 -> 78985 bytes assets/eip-1884/SLOAD-run3.png | Bin 0 -> 120062 bytes assets/eip-1884/geth_processing.png | Bin 0 -> 220235 bytes assets/eip-1884/run3.total-bars-5.png | Bin 0 -> 54820 bytes assets/eip-1884/run3.total-bars-6.png | Bin 0 -> 53843 bytes 6 files changed, 135 insertions(+) create mode 100644 EIPS/eip-1884.md create mode 100644 assets/eip-1884/BALANCE-run3.png create mode 100644 assets/eip-1884/SLOAD-run3.png create mode 100644 assets/eip-1884/geth_processing.png create mode 100644 assets/eip-1884/run3.total-bars-5.png create mode 100644 assets/eip-1884/run3.total-bars-6.png diff --git a/EIPS/eip-1884.md b/EIPS/eip-1884.md new file mode 100644 index 00000000..1a1f64da --- /dev/null +++ b/EIPS/eip-1884.md @@ -0,0 +1,135 @@ +--- +eip: 1884 +title: Repricing for trie-size-dependent opcodes +author: Martin Holst Swende (@holiman) +type: Standards Track +category: Core +discussions-to: https://ethereum-magicians.org/t/opcode-repricing/3024 +status: Draft +created: 2019-03-28 +--- + + +## Simple Summary + +This EIP proposes repricing certain opcodes, to obtain a good balance between gas expenditure and resource consumption. + +## Abstract + +The growth of the Ethereum state has caused certain opcodes to be more resource-intensive at this point than +they were previously. This EIP proposes to raise the `gasCost` for those opcodes. + +## Motivation + +An imbalance between the price of an operation and the resource consumption (CPU time, memory etc) +has several drawbacks: + +- It could be used for attacks, by filling blocks with underpriced operations which causes excessive block processing time. +- Underpriced opcodes cause a skewed block gas limit, where sometimes blocks finish quickly but other blocks with similar gas use finish slowly. + +If operations are well-balanced, we can maximise the block gaslimit and have a more stable processing time. + +## Specification + +At block `N`, + +- The `SLOAD` operation changes from `200` to `800` gas, +- The `BALANCE` operation changes from `400` to `700` gas, +- A new opcode, `SELFBALANCE` is introduced at `0x46`. + - `SELFBALANCE` pops `0` arguments off the stack, + - `SELFBALANCE` pushes the `balance` of the current address to the stack, + - `SELFBALANCE` is priced as `GasFastStep`, at `5` gas. + +## Rationale + +Here are two charts, taken from a full sync using Geth. The execution time was measured for every opcode, and aggregated for 10K blocks. These bar charts show the top 25 'heavy' opcodes in the ranges 5M to 6M and 6M to 7M: + +![bars1](../assets/eip-1884/run3.total-bars-5.png) +![bars2](../assets/eip-1884/run3.total-bars-6.png) + +Note: It can also be seen that the `SLOAD` moves towards the top position. The `GASPRICE` opcode has position one which I believe can be optimized away within the client -- which is not the case with `SLOAD`/`BALANCE`. + +Here is another chart, showing a full sync with Geth. It represents the blocks `0` to `5.7M`, and highlights what the block processing time is spent on. + +![geth](../assets/eip-1884/geth_processing.png) + +It can be seen that `storage_reads` and `account_reads` are the two most significant factors contributing to the block processing time. + +### `SLOAD` + +`SLOAD` was repriced at [EIP-150][eip-150], from `50` to `200`. +The following graph shows a go-ethereum full sync, where each data point represents + 10K blocks. During those 10K blocks, the execution time for the opcode was aggregated. + +![graph](../assets/eip-1884/SLOAD-run3.png) + +It can be seen that the repricing at [EIP-150][eip-150] caused a steep drop, from around `67` to `23`. +Around block `5M`, it started reaching pre-[EIP-150][eip-150] levels, and at block `7M` +it was averaging on around `150` - more than double pre-eip-150 levels. + +Increasing the cost of `SLOAD` by `4` would bring it back down to around `40`. +It is to be expected that it will rise again in the future, and may need future repricing, unless +state clearing efforts are implemented before that happens. + +### `BALANCE` + +`BALANCE` (a.k.a `EXTBALANCE`) is an operation which fetches data from the state trie. It was repriced at [EIP-150][eip-150] from `20` to `400`. + +![graph](../assets/eip-1884/BALANCE-run3.png) + +It is comparable to `EXTCODESIZE` and `EXTCODEHASH`, which are priced at `700` already. + +It has a built-in high variance, since it is often used for checking the balance of `this`, +which is a inherently cheap operation, however, it can be used to lookup the balance of arbitrary account which often require trie (disk) access. + +In hindsight, it might have been a better choice to have two +opcodes: `EXTBALANCE(address)` and `SELFBALANCE`, and have two different prices. + +* This EIP proposes to extend the current opcode set. + * Unfortunately, the opcode span `0x3X` is already full, hence the suggestion to place `SELFBALANCE` in the `0x4X` range. + * As for why it is priced at `5` (`GasFastStep`) instead of `2` (`GasQuickStep`), like other similar operations: the EVM execution engine still needs a lookup into the (cached) trie, and `balance`, unlike `gasPrice` or `timeStamp`, is not constant during the execution, so it has a bit more inherent overhead. + + +## Backwards Compatibility + +The changes require a hardfork. The changes have the following consequences: + +- Certain calls will become more expensive. +- Default-functions which access the storage and may in some cases require more than`2300` gas (the minimum gas that is always available in calls). +- Contracts that assume a certain fixed gas cost for calls (or internal sections) may cease to function. + - However, these operations have already been repriced earlier, so there is a historical precedent that 'the gascost for these operations may change', which should have prevented such fixed-gas-cost assumptions from being implemented. + +I expect that certain patterns will be less used, for example the use of multiple modifiers which `SLOAD`s the same opcode will be merged into one. It may also lead to less `log` operations containing `SLOAD`ed values that are not strictly necessary. + +## Test Cases + +No test cases are implemented as of yet. + +## Implementation + +This EIP has not yet been implemented in any client. +Both these opcodes have been repriced before, and the client internals for managing reprices are already in place. + +### `SELFBALANCE` + +This is the implementation for the new opcode in go-ethereum: + +```golang + +func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address()) + return nil, nil +} + +``` + +## Security considerations + +- See backwards compatibility section. +- There are no special edgecases regarding `SELFBALANCE`, if we define it as `BALANCE` with `address` instead of popping an address from the stack -- since `BALANCE` is already well-defined. +- It should be investigated if Solidity contains any hardcoded expectations on the gas cost of these operations. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +[eip-150]: https://eips.ethereum.org/EIPS/eip-150 diff --git a/assets/eip-1884/BALANCE-run3.png b/assets/eip-1884/BALANCE-run3.png new file mode 100644 index 0000000000000000000000000000000000000000..324647ab75f58b1d77f910ec8bb8c9ee85f69c1c GIT binary patch literal 78985 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

    a*+$|8R<^PGFQnEKQ7}3 z&01qw*)YYU79-oRQ)h-1V=FCR@KAO!5VT}rv|qk%$LXm(Y)h@%M=N`x?DVUAAtGCo z{1kHhm$=-HmXpkIna#)I)t7;Q(=nAv;xN?M&YHk;vqxs=$>kN~Pu}5QaYlpdU%&N! z&Qq>vD(7|6NIC}czxDp{n8=dj$c!G`NaTV5Ce8)rQNFg7Jip~Y%C!l@(1M(o>#Bbo zxi3n!bzMg5AUoG{;wO%%+!ZH;2Zpa*P1GmKJ#&`wsi4=d7HP zVEX&HJcNkq%^I8(;u{pO7s*(uSx+2wjiz4bf!=wm#SI^-W&79To@VEXWytiu^GlbF zpo$0+w2AUVW${N*OTI-8WIVb188aot^zFH3W8;Nwv?J*De$Y;;yz+idUj7k=4nS9estb_os z47ChLfG473QKh53g-Xr>%ou_$l$^g`G1#0`<%qENl$oPS%M0v@;^G5%kh>X z)R&#pf9Qk=#~sndj@_^DLr$1p)DeyFhIkrQR}}6Ki~QwiYsrP>kT81aE<^30B_WJw zX1Jonw8u%Eo8r&@a`tD+(EPKcBps>9DZ76y6nxmP%C`Udbz6V#QQyTS(_gkFrf z2VCQxnbNt~p2WFH8KTDSZ0CJCi`Kd(v8(kque)7*#Yjlx^5Ykktp``E zj;~l;7+L(%&KOMwf2d9e!VA1oExO! zM-ox-%9}Lw7<4nxV!!YGjm`5jCq(-pN<~D=@_cwl%LcVkWx+0}($v4R!Da&G0`iT2 z{`!?Vl>*TxmN(G;RYg-M^w#cx42qe70e%-GuDpN!XI%U(JyFb|FB$=_>!1LX0lyK7 z`z;PKOg$uYadCkOO7zlY7BYn@0{U7ZuV34WC((lmhV_k%WHkEreG*7EfK8{RJOp;? z()me{h+>b4R#c=$%QL z;Li+}d1$vaq^{d#WnZ7kx^=4#cLT&zm9_P;sKH1N9BhkcvJBBlo8{TZY})V=#JbJM z3GCsap9k_BW+}8Ac(C zy)0V&_-I%Fph>xP5IZFW>-uQj&HYKpBY`vd$mToX!qIG^XDH8O$aUz1Gi2kP{qR8X z14}vchSjztj)*##{B@YVOn6_RSKX!yR{xw5)*oZ&8V*vPhw;^$28&feo1i+`WDfR` zjpzJPikMlVy}nchQl&E>N3ED7=P!WBpC zGa4;R*!;r9_C0>`#Bc1)8U{@OB>LRQ^3Ha(Yktls60rW|;=)uZ^Z*{ccTU_8QdhJ7 zk_h~$tAOsRHt7(+@dGg$g00CUTCnxgMmRg0!6(4=gu-J!{!(k*moH)~t4e(4@SseM zjAj~6n034TZ9)MKayU>c%b`=PBGL)xH6RXDi{fxC2n!2u*r1bke0=~qQgkpXD1p%p zLjmwODXG2Kt8sQ@GhrE?ve&C+87~eLnroB*fjhN*w8kDjSd@bZDd|Tp=VFZp3mG8| z4*-&Mr~dr$8ZPKd)VGG!Yw{9KS`(?p%F4=qYY0YkZ(6`*QChkP^O%w3abI6GttI{= z;v9B9#3A>=uwi#Oc|CciWN`GTc|qQ5`xncImN{X#|L9yFsCwc1mEgBj3dv}l!+8u5 z&SKo+jL@}*u;+wuLV>$d=LnK3p_RmC1UvimuG#siP9*+6eDnyltQ=J6fPLD~tf8uw zz4)7SC_tnc%DYW#E`bLF0<^Vt@5@<3U5reoadgCBVkS&?pFW-N~T#dShm!>J{{kVe#)%cT&iY=j|$e)GZ!qb2sQ%;K>bqbohpTIx2r9~3GU z&{jdt9;e*k;7WW|E-k1*S6=;&o(=ztUx3Cx+Rzu;MeNG+O_`d~4klaF)gev&P^D3<(k5__9Ibwc zPk?u#Gf~y*zq&EDOlW1uo0TjKEFw~o{M_7$bKTZQXOMY;C4TnK{$u+35A`Hm)WQF> zKwqC_h|uz+*7V~k;9L`@WWn{id`|Xx2(&^i4tYdDoUAM?j;^kO1ktn>E!TZM;-PyQ z9YZvQp7>aMlAik0RWI4oCGjy!la1;HD$auP%UPzC`7+mN#f`82=P z&5h#XAjQ^1p7k9qXNGWRNO-0Mc+HzLPA3%}Ap5zuXh&&LS? zwBkQXx4C7sAES*j&-{pX__?}XP{kv>$^wWZ^Wp^vX0df}5J77%y3ZN?n4;Lz^mNPY z=9Y&J5D~-4FckbGZJFDJ3vi5)u~*%}*ErtRCQN#?r7IX=p2PJmD_-=~s~tg9rv1DV zDm8r^2Igs>&kyxD1aGj$k`nP^8rvFmNTGOdh_Vp)^ zj3%^GdxU)Cpp}4qvga<~98+kfVQ7H}1=w;EB6K}G@?qV?A(N;-P&87~THeg2eh}V= zjwjds8nS?ix{kI2H^kC+_q=Huq;uqUH^0ra<{2QUP^cileXUfh4hw)ed_+%}e1Hlp zU@-tR-+1so%p=rkT>(FjAGz+cuUfp6jtVZFUnOb_B z8|>0Q5z#a<9R(BuqAzA9Ci~{+I?BVdpZym8VAGQV1G|W+4zCdy7`$wLk=osw=4|DojHdVGaoGz)9h;wH8oM8_&J4#gA4k#Fqel%*>^_=s-{udj!u7kUV5ePgUT*l=F5m z#vf!At?Fa-kH|c|Lw2v&rJ{>lP)#3CHzCjF!)h~$hX;oepo4*1bm-==M_fCs9=KLs zMjgha3{$V5hfnc0&xcle{5QzLdJmNVWRL>;&}O+48R?!`@+2K{s4XvD=H9NAwRi_# zGnp;0xX`(1oOLF!mSZJW?fXxkZd|+eD&+#X761(>9tNlxT4kZ;F-rLDg<1v(7B4dK zwMAju#z##b4i4TP2-MthC8Fb_ii*5|hLfo&dckabmsk0su7m3@C@%fw%eFUfbfk&0 zC)FQ5tlxK2n8jOWA)1pl5EKHediZV70|2DLQX7s?;31Ay9V^_V;WG93s4O3ZArn+X z@QqaQ>>YI9vQE$VDeX)80-^PlH$4g+9^d-n{N9E_`U=s|XCQD2sAEu~K|(H|=G|0P zHSlJQnF}`k1-d4*;?OQQ9xyU${y*Ri6M&jT15{L0K&)_JHTF6K3&%^gA0Z2QHhx?K z+&ny(An>Q{!e>7F0}X>&P^+O}gy01eU>2~DVE1b2XTHh_)kQ>=h38-zoFxE^hM-{p zXz~lfP5g5bs(Qc`RtY1F;fr&%pwKwArg#0GoWv20YD1C-4rmieo^NiKh2h<~fVdg8 zxK22Wkr(>epLq=AA8H$KHFareX<6BopACSkK*O*>O)a*Z$`ber6#&GFniAZ&j=S62 zU;Jl$%jM-~;>F+*uFO;QB;I_~(tITchk;p`1goZ}6cNAuhbfV>=J2{5nbh@Ng6`0n zn4G+K|NgV{-U~B*z->CcMvCF~0V1Oz%n4{l$~gC9TEz%^#9kNhP?4sdn_%gvwuCgq z>g?I`;F5rp;LA5ijju$vhBpNRTHhbkbYYQ+Be!c+nQ_$sj)GPuB;*4MjE{a3lc9kZ z>>%tyB;n6E-`QkT*Gc;1EB*Z00m{X~FtdEeZjg&53$ueLa#ld)gvQ9@jo^QSi%Itd zaJFD90o3!(&d;Hr0nrAP$z?JWbzo@72ib{&VR?4VvM+C~F*UzkPQ|kX@%Zt+ye(ju z{9@3u2oFxs!!ZF5T;-cLXRWOKa6{s9X&Bz2KrN%8QbHw&%p_m5e0atE(<2m#l#uWcbczFCA@djHzhu&&W3+9j0SSu|ulh zs}9Wlff^3Mw((o**Co`pwWa16oP(nuY4{x%`ve5TtUT3Sp9s7_g|F_|RR%#&v|?z@ z2N{WjWn>&XoHj~OH=UceuavlEV{iZUl--`l?%+nJBK>3w8(y^#{p9*#k>KtJalX@iyDRUG@0mOkrzbsm<$LQ~-wKw#3;n}Kf*&8!8Eky?HNW@*lEB(b5^pJ> z$=}@`@ysXh@1%$NWc7-$Xy?DVLL)+wcY{1HJYO?rG;&Ndz(9!6xHOtQF*5Xut`Muz z<={tsI4i&rL2l`KdOYkzi?zde*cO*+n?6Uy-D`fr0`B?9?}1`{^%HuU+xZie=QCbL zmeoX=mIguGir{`DXQj-Iw(c=OsksDUAt*xcxuHCp9Hp&W&%+gg`a`rj#`))|E6|yh z{{8&{kiO4AQe^)y8*yWA@|QG9e33$otO7v`q!Gl|1OpL4w6m)atpaip*R@o9rf`SOnI&1EpV~GCghmmu8laf+bajod0~VRpH#SwhCrRYa0o@ zQy!9z>-H!8#t%Z13F#m*h#~!|ho_i~jv*6Lhtq4Xg32IAS#*}Fx2sahG*$OgL`k7Q zSH9eqnW#v**ZxU<8deh5^ivunc@9YOKr-h9FBiw6$9LxnIp^S4g$Uei)L*0!JPGYA z*L7qJa^oVJ0{LiWemQ3_^QHKT(Y^5BJn!#Sgy-qG-O^gtk24Ijmc}yBui!xc(2JvA z9)c~Td;$)3aSuK88Zf`WO8_TpkFex~bC(34Wj3QOHT~PHVnj)>Dk>;ZB73-Ma|3tS zS&n7%yC>7gybH*o`-hhiH=gQ*Hl4 z*A2qR11}a5M9_Uy^-W=Ygjw?AS;uusA@ora5F^4{T;%o_XUiVL*RZ4emLwyz-8 z0R<9Vv}4{*{P?km#X!jLbyPQw&j~xP?)@lYH(#EZ)Rstu@Em`>iMW%Hg+M11GiEnnwW_wQHxDVDQXfLa!Eh`p|m;qU`dEXkxsDTUdNmK|V0Pw1y3YhJ&X5?SeUC z)DR$&Qi7gD$=q-e_=W5I3W(qakBI-TGWL4a&Ye5S*TwJ)&mi=+O=A1|68Fc1CR{OP zazG_Fx#~+$&T;scpR=|`Zc7W#Rc%ZM*oln6lXE)Tdn%9yJzO->Kg>k1?^kDh_txR8 zCVo)n+MB<$xJD~zz^2LCwAqhMH1ZZz3$~3Ev-BwK^_9dNqK%wEIQLXpiv0t&8o{p%A zrO-3IL}AX70Ds=A)b<~q(mZjWpA>Nric(33h%(Xe_ixwJq?rHFC+QBV5sw8qlqvM9 zBE-<9Rl)Xw*w^?bbuV}?2oa(FUznHN)rpAW#k5=uFamJ=ym%Lc7F?(^+N(v zKyooC<~C{+Htb~8?rKn?rLdm;pH9@=By#tR(*xE%-2pc>SPwHULzerZa9~> zsXl~6z{$PWDzsZfsmf8>j4lvhgN#RMpPRcuM#d4BDhjA4Ic9R^VC?JKnTd6g3%jX1 z)I^q%f~FMfgA`e7?#_q1?JjG|@QTeyIM=A~JfmsygO&AY&Da?0@v5~oTC8dWU?$KO zNLrs1*}90T0k^=-wzTo;D+t=m)aS_vI))VN+SG3&qSU%!|9&1lN=+8T!jNyg9G#Ez zTPQ$d0Us+$o4R&srK}t4c0N3w0$s{}_rrvv_GBboeIQZxVR?Iz)g1tVo?HjT!;;NC zO*GCjM;@folRFM`;Eat!I5AMJJ=^Lq;4czh72#w#o?&`$=_#MzL6<$x@HL&00JiP6 zn?ukr37B$lK;Dr&{}1AsEAWcIwqYm&EQfq*-iqW25c1{>i7nuTKPlQsD2f(b^M1h< zwR5nu_K_`xwqyBI2eS|E;5UrJx!;_*uN2?7HC}X6fP(w;i31YxR}CdQGEeV#)b zG(H!EJmt0-#kNS)@#x(<8z^VdXv|4#GZ{;BBQT(ag(jMrJksSN%7XGoNmmo;0#Dyv2 zhxNnKqcoQ2QaifBWP@j@lTjIr;v-aUMQ3yM#tppDg-Z1WP4|&=yGTq4RfuOAydoF^ zvt4BtJ_|^wai0VYK@tU#u;-9X&MdsX@J0kZ0Z~-|Ytv~j$nw#go}NQ#4~nyPjD#W~ zMY&y`qmiHodvaB#7g2L4U3BO%6HP4QWT@hUbQK;zI~rDdZ_4`c>EUe-Mji}4-IIR= z|6T#er~UW?f$JiG7@%=F_={iXh}b>|7S1o%?BhI4Fx3iQ54WZ~QJA0Wj) z|H3XUv$?d$z8KpdC6bZkSD=iTl!Xy&S2=-OAv~=B-e>=ED5E@aUL#AKQwu03jKE+B zo=9w#lXC%T7sM4}u=(KLy^0rpT!&0zY>W)CKwi>9J(8>bH(>Fapx>=ap*DKqx|h3k z2eq8&9mPK*|GM5JEJqxaVK^?R9p1gf(a`Ht0cjKSBy1OC1-B-MO z$hR2Xmj_!_ZJRH+#Ciz!ppXDm3hJlSz8$&G88^J%S!SDgkG+vDnZ67Xb@y%v)5-e_ z;WCW}q>C*E6e?mlL3O-)|Gp5u9)vFJy9t-o`hBvhs`CJ0g;_ATWp$_C;&|O*GVc-> z)`JHR$R-?j7QBQk3CLl`oFi{6xY{mEZbPVMsvqq9gPAoR*WrDdyvA#Yy!=b;b>#R8t2{LJWLv8Lpl z^x*pUfn6T!ZE?O6Yqk`@7E_%WCv)B_;h9oN=aS+BnC_r8xN_wR0RQ82MUbJvbPd51 zB9LCbRB1<7JSxbF*p~bw;bv;+e^J3Zen%+iel);V~z~(P1db z^Tf4!8DLcGOzU8`LUWx06Dgh$$a*R>&LC%biRMFX-#>k+nAaA4eoz|FSRtSBS^(47 zFV9+~R$l#@VMeyXsM*Z&R59rWnii6RLAeAT&u07Np&Q;EJAagB=kb?=tfE>k{n>clr>FjOl(M}+N&}iq zR)k}Ee#j{LH<~kSw-nfSssX1bBJLu{7;dv$&XGuGzTn zH%XL^hF;uivQHHx4Xjaqf2tLbh)K><`!~FC+m$65TL9-FRy_6!&C7em*8ZE0El%&> zbZmcXZ4_)duWEaI*)!D)qX!m>t568%7bKXZoNy}IpY$vvV-0IykhGD)!-h~7P3hw% zDOX0j)xuN!(vE)NCHi?NwmdH$r>qz6KSXr(GHwS$bK{;dec5Tzq1{wBM~*jYcww%N zjY5O3^2ZPx1BD-iBn7prSQ+3`2DQ{PJZ$g6Hqh4>{4e>Jvd?NDQiY3T*M@yIp?`B- z=)!pOf5tS!K1KRK9Sb=V&~+TdQh!Un>FgjU3i}w3SQG&`Ri$72 z{-iJca-5DD8*;93`L^jvf68!mvFA*v&!A*>1E*ym>~^4v)K3m9g0Mj6@$`r^FkG>dp*xVIH_2O_Dw;*07|3-3aSDhSVQJVw09`Q%2T(aK z+m_Nha29>r+BwQj4?wUi_vt>DQ;Ao`yN_Qr{?uvrIBVnmV!MR}_Us7<>EsuKWWBui z=tD#`43#VVR!(E`MJfHG(AslCCNmx<9G4cfP~a3Hmr%&L^U%Yv6l(@7IxJ`KSScwh z!>GU2^yM_JKyIDxtcStDdyra>BR${59=5i>VyGGwZHNToQPq2x-g2{59OcC=_6io$XU!yy`yDMeBq_`zj!Y^_C z`gKVE)Z$IWD$g!@$C=aw_)8-@rAdnXkR58N9bQ=(7V8w6SsCmV4mbg$voH zJtr!M_9xv;K0VF7KS|$xqt#1###*;3;zHaf&U8w@+_x1?IsR`}RKB;^b7rPTTz33h z=bOb&;X==qqvazrTj;&p1Q*I3R4*LX(O>M$7IblaylU{P$l=eyi$nK8u8zOoa_+0- z@+nrdSr%ru&PML|Zt8H`N4VeRQe6J6iBEQKdnEFlik?Yl@bTXDST5o+->z}k%5d$w zGoBvWiN{kWg8YV7bbNQ-8CJP{{-ehU38XX%d*`)8@NJ?SrepFy?eY(b*qAFMb;3b8MTPgcpoesk%Mu05-s zN2(xRps|PnO3Oo<;aQ00*>d7uQ zVsmB_ELc1K4sE#Qy2W4U37TXLWk*)MLB*0=7Q#2Z4Ysw-YP5Ff3e;ehiZ3c~G+yO^qbLM>-;ZLRHSFE(eIv)1CXwi6ixlXD;2jBkOZNHO2_k6E1$Mg&`fP z>@@eR%hi@Uo2*ATij*UmXe{;&Z&)QHy4%|f-Y1l?5sr!*+_~5P6=Wpj09yf6Oj|{8 zzVg~Kg=>h|r>$v_d#aqYwh^|Tx8FPHLpY!vJtv;)%fVQ)5q;a%tss(?OK-dY*9Lfq zn_?F+5-&gxW10mV4@161tJsttQMzDYHl*&a+N3aOT+e-Ga=Kcqot3IQJ^9o3AC+p0 z)z^bQG3Wg^wa2Bk>QLjbwMW$q3PW4`kmn6#Ok?DP$=p*qUXj;lx4oQ`Sv7r_=1+!oSf7LXqc)|H*^;6ra|= zy|&M3=U50A1xlvBPHGV!k=gvNnQvcG`^f`v2zsfmt6Rl(G?L=;!t&hV367>TP(q@l zm9w?=#e0e-myDz2o1EVpy~o{eFCXivdCnQGAF8OUypJNfFY)*zx5i`FlrjF5{m9P_Qp51+8r9{Ls$(R2-|LWJ|6`GwN#?}(v~Q&ox0@DZjStgLR`FZ#290HC*aQiU zDzcCvS;iR-NpcY2@nv*Gm*F+r?_6p@+ldGKezlpaX(l=YPl)DUjgd(}qAAE465gb( zda}Ci#aWH2uWO0lBRv#b_mxeXu05=`kw*s*@&<-ol!+BZ{#l0XrS4;SKJqyVXo8M%b9N%42`Uey01<$#T71 zui1`ai4?beRi*OdE79aKz@5nlGapP~ID{d<1#!Ges~`LL+V$&+Bqqs6bZK0(<>q2K zK%5paeZcSfe$v-=!z6B7eEmwPLOS9_Wm`&Iw`_cF$xYdK^bfGeB}iOL*t8BI`diyo z9|}Q)&8%;-MZtuQ1#9K+$;P^~#BZK!m7e2^!XefbdC!;d&VyosA6sfp+?vYRO83}q zUXV4D!p0;PstQFe`E^=;QBp(h2GV|6ua|*R7Sclhau3BD8;!F)bq(W+xyfMQ&_dd{aH}PUeEQx~G=?t9G zd8)9-y(|rj?`ZQkuS)|-M6-*0v<@9{_^`nVt9v9)DDWqQ*7~Apd;>SZ4|Sm94RKQ^lUun&0y$`K3yQmwfL?JNaE(x61Ttm!6OCZfN za}OLgD<&zK4H?n^V+xGARKghn#>C%x|5@e{3-1?SqJJ|^jz<#d*6z!MB@-+2==7e2 zLo%v5^Y=%l0YQ+r1sf+D6Ux)mLaVI*1hO#cN6cnZP&kvzUn^wooyF!V*~Nqo)#8;; z_0#e=Xe%~mo)lwbAyGVD|KQ(08i??x@&xti-tB_;RX7~3nJpMhtG{)&bRS=hx?liW z+3%ab#50v0Ur#J&TEenrc3TM%t2lO~;-epsAa*d}iy@4?OrUr1Z}A$#&r%GDMvU(w zuF=RCF6#B+q%dLK`^!@&pz8I!M683)Ja8NMvDY-m_38Lflh7B9guY3Q>svK_tEOJpLwzRa=ltc%i&O(+2 zv-ED!2-0v5KG!q4coX+E9H2;)+!5VgUO_e-t+gvPnuIyrs_Bm{zuKg_dX4QQrDhqS zJJ<3kn9+)`@60W`2)b%7)WUqpe*tpmk2$P&sSHKTaAD!e5dyUpdh>OQkd=7@*(GI~ zDeafeF`K{pN00f)+<+=NKXoeYcwb*1;voM5wm}2wg99$76qnc`h%G;V#sHm3QUHk| z+6XRsza^tTro5u!8q-A!Xoe zUEL}XB)#6gdDD4*)|JVhYxU|0eDmOd0O0^~$TocTadC%_7@(j9tO{F1%2c9$vYd!W zH>zE9B9)a^RW~<4tI8sB?csl;Mod8;?Y6q{z151L@B7Qe!_CaTI!tU$FjeJ-ev;uM z$PLS-1@Yz$k0J*Vzozypk*WKsx6y!YyWl*VJR!GD$sXxaO$b2lh=43}7O>v2&Bu@m zfiHk71Ot8*fY6;V^Jy4;0d)b)RcEr$>@N!w*}0Bgs~-&>?$Hw0LHM-R;z_~=1WS+S z&z#B4vw2Ep0Ikth;wfV~e6bk_efg!-2S?O1=*d_T{sY7Y4TdE9g4?2Sc^pHkp=^JmSb(c>ej6XMI(OUNrQ0(5eJ{pYWvDCAgvf{azcU|f4be9 z56VW!L0^N6hX#qBjt&8*IOVmTB1;DT3mAajRaaw<;F*&rTd=g#Mt9If?-p?xvhUlZ zaX*lzs9L}oZqn7}9(~)Lp!ZZ+4IRRAEtW8jj8jE- zV`314gU{Xuw%>2E*$OVTMrA8FWv~=5`5J)@c%;$M(Z>4vm;G`s^c}(^1~fhhi$?1k zqvlg+WoAE;AVlcKsi|(?egX63Jcl6hL|~K&kZlt5QUxt(BDF^3wPiNFD=;QK?g@mF ztq*|SLHmfoQj~NjdJqH%FNqw1X=Gqn$c-DA!c>D5g&AQalm8NdgjmNF6&01_MgN+m z?Z&rvfXpCz!Z3s{|HgiDBv?-u6d6`X>Ecw(Tgva@s1Y;m>`#Ru}~ z#@UgDgiN9P7<8VIAuVW?Z7Auzc}a;Fpf2{;?EL0Mn4O>(P1R2Zl8=G(s9T)oGEY|^ z(gr%G*Jqp%MPy%eGOfgA;ATfQ;xPJ2XC}17-fEo(vwbgWXwZO${Y_Jh?>Tv~(wJr) z=#k~+EFxU+>>z9Skmd86V)`i&ma{oUCrLyITq`Fc zpD%b|5(jYjDRU^Z>KG!K85Cc+qa!w5@Lp>cedNUF!oC5 zgOJhI&hBrQKL-O{IXJbcq1MPdcaoyrC&2j}5L@XzCnRF9gy`ku2-w@(BYh-aKqN7( z523#Q$PWeW-JP7uhro$VQ?Xauzd3mwJQ!-<2^7*P>C)tbmW|KS)4!$(z@{8_`WUO$ zIrPmfap;_Z>*;zM(@sew%Wqm_mS%9t%rBo+osIV8%B=nbtbT9s7_=)(62j|+xk-13W`Z12sAkKA?^w|ITZo};weK>#Fo z`khZE%>=>zO?F~;PX4gNU}_3SZ}jcN?XBb7!tF7%O-;+1c0jR*o5ULjlt;muM{LZN zXgv#6#2JEgV<@8&6F#^N9qZ+h(tKGMTMB-`F$avAamCXEB4HZ_T3PBJL#o_2rii@( zgF#~|NEH=eZ`2m8rBUbsBfl7$?iP)>BFysgfyAvU?z|st@Uy85JZe?IdxFcLy;3yb z#bI}NKibmulQC@|P%EK3r7rZG>-tkQ%G{0bl{@GSZE0Jw3j)1`H_rX`JhMr!;9Ac> z>Q0-YKaD(W#0w*h`}dSELxG!kq4#Os(Tw6kd1CX*U9kR?!$Y z+rFFA6=nZI$xJ#!mj!BFdkEt2(g_CebI`qTgNneZ-d#aT1ih9Nf)FXJjj-cpqH2|{-MhV->akrjo=nUJKL7{S-_3GyD}WEOwxcU>uMl}k%-Vf;GmyGyY%_}dr_92g1*>_ z(n60hOeX4$b|^_Mir$3@y#HCbN9r|yq;$e{{XcN1CjVc+b;vHTva3slduu_7E->NdxT(9+e;SfdEoKJ6SYjJ?m zGo({tyQHzd!6$(W8mclJzo_HNEwk5)ijHRbBANgSAK0;hDM8+IX#f6`NbUkZC2{SQ zxellpNOAN6nu(bUrtWT7EU;A~pc68y)0m=%A!cfpWi$#5Atq7^m}Us+ zKfpjo|JU@)=AH{2JUwp;YL9LwJYfqASf4}!H(QcsyORz-mPsL@-~x4!HhrPDX+{3SX1qtGT!tvz2o8S4z6gO?09BubsK7D##*~r~P z`}ffNAEtmmJAIA)I_Gar{kSzDd3kK#i>bZp7(Pk6VdSc9p(t}SrNOhJbdt%zxnN!J ziuey7(_Q3j$2-f%hH@?_u6xATj=`|d@~sLkoN*Y{b(wJL#x-=ZO)MXe_hl?~ zCI>g)bpFAqztej63PQ&^m}qGxsC#h01}*(ync0z&Si_$TMBx?w29Em;{wht6)y2>m zZn7V^q`Qu^XPy~wpgBzR4Y4M3U!zfoue%j_M_h zuEMBFKqo-@b1MHX0E{STY_7idEPi#e{!05~?CKDW&8^o7NkKwm1?-Be1>awYy8eUb z%RO^XuFOxHHSSlOpAuvxa$(%8iN06D7?rN);KpG=Spur^!c<8C8$hsC0vT7Rhgdli z=ZPACDYTB%{No*gM7$Lb-IrDd4R?9l==HaZoI9mRJx_nxU_!S*S-xchp|YPM>)R`~ ziD9QE!OKV?`m6U3OYEM$cWN_tPt{CL`Wq!xPwkF}X2X``fzCnv9Ng-*gP_G6jkuyC zOD0X&t-2aVFD)qid5WZO0wt^Y?Jw$_75BWcIT&pkJ9Z&If0N{}ITqj~mB z>shN4aQH-SfQ77HICIgnj>5Bq^PNZObPQzI?b7AF_biIgo;1!FAA(n49cGRE>%U9i zN(l(`a7v9~6gzQ*tndjBKE0T=#I1Dl%WZz%ZXkrGUnaoILoUUmjg!RJ zpZBa_hG>0 z+M5@{yt5;)m|77ZlPUdwWq23qsoV@G+cu{k({?duDg!poySL4vHhDakO@Ypwi|tN} z=i#PfJf9aYiBgHw-O^b#Qs=JGif+@@7qW&wbKR%6>oGH-8vcucHblc~*AffdKO!Mo z^n&T>-JERNsC%pwe;OqdC6V~s#f^h*v}xe_ZA7tP2g*juDak$g&ePN6StjcEg4@VcNLez%*-zMa18 zn~3--d3mGh7sU8({9dK=auc6k$m`QmRV9x{TzO-`$@bdP&9pux=@uOWWP{WlJnhhG z{w^$F;KWU_@bGD~ma42)y6Dd1Qfb+2whTmzWPF*%hd4fh*)lZc+5|mOEgLVy7(F3z zQ_g84)hquaUClQt6Q0n0Ra#LA`BToerxCX|r+6PTj=e)iJf&wUV@*9uPi^0_x?@>W z+n#~P1aQP9r~A0p37ggJhbgR+7K=`uJ%aRHeBheWE7IchQridPI5Qu?vmlX zT@}fA$5K-An4#0ET_F|96!)2K0ka*|&&-6Wx(w@>{$}}iJbu0MUkK^(Xo^hRGG4#= zrZzU3ZctkrTeSad*1vrk%h1rVV!wMajKq0MLQyC<<2 z=7#yZjquk%*3s)+U`lp}n9Xx5tDyt|>%*O;4oz@I8l5_Iz6oyK7^t3KENThDHU@=U zkUQCAqN_c5GBy9<@=Srdx|H7*#@iV8o|R*~lJGo-rA(OMR8al9d#JCic=Ph5XJpAp z?7!1%MR;0nq{ciMe965(dhyTHp)#>_%DL^U+QC)f7TJ+6y;eIlg+O)G3$>cA@?;e;YgXD9>7PWY1rXlkG(nTO52JXAE|9KaN) zMIEfIp>+AIIt2iJ-NOHWk~t8c4THJ=t!hr|%EPA+0IK zPc_@yv>4Sa@2!wZh4oxPo&XD^u%K^KYEs0GWQI(-r2EdjT>1qY_B{WZ{zzU)pk-UT zyoL}HVS`+N^HzGs^u+Qhp8jp_ZBJd12!NssrJ6&@%-jDLuvhBhW-pO>J{p-SfZ$;~ zVb(ycym@~PHA6T=fyGGQ+3(s4n>0+Lb1<@PmzH+;lDH2cveRmqHQEgB8e}`zEEvLeG+0~k66)u=CSSaegFhEVDV_yJt@r|m$rn)Hfj~J`)l&(2K*c_f zo`p@V8`USs=c-Si*jZQr^dCuSU`c@e0sYfwgs32H9d;O0!64gn`uSPx4xsQ!4E*iK zspUJI%3S@EDezd(cjr41BPuV2O3rU%A>J<-$Sh+jscmv4FAM9B`*lx57^rW2eD)~K z^UOx-_PAZ{O!2Dw<7NUJ2vg0BiCp zItsJ>EYwveu3+303qw#PruWEW0LnRjfq$kZoM$^>WOS7ii{aHbs7L}2zv*>GM(t>D zz#{+Jwbz7XUHZuZa481QFyIhl>7d|jQ-dq)zw_lb76YbhzhDz5@sG~US~dz;D`aln z4oU7?a$oaM3$==OmY&>1$e7YonNx`N=?^O@L|AZ?u7za5Dxxy+@%0m__l@bh2420e zV-0VhCtRb2D{tp;?)_QYK07%aEzxj$d-Un!tl`zCe1|R>ecSyDuNhEzYvyTxaA36; z@RCq2kw1{+ zbt`e0bPXb^;k?6=`Sw4eUwU*7fOyl8ff=Pn#M!gb>` zO?7j@qbqSgPM5C=@^Er|U-SkUBw=ZOXT^BgqEocCLmVmdx;OZleOS8_j~jxfD)Qw_yT!VA1~RIyA%CX(qTlp?{@Bq^6}drde3A@oRHn^us zPskIh)PGNh>xx1XcuH^;-7cOe3S1@^p=}}q#`N`H445DY5tpItz0@$vejrDnM>(}T zV&Rfz54ObxgkBsoKU>`XI!5fp01S)|9Nn|U{?t~63^946d$+SIA~I`s_NN+;NTN?6 z7}6d$c*)Joq`6sFm|eElPT?P*n{)2Hai)n#KU?|?tFda$_0$usKAu}TPv^$b87xHV zcUAp(&ewjBaygJjoD0#BIeER8xOXS&20bxn%=pw81@(2)9d~Tr-`ll!_2xP+I(Z@p zfM=m!qZw&>S9I(m;yxeN)zxMp6FxC`4w_onf$t8VQKP#AdxM5(M1D~bzrZdWOx6xF76K@shvUB)|o7y(=Ju3GNHq9O7`&r#B!{-qg zYJUk&pr*D%KT7fsxcEHoc&IYPO_(P1Y1eJiDE<8=Vu5x;cMps_{x7+6?G>YjS@51- z;Mjj0<&F!Rk*Vno;5#nvOv2l?je&kZ0!ZXuF)$h)mo0J00%cPXlok;=jX{dAe7u_I zx^L{;L3c@5RW;_#8Q72E!e~3h`5N)-2!^lf`vd9(S#@h94QX*&FsK536c_(J^A|`X zI6jqj90sJY0}v9EzX&&L*t(t1PggJ{=s^emV`xZ#lQVwaxcTM93&<9AbKB8zx@_eL ze>8fNMZS5*|mo$qP$ye_8$~|9QslFgT+(%)|Ev^8rKpo z>WnOOn8(C>XxW(`)x^{AC(DmGS3cA!J6^Ibx&F41=8f*%)FB?q1(svMd7GmKeO=G2 zI=IO5B9`YNWe~Z8AQx*FF2EiNq%l7!HP!C_17hZ)Kqw;H(lm(F^5h3rS%5l;spy7z zV?AgiSVW-e2E|s<(8iJgZW8uY@r@hjrl(U8$cqT{d>=d|NcjMi^^AGopI0bf6bXPd zyn-r&P+`Q$Ap1ogVY+Rmn5toD_*72gM_vOM{zY{! zE4ohYocS^31Cw$GTVK3L3e?}<%z9ggNAtbZ^YvFmh2zzZ#EJeq%H+KoM03HS|O~&O08WLX1+o$9YX6stc_{l279J;yhe(olHrOq%RT?fly-N)4*cTPR{ zqbypIn6NujSgiWo>ZnVjNg`gx78)_4#EJ-t&gqTR*9EI&jQkk7c6cjsNpF&rgbq_3 zQhveJt2adKg+dr1>YqSmPW9KCqqKYQg;b)Fp&-B>5sH8`UXXjUacX0CuVvE9;Ht!Y z=EgCQ+E2!ScIHPHN{3WgIN!W@?dnw{3=}}g@=LA*=qWq_YV+fDyvr33b3u+9!x)Xr z!WPd98N%RHuaR4^`my7>xK}-%`Q4J~-$dQ{EN>PVSq^di{J=_O;ig;5GxVVpMeLTX znf;7HI_`Qr;oY7B{gh$T`Zjm5 zn@oyd%eaMGjxb&c+N|*@hSqyCDChY2I=ig)KT*o!Dqg|e#qIA%^0jS{YyIxO3v(k6 zW*URvGjUtKyvM=&q(94(WRT{pvjxg)#ClVu#D(0Q|f~Frc zX&5a1suHHMR=)Tbw39(QPvZ zPUgizfGAhQ-B&S|_E)aR-TX6C5=mUfcg&boq7ycxcyF|Pq@+Zg2wB!-sVSwY!>7j; zvAavt?QP6rn5T~!?ZAMIwf}k|DmrKABy;@5G}Fknw4nDi)<(9nluPDn%6^-I+BCb3 zxFQ~lC=sIW%d9R`k9AkCr1W!2RHcZfmF!E-G0**CzmBH-k>1gXD9nj?&Y{&s&#Zyx zX6=)|J;!Gyg}T)`m#OSa7ysR^Bk==&57!g*#tbHXYsz<1(_`tc2X{?uZT0G$Z#;G5 z?v=dMH*>bK1dAzWhv_wJ&;D<6~ZmNA*Is=c>xs*L z*Iw4JQdB=AC8_$XTIJ8g6CpnL7`63YrTDl%ppS1j>^-^{v5!3}|+B4I&F{k<&(bNL0vRzV=WXbrDTcL_=dt-c9pnDaN?|LLoTcOmqyFad+}*~#G1|YMt3v4X9n5bF=fy>v1U(}B9-EQm(c*x2X z+{zq!_uGEzt<^O8^rkLG#;LP3&Pdx?$+dAc(b~aSYy5~AZ)16K z0T!E5^v(Q%vc!Cuew&krWPdteQ)_?EUr)b6ALK?ZlS93KgqRXhz+3rY$jb+x&R)%% z&oeL2#q;};ybt%sp;BVI)s|8eGh6QS@%&d~o|!u64~eKya4v_NR^oNfaQ^@?mV6tv z$9~PklD7Uq(}t<@@C0g+>E3JjpGm+nREjP>GD83OUXc7(gP>$y!Cb-dwv>Bw$Ohv2 zppDs*C?P`WnlxpI+rzoLvI~FSlXC~|F`}EOnVCe97_DbQ?}-u|DP5aEpp&ci4`@B= z=>mOH0{t2j3-H2cDmX?-=E}C%1 zebmnr8Tn(gRp+~Klo;Ky{WUPifx`Jt#nNoLS;LQf!3WR|L=*IW)VLhCg1b}in_TGA zNvF3a9T!7VY-S!=vz%;|h53z<7+?-DYj1Uw)+ZdQUFGz|r4nJfCy#hyU96?)*u%UR zIN!Zdv{xlXvmfsPR|N|>nUPET^o#Q??|D{(^Wlqk@P$Z`Y6C9exIKD7C!RP_aXy%s z-Q7e>h$96O)ML4~X($_IDK8_57w>!ALu4$2{ilgzw6|8gR}&R|et*krO~m?nUUW9~ zvSDQl#>dPq^Ef}yYdarhsIi43PzP-O=n*K<$%TX#1Sy0yPM#+S?7P!t=Wg3`IM8k8 zE0`||l_EbJ5sfMs4wiSPAV1|^WiAKQIv+hUPAWVWo1b}m;v6~}8Z<`%& znv;{EZH2r3|2#GlI`WBnby=?{Bhp}D5)mmv3@au<4+W~1%z(ffQ=-Ok6s?R?40Lp& z&^(7QPiXGKH@X|4q4=cpW5L*q$^ZSzf|RAaFZjy0=|vs9Zhf^6OKjqLNZc`j{4LWL zp2g3d)|a@ z%OU||U!QpA^!#&BcxMZ9keF#uhLE-_}X`!i`ykyI>hEoxQ)qVDK=gLK-ZEEP}YW0QcdpKw_?6%@;YUcE4M4;L!D55tj zoEA3jbhQLJL*g7C$xUDuqj~W_`Ja{0)T^Z9TkP!iF#eAqPRGv7B0|zZbX>L2-i3?} zfL-&Det@Yf7!itca5zA4SV%gQRw|&m^1ke_h>pIVK@B?!ORLlvKleMkH0EaG?DU|7 zc|4*?gssr@Xx0Qrnnz}UbU^nKiJI#LAx^#YM1kQ~p9h<+lSg&&k(iE3eu^JFIY}QA zsvaj&+$j}j6w8VWytH;`_=|CineF4y0WsAz2otbhVKa}u70s}XYvm?GH#1eozeSrz ztL*kb0E*#39FN=&qxT-71xGpfxfq@haNt1e0N6SZnu!OVeK-s+7Z~}qJF?wsGFF{( zCm2<-O&MH%o$NuI12>7;9fEEy=ETX64HolQlM*~M&C21&h4pdVRgvX%6`h4h!c4l% zVKApxki89UPB)R{f5*tGl?~ghoQIU9R;bR}p3WVl`H~RU;xgA9YzJG>JS*G6b_JMFa61JP6M4>WWa`Sn zGyYuI2`4b+Jr8U|%ybV-vw|=H=DW3_IgqlEXQG)DHY4M+;SKEJi}3{i7+|^> zLpDELiIX^fe)ZJhouX2Ied<_Tbu&_qwaTXpTuD!4@uS{>q{3~ayz1}Nl~;|jO#)F7 z0;J#sI{J)Vc$DTwS+csjFWE+?9%7TU?tnmNzhN!#Z;Z<&W@TOvPEmSl>feBWhP~hc z15Cshx%SsxQ*Nk~w-t2>@)1YqBg0pfmY)+W-u^GlqqMNFmd52*wF^u1(Z_CkJf5_I zRfiLsI~jIRMrydiY>#*N%?Nz>Feq2JK7=v`zb>{dt+0d-g;r^H2}Od`*_S9`r4NLt zkODljq^5da;#50u(a8JX%W9QbLB)G=1=m>=;3(&VqgRpBKz1QkZds^6I-{#uN zkm>s;uzWD=0Y6eEsZ$oKoUAg%BmB|}2p80KWZ>S;}gTovd zIiPr&k~Y~t!ag@K*2-ZZEVHp==uRdb>48GWJ0e{KXr*#gKo4C{!KK{_3PC+*&)vUk z{y4dnc)3gL(pPT09(-m0!nYzBC*cBsL9#?W)?s825`Pe?>I-LE7u`VG zBJ&=KWlG3);$m3PW%7NWjvF|}h1~E+yJVOv61UR}X}C-!oxpQ-bnAM{cifK>#jy$x zLH7qtshx(M1yhT+j@Lu_`q@~svl|GWVeFZ^qiAeu(kxzrELccV664``ALuGD`9*@) z38IomHh0>44Y)u2b*1a(vzM1MVX$>Hr9GsQuH(;*Z9(pIQN#Yhk>RI}GU#o(j*ul` zEz#e({%L?I#HO{JhLhl3`YuDt{0w169Uj^>5xGklVj~Se0SvbT7B)_LEh3cg%*B2_kX>WfMHri>5 z_qD;#$IM@1DP)+%hc2lK3Q`xPnS~w&K z0m$IExz}!ryty!`y{oEaNeWL9{0)hyHUGSxw$ka6gNZvzU$GfNpjpoesKL4oNp89Hr}V|(FuSPE*t3H{iEkUoMxmxYBi z6os}#Yq1RP5YyK!(SN8;_oVOA?D|CGUo+9eE{#XbeMu$%@G9%h*NYP8KT9h<<$Q%% zUCq%bT7Qcsh-&YnCuAm!%A>hY!^=SFw;}*AD{ih7X$({Slm76rP?5T{ahwSr_gT9AHnT{UqsRJpDTn zZuZp7btxyjA z`#yU13-&8?uE+u1N#E+W5@x~^9~1N2H3{b1Kurh8HxK%%vNBK_ew%wQylfh%R?zJx zxiBgy$6FH($D3Ne_Gzh;aQ+s_#vKF86&RUl?|7aUvLeb{@R3IUzqKfl33G{lUHgBRSGwU^MbcXY-)}mUL<`> zBcC4kj!YVOK7mHMfjXnP`66&4 zvi*K4H>^Mo2j$a2x;% z@G8M5sA_@G7wN($14Tdp9G${>F)A3_{G)GM$APnhDcu8aPQ+=tHSiqDd%qOfqI{qo z2{#rgo-BM9cpW)Do9urlF-JT=l;OK*u;o^;rTE-5ySjXNe&(XaZAS1jI5&aYu^P1E89`kM7uGU---F#baVW<^;}a%M+PeS7Oa3c?f-l?~{*c)O0Cy0S zyKN67A)jt*YlBY%Lj%9rh#Ak}bCs8sfgm>;!th0)fxt+ImqatXWVm`Dx2}Wx{F?Gl zP*8`iz=}BrH9f#30ChG6a#vU$S~@kj{PNDc8^5^xS?JkOzX7c&`FmIvIMpYxfWQbC zT0Ic&faj(bSSrKZ3;cIrc@_sjC``A&@INR$Rh=x-s*F$+j~>lHB7H@NmdGdU(^i1W9py5jBqNv!2L-VD>JOOX2bo#?m7Ur>&~^YcThwW$7TzY9t$%|~b`Uo`02)A+ zo)606^Zib8fDFw8d@eYBA=*0_b~iLD5pzI6`#T1eN_%}!!=xk}j(%_>(vF5`4J3$r(VAF&w!rOzPEDX{ZjCDa4 z03^;O5g7`M90jb;p-Ts2T%*PJnM8KGK-UlJOB5>DKo7#yv|%g>w9c+3#bX%j707U4 zL*oT6K?_#08O?G|8~XxLQB%tjupfoL1-x4c75PZEMhib-k|X%ifD;8%>cXNTK&;jP z0||7{bYN<$SAH32vT$Y(U6~0G+<7)JGfq*RX2m6_3oHOep+~fVndjTznb_|S+J7)) zym(OvuooDD`*JjsD@ck4_xEY#f2Pns5r?~yp41q{<(E}RJ0;2a=zII9qneH)DcQvu zxDv64r)XZI7FYLWPx)FXC`_0S-x5q+#ag_8kItRYa=DN|kAE`~54?$=m!53Reagc_ z)-IuLKOTFVdRGIt1OiN;r84=|Nv)5(ql-qBA#Wt&=WdA0+*d7c0SYVfKi1P_)4fBgE=0(yrvx|hW~67zkf?@?DzI`4ZL!=58N1gaGj(Qi-r+=X^xa# zP~JdD39amW#}yBd35Oe1#Kpt_jdcxZv=0SlYOX zU{C{TMNU|t@`-38c4Vz50g(y&4WBTv? z8Xdk=&h@Rd(gylXFPJefF`dK7*lDbLjW2oN`$8Px3q-mFjx^8C5`T`Vxgx+a@dwr% z#A4`#$~*`BlvoJ*ednGC5R;I=*b~kjd}%&h0;=-l4@YR{^>?^xn}p0ZsK{Ef+&7=r zH$)f`O*s5Ya)K!+)P!sC+Il#oH)oBpHNZ<+A8 zW+UIw5+s$Dqg*|*@_rTR=BC`Zg|&zlKTfy?PJYn90tt=B;1X;pkOJtiQ6p%e?l+oz zo(^G)^4bJSBXgn>9Hw$BgB#xPHyIhJP;|j4S9y6kn1w?bqZR;~h%`Vc)YJws3;Du@ zIwBm19!7g_Da{sXJW{zvs`M)h*gOAMaH$57AN3UwU z`aN~?QwnsqF{dU>!@*H)9_&RzKtS6L$KKb>8ov;+wgij|FHCX4naz3iYF<#Wi|>mQ zuhm@bGjcyWx2j|L{!2`D9}K@1sWH&H407G<@$xG9k~5{&Y-bi}SVEIngPp5q_I|Su zg&=pP%{=}Z4JHK_l773j9m0mgIx2>4wx3f(5Kf#Bn$0cMfthjYDpgkzsrTD+NOIO2 zCM9#<3~Xlkj0d<8@2ElZMwd4^p5fM2g=*6bp>RczOC)Z^U+*Wx++9;l`?I}E5a+Xr z-4;fT){CpJCujp#gzk5V4UGO|PY$m3zy=7mn35%zSQUG!u1==!7XAvb3eOab;2+{v zGCOle>_9+2MZ#36yW)gn4sjz~Bd`a+K>&=xYFt3k0|S=^{tOo{9)O??L*3o`@GH)= z>KyKJ9NRX&fzF0pN%Am@-H%%m7DM3|?7s`JoZpm?@CV@)oHPf}uFi1(#?wB^C4p)G zL8%I}T_H7x4dU{R^3+E=d?r(K5|d|_?y+1LpMLBDn{RxW~sn#h~j!Ve1B4?D|TGvE$5c|X0HEs zA>rqt;zLQ79u*XcJb~6Cw=bou$0X9AfLLvY6(WSD_iIwZh#Bb{X9ayBad#kf5~6rb zlwhk!+@CUIbNd|+ey-`)>F@-w6Ndo;*wIY=P2=%Hv z!IR=4c5uJDy7HOiwE|FGlRC6f7zR!Y>u&kykCc4bf?&Y8#$N0(f5sqQu*7L@bv4B# zX=efROJ%$sSy@@o4Vm<4Qm<{sUxjo_B<|Nc6w=k*4O6`k(KN-q4`?d(j`(!W{VYrc z0Wo4My`Tf!`A~6kT+VxFNT>E!3>K=Jq_o<>!V;JI%84yGmUJsYn($8Bon&2$SfT_G zQgyclDiLPp+_EyFYO*%&@_`2^gsB4S)W_!A%6p=F4)kl45$y0fgN8$Tl{z$*y2qmi?fDvZP&4(KjU|CiVroOCuLO z+d5cS48uN#VaL$B0E&?v6F9j}3Z+ok*pLMQs|610e0zF_Fqnn&h6@6clO4cb!*~<$ z>LJ!!6hRi@W`+t_2=8w5p{ZTfG1%?4_&o*SFMyNZ3a$UXM<^H%^#t;-k5-H8MZnir;$W@O%0Ny**uA zN#W;mcJ1YH7bfnFjS+Wq+9C}$$iimK8=R9GK}fvZLKgM(@UK)$jotamXH&J)|2`nL zDJeP^1|?@{^OH?@E0Te$imzcItg`imX@$eAQOx|yUJGaS8Ld2RF$2~h5@k{F@@7rL zcTB{ltJ_YG^f`Xf)f(ToiCHu~p=SO(v1GgN!493i7N_yYccChxG0G}qz-|<^XmH9d z&4xA3KQ29-?aN*d);-~_r?Be5u%xAOb0+~JTwqjy`|PG?6L5aCsk^76FcvHrDiIl@ z9Um>oBrp#0zEab3@%m)QGiI0|K5sogmWoxlKt=TvM%_44RHh1Dx*{ksHc()b^s^0{ z9IlBA@*{x8?J%1MdL;nJ!~pLM+3-EqBv7qi&q(^wXKv;<&8HJ0&as3|0==Ly4LxRiql?OPvU^F{kq6r(+ zgNnmh;L&aK@SARsn?WQ340Pf5VE76lMz%`pEw`QG$~`gpBe+#0#dRm1*9>x9GC0FW zjok{f?xCOr3fDgl zonDlb_CXZe4(~GP5#JlCJc8y?HA^p_Y6&L8z!E!nKllE-}Ol)&YWsO+`zBS6n*_UmUzB{W6FgU=nD5X#(_+W zJQY}&(>01!U*h59gV}DTn~eS z1YMM?n+`{cGb96W2)KOsp#Z`9m)C~a8`FW7#jA48S3~uKO?Gm zb9<%Q{%Dn}huSyWNdtpg5-=+;T*n2VetpF~TGqZY<_dvD;j1m--5GO`HP#w&OJ9c$ zgQtIL0bRiE!&ZW$+wU`K1$K>)wp-WLn}r7#Kcm=qdE@zLN6W4g-_b*UwQKJ0bz$i=EZp_{g_+vc^bXsOo2t#u9Zr(Jj$u6sCIP*Xr z1Wz~a@E8P@0M5_CT$f9W#J!)D1c)`@If0+~cFa3N$mt@F$zPx@JmmU{ z!HkJ$D;H{ED&;^B1$g6@Jc1ihRNZhzy-=evX? zBwW0__;{U9o5yvrz%_dd)aS6wy_&B*A?RAjpuO{J_SyKQ8A25j!fP1e09kG*HzO){ zb9<3COQ5-S5@p`gDflwQQswF8XSi-9C<+H$=1$7waxC_4d4w^2k)FVaTQMi(DrcpDU=HWe%0OcxSET~|_8>34%b;SXr2)aShGR8>!v-CW$7Lu*&GAxoMj48h zKYN3@CL;8yJ-m`82M+GCdcWnNxA0h6qsC22G3h7ibz8p9<29-N!kiPfBG|UTh5pH$SINAqyym&f+pi^JtFl*-X zH@(Jl<*s$=<|nM>VuX+gpYT9EDBMf8ZIuP7fA?XS*@2Od9KR)u3>~KS_DS8BqkTt& z@iKZwy{#_wF1I`vHMT#4Ek1fqq3CD%Dj(9b4*^>RH$t`q<2veh(gfnm#kj zPjc8mqs0}o)XdS{{4lN!x;=o7s8+|zjYX2a$Q~@WW&eCRHHx5SLgr7$ZD?t2#p!#` z-%yIAjv6eC_6ch!jch($3D?HL{e`u9FCUWu5t=OcRBa*86-Bx zY2R36!Fo3HH)#ePISwOI`hGyROYj)i0X=yUC0tCTv4a~zhB#UnZ+al!f=ELKJ$h#L zbt}VrHP<9IT(4|I>p^x4UqRhVr5R&uMwN zGZ{?ZEHv?f@-iFM=FOAd>&ots4{@ZxMb<*4`u33U!QBG!&-%iaJ^9~@5{=!%JT>+? zckV!QBS2_qIU#N9u5sX<@{WGVW8E{>GV?%KY;s_F4Eb*57<_eUuosFRjhs!}uVtosQ1V**eEd z-OJW1w268Vt94sMgqzen?@yJ?-t%;77N;ALOT##@+cj(>-=4e3%MopVmazdbr0wOA z{)vY+c4vO}-_;o5U!7k%*ro55<<_xFS5hJ$O|j8J4@nUzr@mc;P2)+E1fw6_FtCQg z<3H|sejdVF#+G1e>>tvoxM^=**&Cl-@7H&`#^>Fv6qI1Ua!?@}+6?7EiBVv{fVm26 z>kk|Dj;nI(^CFapkg?)zwM~Paj&cLJ8mxz%Jf$R`4?lQXJgAY9A(~3o`FY z$%L$0r&DOLwj8Z9F!=>gCI%83abynYXB5VG=06t^YQ5x#;^kT%S@*8R*}j~NAwIZs^jzdm(FGc; z{!=_z(X#!w#4nlIuv(r9)SicJFWrhVwZM{O*x*3wuda5<1h>7sbwUb7TmUok-@Xly zb&OXQC=pMLl#*7Dv7zF{$Y(B{e_ywtd*pSKzEDk=eWgKd4VqB8 z*7Tz%X;2&M>s~k{`s7g*g#J1sB%(bg@{<9IE72`aq$mgwJo~JRc znLA$2A8CM@02~?cyCl18&N=9cOZf4myjzA65%E+Ne!Dfjrl8XI>0dcFmd)2oDB*|K z_zu1ue1ZN1_$7>hO5|GiV}(QG7nKRjf^pnI_USoTR!pnK96xIErcBMTbi3CSjEXxf zm;b37|2xvJQjKb`WsGCl5qk_?2H41Ijj%&Wd#<5Z=Ux8GJXd@-`;-HSsByfQF?4;2 z8y{_z?QpC;4(M~UxmZR8{yS~qK7SkVwq_dR<_qF4aLh0){Q3OHvaDrrAqb3J7?GAg zjy)n@BgN2iX}Iwm>iBw)E2fB>$zd!d011v1IWnbd??zqK*Xlk3b2!??T&%j@N2~iwOa;bHHP=~L z8O1z%!^xyU;}?rF_<>=ooKRlw&NXOqb4QNS_bUyL#8o(9SZ3g2$|&J84j$0;S;~*9 zSAFbH?+4u6%JD#O#J@D;n}wWM28F%~-AS>;rrQkvLzeo0`^MkLZ8!PVWW~G-bMF+s z_u0E1oQ$oZV{rY?;ozUIeAf&1{=IHaCDCpwpK~4;xIPTcSMXK^{?-0Knok+4{4SX* z334fa*q62Hfxfb4XNFqcyeqkw;9Y5LV|KSoC}em(3;I2W+0C(f6@6C!ym$JCC0Dkw zB-88Xn(9I;dKxc-XB?z9pM;-6LSqB9g1!7I>*6b(Vo_;UEVbUHBkiN%M2D46CHZ96 z;SFE%3Y>8p^&a-6J=6p733P>V-nU_zfHIfbBekcCMEwQoJ#J?Z6B9!(Ha@o`#Zn-E zO|z5Y`Dwby&YA``vrH(fB#IZe*A!;}*&w&`KnhBN%xC1f%aoHxq(?};&D3o{Au5{m z&5tGimsr##UH$IPi&Tctv$U@)9F?mAQ#&YPgObC&@nl4iDK^%rY-yKQF}CY6#RQeT z;K>+^1IRa)9%UC6KP0Y(DG8tzgTLEfA^lJq9u~O-@9J%*4}_YDy10&$Z;Mt z``DBFT8?cPME4utO@8?0Hfq+q-hv(cxYBoeSN=g$nftGu^!mI|_aXlZc<^azUR> zji{g?2J3Zr&`GRm@#?-!`pviZu)(_}2F5!1NY0!!ao7r#oKtkUWlz@(N=KGze(9oD zL5f7?k9f07gT8TS-jAyw0h?Kt^dh|%R@iMQ+d`X=M%OsjaATm=-+Re2{ll^tq(yS^ z?FUgEFt7avv09K%>K&$%>wY5)&jzFzK}r(A?`2 zipHr3Wcx729E}>~z3U|~$2N7|P@PVqIh)PsKhv-6G03~aDHWSM?ox_bkM?Y=qB=IrFE17DAGf^yPPBTi*0_dKP*2J0vU z#zf`B*2li`T-DmU{kOQ9JLrfEo%cbEuRgm{mUOw!0;O2_<+X&~8*guP+iZ&+-W|K) zTo4CCPg$0Wpk?bveJtbS3n+6}>Zd@5UjPR~ zgAw8_bmKU4doweLUS^?pj!iz8Y}t$PZ?)>9N>M3%Vfgs6PqwJX$97aTKjoPaKC-?~ z8~YKX4Hb6t8k%` z-mD`|$Ql6?$}v_pB(b=}rl_ za6psX!6vZL#p0w>%KkHNJc^C%%IQdMt%Sb-|MLaH259F(t?4>J$IVTTZb6-hZ-fzF zFJd%>FS@4h+`Geo!jzGqZ{Q1d9+0UAuBwh}$(6U67t`L{tUJqVF%2gB0;$-^bgyvS zb6#=O?7N2mg+=ay%iHN z>D6-KBEV`%r>kE&jJhp)w^3D19rX;FzS2yKV5gy$qqZ7{+lrn2;6K^w-Eo6Ac~=7G z0}XwK4&N?bGP@?bCc>hFjj(A?KnwsKXfmi|u<7q?Ud7@Ar!^>{z0lt*6mf?pI_UcE ziVJ?&n}Ym2rnRtiaWiyoE8wr)5kM=!jYO+dRb4&6bEN;}QcXaM&EBf4^KPmI>WA1 z-m7M{wpbmnIEoK&ocrg>K*#XsY+tUs|2R08R&&pFy77(&n#z$0ZOa{d(4vS!m^l#g zG4q=>1FnKRp`czFpU)^r%N);9h@s8Xn+?vqgOB`R zMC~6QGJ%-mKK{Wi>qOAtad7mnBfXkV@gs#&RSVFM1!(J|$<`E`q%-Z?xx812XWvVe z-p>ix7jpmgOy-7u$&9B`Yr0U;r)F36msgXYo@zlG_iy8$;a`#Dsq%I|{8Js8yml}i z8Tl!BbiNrDVHPkvToZVH28`NCUqkaWl%GGW8px$xT}DXqU*utOk7KaGR<}tz694Il zFynN~;i^DuR*TW_wt7#h-B@Y$2M))*diN{VCU{m@){X2ETKEv`h{QZYN~WowOH*Nd-A8=+e|w5=1D zsAt0OS9#6g1=baJmBN@oF1BmkO9FXS=^fMB;y0?hm15o%>y1oN?9&r5)IbIxjzS!;XV82iJqMu*S~6Bc0nu z5)SM}vV7Hi>qFYbH16GX48j_bzyCaun)Z9^pkx`l8t(aPHml($_W6NC<;m%#mzGZu z^RNN%3V;FQ%$dqJOpMp;VOTJv)vcyqPKNLvj?4=HUpP!~R52pSb40B^e>gUpq|HgC zBZFcllnJByxSm8IeCnZ#INjf#mxNlW+h(lXz1*L(cy)>Zaj54<3s&EAERnv>izPk% zI#7L|x~$xd@UG8oC&RJ6(i++gf|?OJpQ)eL;4`O*xUr1xQwuhyU76H;T4Msy z&DR@{k9DQ_kUsGWshkU|yu9S}uuv^z=f~?8d9PP-%U;Z!>8dOels#v0DBW4eRN4BG z@e$TXhP7THbu8I)Is7;0xHIRmzk3=P>{VVEW&~~@O`MB*e$#-c@_gwNPFqcIZTud` zc8#R((YM^bIo(ztr_;{puMNTduB)?#d7sErNoStdINz;yEU!}FJiPzCGW$%oy@?Pi zS#?y)0Uy6Ik|D@qaAf9l8Xu}x_Q2rad7=~B{b|`)w*-Z#rk?7akjLxf2X&cEr=+_ ze|tLhWIXwf$(>xU4a4jWL9Hk53LYaQt;nP9ww0RtBLiT`N*30d zuSPZn!3N2f!X)j&mb8{0bG+`?c|v*Pe)fO(;?-5)+Zwas@ky^M9L5-jNrAQ$DpG%4 z5(TgiHw%)-4bldP@IOt-@ddam;-gPRgx(F`#TTm=44H9MAtbtne9hY-Lz4svB5YX3 z*|##A=m!qCgfz5BmYy&S_umSjLv(Od)YWZhZJ_M~Fci@K4KdJD3}<}*>uTr_CozmV z*SNl%6slAML%L7M-;KGF>sapGan4T=@J1Chggwh{`$P3>sr48C&rffE-h(FSGd@{n zqie+^`uxO&`iEDe-TKv zgQ`Z4bl>xer`juwkL)@#vgjo|{;xs7QW^VOf&B-c{i7TB(pP2bhlm({+3&U;5aI9P z+MteVOR(ifg1Df6$;Qrp1X8W@KUIN|%~(cawSxs#wL}Bb!-&9uTvBU*>~sPT;}tX| znnG~>>BNCtkv&Xc8C`8JM4-`0#yco%Jp1F*{!f=_>-9#;ETT_b@4_56^_m{QmnV4k zX#USH2K-+Q7g0j^ZI3RMCz6u#8Ghd|jhsJLcFrAL*Jmqa6PTX3H>#X|^hMgqs`Z%M z|6NS-Z}wXW@=_;<0MOX|Qnj!fT)20oT*SL>y`NLlclV`_f;sHqiF$?O(xGnfl5RileDSLEJ}6fM-K@nr1!UU;ZPM zV!OZD+?6JMmvyk$4If`xp8-|!Mie0vL^7Mwjl$Nql>a^zHOE0qVbKJEut~oXctgLy zVV&MHCy!40mg+m9(aRge^dFD@EW$qZya#TUO4s(vd=AJ+Xd zCiw6r-qu>yw#}FaIf8f`+e5i7k3PK0wb@=LJ8i%L)m=w8z;#nsPVKfRGW^8o&K=ju zC%CN=42JJsuM=NoCda|Y=Y>u(^n{`I35Z?07VJm?VFk|ogsEL~QtqN~y3K>1gEyYk zR|sfBSsTj|QQ!<_5lTLNl)V<1AAHs;(5^dQ+p47yN9$bJ&S7QYZJxC|c_?)@+OlDO zMk03IOKg^8jeRM?@hkeihJm<~++2tQd;bHbSVloZ`pBgnAj@RnuZ<`3MqZG6!5sh>49}o-bd-D6+(f^q%@@|nf*fXJCF7x z=V5pea>n+}z~qckT=j^tIs|RR5RDAmJKYc-m6T30w1{=QhKu<5>z&W+qg&!)r}C`h zS)`Y4kT|f?3dQyZ@D~c|gtX%9KD!z*qO$UGN9&6i@_Y`JFvEz%<`-ej61D9t%-vw~KedqSjzKP&q%8&sd2uPgjInkzG`Q zlg}t@l>eZPI)TbOC9f7IkClL1o{jx3d(e&|i3Y8#MZ}I7b-u=POTNjUm2QqXmwqbJ zTNaH8#I8VNvb$Nfe|haA)a3y(YxF|;VufD0v(WpRqs1$}?~+aLI-$}#pz;hmpNoO+ zrJ+SiMg}JqV(6K3u(2iR!pLrXORQIN^%{I^W`eh15(%QA2r}ttJo>kM-GzC_ECiN? zv?TH|dLKQ!RGPmH*5cDJPb4v%xpSQdj-;(k9*eQ{$JW~hQOgQBow$O*B!hFUe7pVG zfu_XX4*x*AX~+a_CJEa%u1!7NSO*@D4F8D$&Do!k-jP=h=JliQjD#AwP~Wf_bjEI% zUO*Hn8F9yQPWN^XFZzSl07RvSF@cX(I|4iBlCufEWPH!wvo1_Els$E&vzZl<4sy4b z!u9!ShJB*_R_$vR9}f>1(Mqpd!AG_4SU0=A8zIPpD*>%oCHvTy(Z99I9gW>yV(HY0 zeJpgWzMMaCaLjMC#e$gF(g>Ds)0K2Jc=d)(Sm~gBQk(zw@ zLg~@L8=Rg~R`1+swU{N5Hn*hHOGtDwEQ*xwErQDFHId`U zo3V)_HfMf;a_~U=ySy|k$z&C~S@4!P=vbYg7aP8cFC@1a$80QvQHi-JRC3pP=rvX2 z^V?KVc6FaFE!e5NkhdqDQ0M%SizSDR*FP0r@`mFA?q$4&@zcw}QbNwZn|HQ;o9bO= ze=^ftPcHpn_8~25(d8kFlOzc>!psJv_hFM1wPS>zrfI8GqV#A>ot>=GX!O1@R8#$p z;JD+wFrs}){S0K*^~G!*M#pbJf$_S7N{l1UdP>#rC3)~w>8o{H8@;Ypaxw0|`c!re zU^(lR*VWeQ@W?oPtyTT40oYE%k;KYV9L=D=6*D^JTi4}c)R${-nee7sIM0dZLv>4< zoJfR_qTMb@J@kzrf(GXpytl2F3vn7vml;uf#%bJvdM_ACtFBO9qzf**1ZqyGwuU$< zkKc2_VSh84ayhGBAeqGSSC?HZqdX-A9okke0g|?sD4OX1j%A!S3W~)lO*ShccAiv~ z=lqc!2TYYo_fq&Hwc?JaO(Q%ztFYcZ+37u z%p9r`^9Hl9aK3|{S~&?y{wFVFS-6SwQ-YLZD#_aDqS>c4b}Y=A$Z_pHzQUoE(Pn*k zw}i$z)>Axigw_)4x_rTP@fj{YWwU;cyoC}rn}1p^&o5m&Em^ac|M=4KU*A*X)8|LG z{>4YW?X-TZw_QblEsVv}@PSa`mAu=pRF#P|uBcX+9|!7qU7H_C4Y@_TLG}8pNh$xV zKkYLtt$D25Q3#=felwS~wkOY}3o1eqVHMZ$Ag{=*jZ3p~B{BT{@W(5r=(Hz2*}VdR zAB3f*Z}kNjD6YLBS!p|PcXEoX(2LVcXKM~6`?7dgpE@*Wu})kAb=^N8Bh=#R$TH_# zK+%FR=oZaKiZ;S0k4cj5;f9YYHhoJ32uW;Ik7e)4bFVU0)37QV2)hVB2DUVCNx%FpE` zEDxRy_gU{*F2*@jOaLXq_debuIdOn41uL}ogOe-AA4wV>efGv@_y2}`cv^7s zUB)vDJ6HNstboqIcxg2=jaTDKyQ=P6)S4;@;0FQ*SIsy(-df3-E6|}Hl4TNU+*P!W zjh=a}5Ei#r_V2e2jcWc~%Ed~)Yrx!sRSqmt9E)=g=YWp8w{yc%=t9FI$lkuYBkLee zRjdBth$nhH8bDTUQMnZDPe9fpxBB^d_oIJ(z7Lz&b@ZNPiMPF^Ts_{RI?QC!`+3-S z+#%Dcukefg=kaEL@d-AK=|WwPSLFkvtvQDAdg{UAUOCy$^&i<5{(G;*+#@!`>j-jY z2oNJ3wL%)I;eTAkrIAn596j@X3ASvT`-j(1J$I|hazM7}4<043N=GW-E?**!;3LKR zrKHUZQ4@(8jM{ba}id1|~+bd+8T;Jzw**QzhAGc?=je&N-9mSgzeD zt4=4fogl!gPd-nx-%K>1e)Tc>g<|W^eoiyLKZ9nix_E3F&7mFkoT=p6k8&x16w`1K zA)vx&P_OUKJ@;=8c{!!VEMi~p^ES1w?hPCA>j_O-#a%L_Jd!#;c~O|+CJl1~?Vi#4 z$StKLZDlQzePf?%(m^Rz?w@y-Xo1L>{$$d!CYAWbYo%Lku2xn3-wJB*#f&`8?r)v& zECfJaDYr_tR#IwXBXi)VhCUJE3bLy+Zy(!_+wbi>MZSHB5bd|)c+<2wJKXEW(OQ)G z=`rUmt__>94a!F2TgLWW`-49v&sIM^Vznq2?Ks9YThgsq1k`2R}969uORlwVImL&+_u}=p0Bhwc@Xg z^D)^#9kMg2gPO{7xPl_vgM_sz9T-=5*;+qwp@!k(kmD}O&Dn+_B=>;+gR4Ml; zhz-9mW8sNG-I%lWSzgKf=$ny>T_ZMDq~h0mzhgjr0GWr~%ZAlaHX_M;}nxy;2! zx04PR;&%VtAB_2;I-P#F=Ucb0Xn?)%7)EI$aNSdfN7R65h{##vQLZNkR|ivTd%di> zlF}3~U}eb%k;^wST&HKWr%K3rH;!8YBwTi$Y#GtY*sOQgiZ_}}gCLXXyS$7@2A13} z+=zx>A?jFh)2ioG*fg)peib^*Z?YN~Gv+53r5Y`9w1fxqC~=jMeOI*2a#*kyE4G@k zcCxV$?EAprSV+q#pF7Id$!BOwcGh?ruYdM}w)HC-S=Bx2=&_aPT2sU1e=-T;1sBwB zk2th`ddCE^3(Ce7JGaR|8nyVr=0DGcT(cE?Zw_2@fAY}k8d9By6IUv%_rf}@trL2sEY?8f+vYylT_kW(__`i5wKD}^++dV$x8s~Lg=Shdg%hWiz zBR>*i$^!2n`CTZD@Ztv%B~`XB)A)>@;1ElpqCj*>CK%)kuB}`nb9qs0ygU2pq+qAMCXx{TOg*GjD(SX?fZt{6y2G&Ic;(X`)tHgty> zVCmQ|^7eSH&7c`ZTdk#0$wgn@Ol)?C$m5(rJzbma>3t;`JU)>FKR9StGCeyDeS9CP zItbLfzG@;)N+O%X`APh{=#s^D@zUn&v!bVtw96gQ*1h~&D@ufQf{w3P-6WDJDJ;U6 zD^e+wfyA;gXK9aT8nZBq545F*G3*Rd=+;}kxuzs{IYSwbM>UM9lI;&W{Gt&E*_j#^ z&DjoC>kNVQKCO1C|FgV#Sl-GYQ=T!4aPh-U&Jx96kX@{Gm&6eZ{vZs4294)F9R;pcbY7P_+4)o}a=8P{+MpdBC zjE^O-*j2*7wClso+5Qy+5`vzvQUgJFA#@{lAMqNEU%$#BYuZN4e4XSV_m~Zd(ny-D z+zg+2`*h=G|2*?e^WyzJM%7K(413p^zA+bg+k8GLG;=)pbVb8q^1HvLz7owaaHMNl z@(a?B`3~r%cJ^;9gsK&)fU@@AjQ;9Fs*)Ag0@e%c2gEl1{*B<~@?!)`xqZY7a`Vrv(gyIE~dr0AqM4~MPz zVo>7g{tQ6f5%=!Nk$Rl;yyWBK<6a!_ujm}tL~n6kZ0U~RS7pj+jdzQcHb2|@S^0iYgZI`{ z$19g(qg!Kr3i8=rhK^Gbl8!Q&r-LU9YWzby{%uaJa|I<_^_AII`o?5N zypimqMo+n9+k(!coOClu`m|bTu}=Zj-9nAEd0JQ6VVZR6sJHIh#lE@vs+SzZ>$0TW ziz&WRgu{nUNCEUbs(!!TK0iO0rLO+|$L{z1%A|h#`K@J9SxZ_XMeXtXVN;Q_M7BQ` zx4(#mZAdbmty;^TwDa94)iV{X5bP4?RXLpJ?YCyvy_~c7?N{7M+GBhr^Hy#}j>n6n zpWaG4Vpy?ko8{o@wywQySh1N;2#`E{cm(X*lFpM1HNvPi?&Pe7Nqyiw#+1b>Vk~rq zfEx-7u4`$^(bn2ziscw@2Hi6FLxqLyP-Rd%v+`Yb`P8{{lhq9c+d#SFR9rSKL5U3N zCQz`I**DLiX&V*7CJqn`pRybDi!DWK7W)CIqTP3`sl(m+Z_h3MCX{Sz*0r*m((7bCvg{@E4T1H-&E$n+{sYZff}gjBi| zFnEu3Is^pyKiK+QD0M1+O)+6kd_-jaRdFjXh$U+V@&>l^T-i-DSd9rO(lkXcTpt~~ z%Am1qO-@XCEOm=)&vTv=pBclB|B2HgB1Ox40g9{a#d32BXVlA zW;YjhvHC3?By&DXDM4Ty9=oPp*A?-sNV4tO=f{T(aJx zzHh>mJAVwn*gD8{`)?EvslVQ6HGxz5lZzb`HZb$s=~&E zbmhwduYuUD?GV?t=TY=2+a+_4-~Lwjc_J%g>_<$;!UAQjsmaM>5RROlo*o%#U+D*v z&4Y-DflA-X$jF_Uqu#zg5R6{nq{H|QJ9q<7PxJKj#C))t+BY0*r=CM{oHEBZ-*0H> z=*W7l%>(nscpv)GF#bx*Dk(gefyuE4u0iWBm3rA^&)*3&3aq!QUUhFDyLyfD$&)7- zP;s=kcgOlQ#$|qse<+=CjYC(}!9gTQ9@At>+S-h#FLKg-4rjBnu_?dR$`yy6Xcjg$ z?~%{c&~1lG`S2+Eu=qqp_YHKkx9=f`c!`^*XGl=c&;&6tF@y;|yJ8AAF)0b{mSlwa zrKO!I;t4AAx6hwnx3vYQ!T<>Y(u?33nBSRiuJByFV>!{!YEY#HeoVW$wzY57!giZd z>Q~7|>U>R<%MCTmdB!C_=VhNbM5KG|L#7pbd7OEs&@m-$I &v$+mejM34a5;?W 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 literal 0 HcmV?d00001 diff --git a/assets/eip-1884/SLOAD-run3.png b/assets/eip-1884/SLOAD-run3.png new file mode 100644 index 0000000000000000000000000000000000000000..674eb2d9cbb7aa451c2eed5b6a5b3349ecb2714e GIT binary patch literal 120062 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ƾS0$=uJEA4{L)%H~n@%lsw-68?bY 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 AWB>pF literal 0 HcmV?d00001 diff --git a/assets/eip-1884/geth_processing.png b/assets/eip-1884/geth_processing.png new file mode 100644 index 0000000000000000000000000000000000000000..64bf92e4e591e8d7e6e4803a3dfa3dbf9957b91c GIT binary patch literal 220235 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

    x3htzVIL0v8#Vxzr!E<=K&sq#W& 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®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 OX36Wa;#pU7+L~SAw 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 KaXarCknnGjlRF^* literal 0 HcmV?d00001 diff --git a/assets/eip-1884/run3.total-bars-6.png b/assets/eip-1884/run3.total-bars-6.png new file mode 100644 index 0000000000000000000000000000000000000000..56548b96f4f17a3e9a7bf8ffb9ea9586e3e03728 GIT binary patch literal 53843 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 JE-dlg`#*zn`yl`T literal 0 HcmV?d00001 From 4ca777843a4a8ff80bca84f3484da47a5317ddef Mon Sep 17 00:00:00 2001 From: William Entriken Date: Sat, 6 Apr 2019 02:49:16 -0400 Subject: [PATCH 142/431] Recent ERC-1155 to draft (#1917) --- EIPS/eip-1155.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 76efb625..edda721e 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -4,7 +4,7 @@ title: ERC-1155 Multi Token Standard author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet type: Standards Track category: ERC -status: Last Call +status: Draft review-period-end: 2019-03-28 created: 2018-06-17 discussions-to: https://github.com/ethereum/EIPs/issues/1155 From 28c99cebb0d2971721c04e7d6173d1d6f025672a Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Sat, 6 Apr 2019 15:05:18 -0700 Subject: [PATCH 143/431] Revert 1066 status to Draft (#1918) --- EIPS/eip-1066.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EIPS/eip-1066.md b/EIPS/eip-1066.md index e5ea916a..bfb15d1d 100644 --- a/EIPS/eip-1066.md +++ b/EIPS/eip-1066.md @@ -3,10 +3,9 @@ eip: 1066 title: Status Codes author: Brooklyn Zelenka (@expede), Tom Carchrae (@carchrae), Gleb Naumenko (@naumenkogs) discussions-to: https://ethereum-magicians.org/t/erc-1066-ethereum-status-codes-esc/ -status: Last Call +status: Draft type: Standards Track category: ERC -review-period-end: 2019-02-25 created: 2018-05-05 version: 1.0.0 --- From c8f3b4e300436a8ca0f9a9937d6199cf0c1a8f06 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Sun, 7 Apr 2019 00:06:15 +0200 Subject: [PATCH 144/431] ERC1820: Move to final, mark 820 as superseded (#1919) --- EIPS/eip-1820.md | 3 +-- EIPS/eip-820.md | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md index fdaa761a..055bae9c 100644 --- a/EIPS/eip-1820.md +++ b/EIPS/eip-1820.md @@ -3,8 +3,7 @@ eip: 1820 title: Pseudo-introspection Registry Contract author: Jordi Baylina , Jacques Dafflon discussions-to: https://github.com/ethereum/EIPs/pulls/1820 -status: Last Call -review-period-end: 2019-04-04 +status: Final type: Standards Track category: ERC requires: 165, 214 diff --git a/EIPS/eip-820.md b/EIPS/eip-820.md index fb17ab6b..0e0efd1d 100644 --- a/EIPS/eip-820.md +++ b/EIPS/eip-820.md @@ -3,13 +3,22 @@ eip: 820 title: Pseudo-introspection Registry Contract author: Jordi Baylina , Jacques Dafflon discussions-to: https://github.com/ethereum/EIPs/issues/820 -status: Final +status: Superseded type: Standards Track category: ERC requires: 165, 214 created: 2018-01-05 +superseded-by: 1820 --- +> :information_source: **[ERC1820] has superseded [ERC820].** :information_source: +> [ERC1820] fixes the incompatibility in the [ERC165] logic which was introduced by the Solidty 0.5 update. +> Have a look at the [official announcement][erc1820-annoucement], and the comments about the [bug][erc820-bug] and the [fix][erc820-fix]. +> Apart from this fix, [ERC1820] is functionally equivalent to [ERC820]. +> +> :warning: [ERC1820] MUST be used in lieu of [ERC820]. :warning: + + ## Simple Summary This standard defines a universal registry smart contract where any address (contract or regular account) can register which interface it supports and which smart contract is responsible for its implementation. @@ -889,3 +898,7 @@ Copyright and related rights waived via [CC0]. [Nick]: https://github.com/Arachnid/ [William Entriken]: https://github.com/fulldecent [ENS]: https://ens.domains/ +[ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 +[erc1820-annoucement]: https://github.com/ethereum/EIPs/issues/820#issuecomment-464109166 +[erc820-bug]: https://github.com/ethereum/EIPs/issues/820#issuecomment-452465748 +[erc820-fix]: https://github.com/ethereum/EIPs/issues/820#issuecomment-454021564 From 6bf57fbfc6533984d6d2b90e20ef9baa4bfd145e Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Sun, 7 Apr 2019 00:07:05 +0200 Subject: [PATCH 145/431] ERC777: Add function modifiers (#1920) --- EIPS/eip-777.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index f2b4c8bf..72f4e821 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -139,6 +139,7 @@ function name() external view returns (string memory) Get the name of the token, e.g., `"MyToken"`. +> **identifier:** `06fdde03` > **returns:** Name of the token. **`symbol` function** @@ -149,6 +150,7 @@ function symbol() external view returns (string memory) Get the symbol of the token, e.g., `"MYT"`. +> **identifier:** `95d89b41` > **returns:** Symbol of the token. **`totalSupply` function** @@ -165,6 +167,7 @@ returned by the `balanceOf` function. *NOTE*: The total supply MUST be equal to the sum of all the minted tokens as defined in all the `Minted` events minus the sum of all the burned tokens as defined in all the `Burned` events. +> **identifier:** `18160ddd` > **returns:** Total supply of tokens currently in circulation. **`balanceOf` function** @@ -177,6 +180,7 @@ Get the balance of the account with address `holder`. The balance MUST be zero (`0`) or higher. +> **identifier:** `70a08231` > **parameters** > `holder`: Address for which the balance is returned. > @@ -210,6 +214,7 @@ The following rules MUST be applied regarding the *granularity*: *NOTE*: Most of the tokens SHOULD be fully partition-able. I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token. +> **identifier:** `556f0dc7` > **returns:** The smallest non-divisible part of the token. *NOTE*: [`defaultOperators`][defaultOperators] and [`isOperatorFor`][isOperatorFor] are also `view` functions, @@ -322,6 +327,7 @@ Get the list of *default operators* as defined by the token contract. *NOTE*: If the token contract does not have any *default operators*, this function MUST return an empty list. +> **identifier:** `06e48538` > **returns:** List of addresses of all the *default operators*. **`authorizeOperator` function** @@ -337,6 +343,7 @@ This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to authorize the holder (`msg.sender`) as an *operator* for itself (i.e. if `operator` is equal to `msg.sender`). +> **identifier:** `959b8c3f` > **parameters** > `operator`: Address to set as an *operator* for `msg.sender`. @@ -354,6 +361,7 @@ This right SHALL NOT be revoked. Hence this function MUST `revert` if it is called to revoke the holder (`msg.sender`) as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). +> **identifier:** `fad8b32a` > **parameters** > `operator`: Address to rescind as an *operator* for `msg.sender`. @@ -365,6 +373,7 @@ function isOperatorFor(address operator, address holder) external view returns ( Indicate whether the `operator` address is an *operator* of the `holder` address. +> **identifier:** `d95b6371` > **parameters** > `operator`: Address which may be an *operator* of `holder`. > `holder`: Address of a *holder* which may have the `operator` address as an *operator*. @@ -484,6 +493,7 @@ Send the `amount` of tokens from the address `msg.sender` to the address `to`. The *operator* and the *holder* MUST both be the `msg.sender`. +> **identifier:** `9bd9bbc6` > **parameters** > `to`: Recipient of the tokens. > `amount`: Number of tokens to send. @@ -506,6 +516,7 @@ This call MUST be equivalent to `send` with the addition that the *operator* MAY specify an explicit value for `operatorData` (which cannot be done with the `send` function). +> **identifier:** `62ad1b83` > **parameters** > `from`: *Holder* whose tokens are being sent. > `to`: Recipient of the tokens. @@ -675,6 +686,7 @@ Burn the `amount` of tokens from the address `msg.sender`. The *operator* and the *holder* MUST both be the `msg.sender`. +> **identifier:** `fe9d9303` > **parameters** > `amount`: Number of tokens to burn. > `data`: Information provided by the *holder*. @@ -690,6 +702,7 @@ Burn the `amount` of tokens on behalf of the address `from`. *Reminder*: If the *operator* address is not an authorized operator of the `from` address, then the burn process MUST `revert`. +> **identifier:** `fc673c4f` > **parameters** > `from`: *Holder* whose tokens will be burned. > `amount`: Number of tokens to burn. @@ -740,6 +753,7 @@ by the `operator` address. *NOTE*: This function MUST NOT be called outside of a burn, send or [ERC20] transfer process. +> **identifier:** `75ab9782` > **parameters** > `operator`: Address which triggered the balance decrease (through sending or burning). > `from`: *Holder* whose tokens were sent. @@ -825,6 +839,7 @@ by the `operator` address. *NOTE*: This function MUST NOT be called outside of a mint, send or [ERC20] transfer process. +> **identifier:** `0023de29` > **parameters** > `operator`: Address which triggered the balance increase (through sending or minting). > `from`: *Holder* whose tokens were sent (or `0x0` for a mint). From 54051094c7014250111bcdae33170a45f3e6940e Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 8 Apr 2019 19:43:50 +0200 Subject: [PATCH 146/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 72f4e821..7f77b041 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -549,8 +549,6 @@ Nonetheless, the rules below MUST be respected when minting for a *recipient*: - The `data` and `operatorData` MUST be immutable during the entire mint process—hence the same `data` and `operatorData` MUST be used to call the `tokensReceived` hook and emit the `Minted` event. -- The `data` field MUST be empty. - The token contract MUST `revert` when minting in any of the following cases: - The resulting *recipient* balance after the mint is not a multiple of the *granularity* defined by the token contract. @@ -576,6 +574,10 @@ The token contract MAY mint tokens for multiple *recipients* at once. In this ca *NOTE*: Minting an amount of zero (`0`) tokens is valid and MUST be treated as a regular mint. +*NOTE*: While during a send or a burn, the data is provided by the *holder*, it is inapplicable for a mint. +In this case the data MAY be provided by the token contract or the *operator*, +for example to ensure a successful minting to a *holder* expecting specific data. + *NOTE*: The `operatorData` field contains information provided by the *operator*—similar to the data field in a regular ether send transaction. The `tokensReceived()` hooks MAY use the information to decide if it wish to reject the transaction. @@ -594,7 +596,7 @@ Indicate the minting of `amount` of tokens to the `to` address by the `operator` > `operator`: Address which triggered the mint. > `to`: Recipient of the tokens. > `amount`: Number of tokens minted. -> `data`: MUST be empty. +> `data`: Information provided for the *recipient*. > `operatorData`: Information provided by the *operator*. #### **Burning Tokens** From 429eb45d53f593c07a43f59d6f905692001b9170 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 9 Apr 2019 22:50:48 +0200 Subject: [PATCH 147/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 7f77b041..905e7576 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -27,7 +27,7 @@ when they receive tokens as well as to allow compatibility with already-deployed ## Motivation -This standard tries to improve the widely used [ERC20] token standard. +This standard tries to improve upon the widely used [ERC20] token standard. The main advantages of this standard are: 1. Uses the same philosophy as Ether in that tokens are sent with `send(dest, value, data)`. @@ -41,7 +41,7 @@ The main advantages of this standard are: (Rejection is done by `revert`ing in the hook function.) 4. The `tokensReceived` hook allows to send tokens to a contract and notify it in a single transaction, - unlike [ERC20] which require a double call (`approve`/`transferFrom`) to achieve this. + unlike [ERC20] which requires a double call (`approve`/`transferFrom`) to achieve this. 5. The holder can "authorize" and "revoke" operators which can send tokens on their behalf. These operators are intended to be verified contracts @@ -205,7 +205,7 @@ The following rules MUST be applied regarding the *granularity*: - The *granularity* value MUST be greater or equal to `1`. -- Any amount of tokens (in the internal denomination) minted, sent or burnt +- Any amount of tokens (in the internal denomination) minted, sent or burned MUST be a multiple of the *granularity* value. - Any operation that would result in a balance that's not a multiple of the *granularity* value @@ -823,7 +823,9 @@ If the *recipient* is a contract, which has not registered an `ERC777TokensRecip then the token contract: - MUST `revert` if the `tokensReceived` hook is called from a mint or send call. -- SHOULD accept if the `tokensReceived` hook is called from an ERC20 `transfer` or `transferFrom` call. + +- SHOULD continue processing the transaction + if the `tokensReceived` hook is called from an ERC20 `transfer` or `transferFrom` call. *NOTE*: A regular address MAY register a different address—the address of a contract—implementing the interface on its behalf. @@ -987,8 +989,8 @@ when sending, minting and transferring token via [ERC777] and [ERC20]: ERC777TokensRecipient
    not registered regular address - SHOULD accept - SHOULD accept + continue + continue contract From 7e97fb44239bb9eaf7be9ad1fd6d2eb3b31344f1 Mon Sep 17 00:00:00 2001 From: Lane Rettig Date: Thu, 11 Apr 2019 09:39:05 +1000 Subject: [PATCH 148/431] EIP-1890: Commitment to Sustainable Ecosystem Funding (#1890) * Create eip-credible_commitment.md * Update and rename eip-credible_commitment.md to eip-1890.md Assign EIP number --- EIPS/eip-1890.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 EIPS/eip-1890.md diff --git a/EIPS/eip-1890.md b/EIPS/eip-1890.md new file mode 100644 index 00000000..d4a6eb88 --- /dev/null +++ b/EIPS/eip-1890.md @@ -0,0 +1,53 @@ +--- +eip: 1890 +title: Commitment to Sustainable Ecosystem Funding +author: Gregory Markou , Kevin Owocki , Lane Rettig +discussions-to: https://t.me/joinchat/DwEd_xahL5hHvzNYH2RnQA +status: Draft +type: Standards Track +category: Core +created: 2019-03-31 +--- + +# Commitment to Sustainable Ecosystem Funding + +## Simple Summary + +Ethereum currently provides a block reward to proof of work miners every block, but it does not capture any block rewards for ecosystem funding. This EIP adds a simple mechanism for capturing a portion of block rewards for ecosystem funding as a credible commitment to doing so in future, but it does not actually capture any such rewards. + +## Abstract + +A mechanism that allows specification of two parameters, a beneficiary address and a per-block reward denominated in wei, that allows a portion of block rewards to be captured for the purpose of ecosystem funding. Both values are set to zero. + +## Motivation + +In order for Ethereum to succeed, it needs talented, motivated researchers and developers to continue to develop and maintain the platform. Those talented researchers and developers deserve to be paid fairly for their work. At present there is no mechanism in the Ethereum ecosystem that rewards R&D teams fairly for their work on the platform. + +We recognize that, while technically trivial, the real challenge in inflation-based funding is social: how to fairly capture, govern, and distribute block rewards. It will take time to work out the answer to these questions. For this reason, this EIP only seeks to make a credible commitment on the part of core developers to securing the funding they need to keep Ethereum alive and healthy by adding a mechanism to do so, but the actual amount of rewards captured remains at zero, i.e., there is no change at present to Ethereum’s economics. Raising the amount captured above zero would require a future EIP. + +## Specification + +Two new constants are introduced: BENEFICIARY_ADDRESS, an Address, and DEVFUND_BLOCK_REWARD, an amount denominated in wei. Both are set to zero. + +Beginning with block ISTANBUL_BLOCK_HEIGHT, DEVFUND_BLOCK_REWARD wei is added to the balance of BENEFICIARY_ADDRESS at each block. + +We may optionally add another constant, DECAY_FACTOR, which specifies a linear or exponenential decay factor that reduces the reward at every block > ISTANBUL_BLOCK_HEIGHT until it decays to zero. For simplicity, it has been omitted from this proposal. + +## Rationale + +We believe that the technical design of this EIP is straightforward. The social rationale is explained in [this article](https://medium.com/gitcoin/funding-open-source-in-the-blockchain-era-8ded753bf05f). + +## Backwards Compatibility + +This EIP has no impact on backwards compatibility. + +## Test Cases + +This EIP makes no changes to existing state transitions. Existing consensus tests should be sufficient. + +## Implementation + +Reference implementations are included for the Trinity, go-ethereum, and parity clients. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 3b49f68170dba97186a68cff51dde4afd6e8f55c Mon Sep 17 00:00:00 2001 From: Duncan Westland Date: Thu, 11 Apr 2019 23:27:00 +0100 Subject: [PATCH 149/431] First Draft for EIP-1922 (#1926) --- EIPS/eip-1922.md | 210 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 EIPS/eip-1922.md diff --git a/EIPS/eip-1922.md b/EIPS/eip-1922.md new file mode 100644 index 00000000..9742dd36 --- /dev/null +++ b/EIPS/eip-1922.md @@ -0,0 +1,210 @@ +--- +eip: 1922 +title: zk-SNARK Verifier Standard +author: Michael Connor , Chaitanya Konda , Duncan Westland +discussions-to: https://github.com/ethereum/EIPs/issues/1922 +type: Standards Track +category: ERC +status: Draft +created: 2018-09-14 +requires: 165, 196, 197 +--- + +## Simple Summary + +A standard interface for "Verifier" contracts which verify zk-SNARKs. + +## Abstract +The following standard allows for the implementation of a standard contract API for the verification of zk-SNARKs ("Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge"), also known as "proofs", "arguments", or "commitments". + +This standard provides basic functionality to load all necessary parameters for the verification of any zk-SNARK into a verifier contract, so that the proof may ultimately return a `true` or `false` response; corresponding to whether it has been verified or not verified. + +## Motivation +zk-SNARKs are a promising area of interest for the Ethereum community. Key applications of zk-SNARKs include: +- Private transactions +- Private computations +- Improved transaction scaling through proofs of "bundled" transactions + +A standard interface for verifying all zk-SNARKs will allow applications to more easily implement private transactions, private contracts, and scaling solutions; and to extract and interpret the limited information which gets emitted during zk-SNARK verifications. + +This standard was initially proposed by EY, and was inspired in particular by the requirements of businesses wishing to keep their agreements, transactions, and supply chain activities confidential—all whilst still benefiting from the commonly cited strengths of blockchains and smart contracts. + +:warning: TODO: Explain the benefits to and perspective of a consumer of information. I.e. the thing that interfaces with the standard verifier. + +## Specification +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. + +Terminology in this specification is used consistently with libsnark, as provided in that project's README. + +* Adhering Contract — A Verifier contract which adheres to this specification. +* Arithmetic circuit: An abstraction of logical statements into addition and multiplication gates. +* Public Inputs: often denoted as a vector 'x' in zk-SNARKs literature, and denoted `inputs` in this interface. An arithmetic circuit can be thought of as taking two parameters; the Public Inputs, 'x', and a secret 'witness', 'w'. This interface standardises functions which can load the `inputs` into an Adhering Contract. +* Proof: A 'prover' who wants to 'prove' knowledge of some secret witness 'w' (which satisfies an arithmetic circuit), generates a `proof` from: the circuit's Proving Key; their secret witness 'w'; and its corresponding Public Inputs 'x'. Together, a pair `(proof, inputs)` of satisfying `inputs` and their corresponding `proof` forms a zk-SNARK. +* Verification Key: A 'trusted setup' calculation creates both a public 'Proving Key' and a public 'Verification Key' from an arithmetic circuit. This interface does not provide a method for loading a Verification Key onto the blockchain. An Adhering Contract SHALL be able to accept arguments of knowledge (`(proof, inputs)` pairs) for at least one Verification Key. We shall call such Verification Keys 'in-scope' Verification Keys. An Adhering Contract MUST be able to interpret unambiguously a unique `verificationKeyId` for each of its 'in-scope' Verification Keys. + +**Every ERC-XXXX compliant verifier contract must implement the `ERCXXXX` and `ERC165` interfaces** (subject to "caveats" below): + + +```solidity +pragma solidity ^0.5.6; + +/// @title EIP-XXXX zk-SNARK Verifier Standard +/// @dev See https://github.com/EYBlockchain/zksnark-verifier-standard +/// Note: the ERC-165 identifier for this interface is 0xXXXXXXXX. +/// ⚠️ TODO: Calculate interface identifier +interface EIPXXXX /* is ERC165 */ { + /// @notice Checks the arguments of Proof, through elliptic curve + /// pairing functions. + /// @dev + /// MUST return `true` if Proof passes all checks (i.e. the Proof is + /// valid). + /// MUST return `false` if the Proof does not pass all checks (i.e. if the + /// Proof is invalid). + /// @param proof A zk-SNARK. + /// @param inputs Public inputs which accompany Proof. + /// @param verificationKeyId A unique identifier (known to this verifier + /// contract) for the Verification Key to which Proof corresponds. + /// @return result The result of the verification calculation. True + /// if Proof is valid; false otherwise. + function verify(uint256[] calldata proof, uint256[] calldata inputs, bytes32 verificationKeyId) external returns (bool result); +} +``` +### Interface +``` solidity +interface ERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} +``` + +## Rationale + + +### Taxonomy + +⚠️ TODO: Add a specific reference to libsnark here, explaining the choice of variable names. + +:warning: TODO: Explain how _C_ may not necessarilly be a satisfiable arithmetic circuit of logical statements. As current, this is a limitation to certain kinds of SNARKS. Whereas the source references also mention polynomials, and other applications. + +_C_ — A satisfiable arithmetic circuit abstraction of logical statements. + +_lambda​_ - A random number, generated at the 'setup' phase - commonly referred to as 'toxic waste', because knowledge of _lambda​_ would allow an untrustworthy party to create 'false' proofs which would verify as 'true'. _lambda​_ must be destroyed. + +_pk​_ - The proving key for a particular circuit _C​_. + +_vk_ - The verification key for a particular circuit _C_. + +Both _pk​_ and _vk​_ are generated as a pair by some function _G​_: +_(pk, vk) = G(lambda, C)​_ + +Note: _C_ can be represented unambiguously by either of _pk_ or _vk_. In zk-SNARK constructions, _vk_ is much smaller in size than _pk_, so as to enable succinct verification on-chain. Hence, _vk_ is the representative of _C_ that is 'known' to the contract. Therefore, we can identify each circuit uniquely through some `verificationKeyId`, where `verificationKeyId` serves as a more succinct mapping to _vk_. + +_w_ - A 'private witness' string. A private argument to the circuit _C_ known only to the prover, which, when combined with the `inputs` argument _x_, comprises an argument of knowledge which satisfies the circuit _C_. + +_x_ or `inputs` - A vector of 'Public Inputs'. A public argument to the circuit _C_ which, when combined with the private witness string _w_, comprises an argument of knowledge which satisfies the circuit _C_. + +_pi_ or `proof` - an encoded vector of values which represents the 'prover's' 'argument of knowledge' of values _w_ and _x_ which satisfy the circuit _C_. +_pi = P(pk, x, w)_. + +The ultimate purpose of a Verifier contract, as specified in this EIP, is to verify a proof (of the form _pi​_) through some verification function _V​_. + +_V(vk, x, pi) = 1_, if there exists a _w_ s.t. _C(x,w)=1_. +_V(vk, x, pi) = 0_, otherwise. + +The `verify()` function of this specification serves the purpose of _V​_; returning either `true` (the proof has been verified to satisfy the arithmetic circuit) or `false` (the proof has not been verified). + +### Functions + +#### `verify` +The `verify` function forms the crux this standard. The parameters are intended to be as generic as possible, to allow for verification of any zk-SNARK: + +- `proof` + Specified as `uint256[]`. + `uint256` is the most appropriate type for elliptic curve operations over a finite field. Indeed, this type is used in the predominant 'Pairing library' implementation of zk-SNARKs by Christian Reitweissner. + A one-dimensional dynamic array has been chosen for several reasons: + - Dynamic: There are several possible methods for producing a zk-SNARK proof, including PGHR13, G16, GM17, and future methods might be developed in future. Although each method may produce differently sized proof objects, a dynamic array allows for these differing sizes. + - Array: An array has been chosen over a 'struct' object, because it is currently easier to pass dynamic arrays between functions in Solidity. Any proof 'struct' can be 'flattened' to an array and passed to the `verify` function. Interpretation of that flattened array is the responsibility of the implemented body of the function. Example implementations demonstrate that this can be achieved. + - One-dimensional: A one-dimensional array has been chosen over multi-dimensional array, because it is currently easier to work with one-dimensional arrays in Solidity. Any proof can be 'flattened' to a one-dimensional array and passed to the `verify` function. Interpretation of that flattened array is the responsibility of the implemented body of the Adhering Contract. Example implementations demonstrate that this can be achieved. + +- `inputs` + Specified as `uint256[]`. + `uint256` is the most appropriate type for elliptic curve operations over a finite field. Indeed, this type is used in the predominant 'Pairing library' implementation of zk-SNARKs by Christian Reitweissner. + The number of inputs will vary in size, depending on the number of 'public inputs' of the arithmetic circuit being verified against. In a similar vein to the `proof` parameter, a one-dimensional dynamic array is general enough to cope with any set of inputs to a zk-SNARK. + +- `verificationKeyId` + A verification key (referencing a particular arithmetic circuit) only needs to be stored on-chain once. Any proof (relating to the underlying arithmetic circuit) can then be verified against that verification key. Given this, it would be unnecessary (from a 'gas cost' point of view) to pass a duplicate of the full verification key to the `verify` function every time a new `(proof, inputs)` pair is passed in. We do however need to tell the Adhering Verifier Contract which verification key corresponds to the `(proof, inputs)` pair being passed in. A `verificationKeyId` serves this purpose - it uniquely represents a verification key as a `bytes32` id. A method for uniquely assigning a `verificationKeyId` to a verification key is the responsibility of the implemented body of the Adhering Contract. + + +## Backwards Compatibility +- At the time this EIP was first proposed, there was one implementation on the Ethereum main net - deployed by [EY](https://www.ey.com). This was compiled with Solidity 0.4.24 for compatibility with [Truffle](https://github.com/trufflesuite/truffle) but otherwise compatible with this standard, which is presented at the latest current version of Solidity. +- Dr Christian Reitwiessner's excellent [example](https://gist.github.com/chriseth/f9be9d9391efc5beb9704255a8e2989d) of a Verifier contract and elliptic curve pairing library has been instrumental in the Ethereum community's experimentation and development of zk-SNARK protocols. Many of the naming conventions of this EIP have been kept consistent with his example. +- Existing zk-SNARK compilers such as [ZoKrates](https://github.com/Zokrates/ZoKrates), which produce 'Verifier.sol' contracts, do not currently produce Verifier contracts which adhere to this EIP specification. + - :warning: TODO: Provide a converter contract or technique which allows ZoKrates verifier.sol contracts to adhere with this EIP. + + +## Test Cases + + +Truffle tests of example implementations are included in the test case repository. + +⚠️ TODO: Reference specific test cases because there are many currently in the repository. + + +## Implementations + +Detailed example implementations and Truffle tests of these example implementations are included in this repository. + +:warning: TODO: Update referenced verifier implementations so that they are ready-to-deploy or reference deployed versions of those implementations. At current, the referenced code specifically states "DO NOT USE THIS IN PRODUCTION". + +:warning: TODO: Provide reference to an implementation which interrogates a standard verifier contract that implements this standard. + + +## References + +:warning: TODO: Update references and confirm that each reference is cited (parenthetical documentation not necessary) in the text. + +**Standards** + +1. ERC-20 Token Standard. https://eips.ethereum.org/EIPS/eip-20 + +1. ERC-165 Standard Interface Detection. https://eips.ethereum.org/EIPS/eip-165 +1. ERC-173 Contract Ownership Standard (DRAFT). https://eips.ethereum.org/EIPS/eip-173 +1. ERC-196 Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128. https://eips.ethereum.org/EIPS/eip-196 +1. ERC-197 Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128. https://eips.ethereum.org/EIPS/eip-197 +1. Ethereum Name Service (ENS). https://ens.domains +1. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt + +##### Educational material: zk-SNARKs +1. Zcash. What are zk-SNARKs? https://z.cash/technology/zksnarks.html +1. Vitalik Buterin. zk-SNARKs: Under the Hood. https://medium.com/@VitalikButerin/zk-snarks-under-the-hood-b33151a013f6 +1. Christian Reitweissner. zk-SNARKs in a Nutshell. https://blog.ethereum.org/2016/12/05/zksnarks-in-a-nutshell/ +1. Ben-Sasson, Chiesa, Tromer, et. al. Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture. https://eprint.iacr.org/2013/879.pdf + +##### Notable applications of zk-SNARKs + 1. EY. Implementation of a business agreement through Token Commitment transactions on the Ethereum mainnet. https://github.com/EYBlockchain/ZKPChallenge + 1. Zcash. https://z.cash + 1. Zcash. How Transactions Between Shielded Addresses Work. https://blog.z.cash/zcash-private-transactions/ + +##### Notable projects relating to zk-SNARKs + 1. libsnark: A C++ Library for zk-SNARKs ("project README)". https://github.com/scipr-lab/libsnark + 1. ZoKrates: Scalable Privacy-Preserving Off-Chain Computations. https://www.ise.tu-berlin.de/fileadmin/fg308/publications/2018/2018_eberhardt_ZoKrates.pdf + 1. ZoKrates Project Repository. https://github.com/JacobEberhardt/ZoKrates + 1. Joseph Stockermans. zkSNARKs: Driver's Ed. https://github.com/jstoxrocky/zksnarks_example + 1. Christian Reitweissner - snarktest.solidity. https://gist.github.com/chriseth/f9be9d9391efc5beb9704255a8e2989d + +##### Notable 'alternatives' to zk-SNARKs - areas of ongoing zero-knowledge proof research + 1. Vitalik Buterin. STARKs. https://vitalik.ca/general/2017/11/09/starks_part_1.html + 1. Bu ̈nz, Bootle, Boneh, et. al. Bulletproofs. https://eprint.iacr.org/2017/1066.pdf + 1. Range Proofs. https://www.cosic.esat.kuleuven.be/ecrypt/provpriv2012/abstracts/canard.pdf + 1. Apple. Secure Enclaves. https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/storing_keys_in_the_secure_enclave + 1. Intel Software Guard Extensions. https://software.intel.com/en-us/sgx + + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From e8a54cb5e43529207f76f746155fa120dc5e4363 Mon Sep 17 00:00:00 2001 From: Duncan Westland Date: Thu, 11 Apr 2019 23:28:01 +0100 Subject: [PATCH 150/431] First Draft for EIP-1923 (#1925) --- EIPS/eip-1923.md | 170 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 EIPS/eip-1923.md diff --git a/EIPS/eip-1923.md b/EIPS/eip-1923.md new file mode 100644 index 00000000..3c4f74e5 --- /dev/null +++ b/EIPS/eip-1923.md @@ -0,0 +1,170 @@ +--- +eip: 1923 +title: zk-SNARK Verifier Registry Standard +author: Michael Connor , Chaitanya Konda , Duncan Westland +discussions-to: https://github.com/ethereum/EIPs/issues/1923 +type: Standards Track +category: ERC +status: Draft +created: 2018-12-22 +requires: 165, 196, 197 +--- + +## Simple Summary + + +A standard interface for a "Verifier Registry"'" contract, through which all zk-SNARK verification activity can be registered. + +## Abstract +The following standard allows for the implementation of a standard contract API for the registration of zk-SNARKs ("Zero-Knowledge Succinct Non-Interactive Arguments of Knowledge"), also known as "proofs", "arguments", or "commitments". + +TODO: Which functionality is exposed in this standard interface? + +## Motivation +zk-SNARKs are a promising area of interest for the Ethereum community. Key applications of zk-SNARKs include: +- Private transactions +- Private computations +- Ethereum scaling through proofs of 'bundled' transactions + +A standard interface for registering all zk-SNARKs will allow applications to more easily implement private transactions, private contracts, and scaling solutions; and to extract and interpret the limited information which gets emitted during zk-SNARK verifications. + +:warning: TODO: Explain the motivation for standardizing a registry, other than simply standardizing the verifier interactions. + +⚠️ TODO: Explain the benefits to and perspective of a consumer of information. I.e. the thing that interfaces with the standard verifier registry. + +## Specification +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. + + +```solidity +pragma solidity ^0.5.6; + +/// @title EIP-XXXX zk-SNARK Verifier Registry Standard +/// @dev See https://github.com/EYBlockchain/zksnark-verifier-standard +/// Note: the ERC-165 identifier for this interface is 0xXXXXXXXXX. +/// ⚠️ TODO: Set the interface identifier +interface EIP-XXXX /* is ERC165 */ { + + event NewProofSubmitted(bytes32 indexed _proofId, uint256[] _proof, uint64[] _inputs); + + event NewVkRegistered(bytes32 indexed _vkId); + + event NewVerifierContractRegistered(address indexed _contractAddress); + + event NewAttestation(bytes32 indexed _proofId, address indexed _verifier, bool indexed _result); + + + function getVk(bytes32 _vkId) external returns (uint256[] memory); + + function registerVerifierContract(address _verifierContract) external returns (bool); + + function registerVk(uint256[] calldata _vk, address[] calldata _verifierContracts) external returns (bytes32); + + function submitProof(uint256[] calldata _proof, uint64[] calldata _inputs, bytes32 _vkId) external returns (bytes32); + + function submitProof(uint256[] calldata _proof, uint64[] calldata _inputs, bytes32 _vkId, address _verifierContract) external returns (bytes32); + + function submitProofAndVerify(uint256[] calldata _proof, uint64[] calldata _inputs, bytes32 _vkId, address _verifierContract) external returns (bytes32); + + function attestProof(bytes32 _proofId, bytes32 _vkId, bool _result) external; + + function attestProofs(bytes32[] calldata _proofIds, bytes32[] calldata _vkIds, bool[] calldata _results) external; + + function challengeAttestation(bytes32 _proofId, uint256[] calldata _proof, uint64[] calldata _inputs, address _verifierContract) external; + + function createNewVkId(uint256[] calldata _vk) external pure returns (bytes32); + + function createNewProofId(uint256[] calldata _proof, uint64[] calldata _inputs) external pure returns (bytes32); + +} +``` +### Interface +``` solidity +interface ERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} +``` + +## Rationale + + +⚠️ TODO: Add Rationale section. + +### Backwards Compatibility + + + +⚠️ TODO: Add Backwards Compatibility section. + +### Test Cases + + + +Truffle tests of example implementations are included in this Repo. + +⚠️ TODO: Reference specific test cases because there are many currently in the repository. + + +## Implementations + +Detailed example implementations and Truffle tests of these example implementations are included in this Repo. + +⚠️ TODO: Update referenced verifier registry implementations so that they are ready-to-deploy or reference deployed versions of those implementations. At current, the referenced code specifically states "DO NOT USE THIS IN PRODUCTION". + +⚠️ TODO: Provide reference to an implementation which interrogates a standard verifier registry contract that implements this standard. + + +## References + +⚠️ TODO: Update references and confirm that each reference is cited (parenthetical documentation not necessary) in the text. + +**Standards** + +1. ERC-20 Token Standard. https://eips.ethereum.org/EIPS/eip-20 + +1. ERC-165 Standard Interface Detection. https://eips.ethereum.org/EIPS/eip-165 +2. ERC-173 Contract Ownership Standard (DRAFT). https://eips.ethereum.org/EIPS/eip-173 +3. ERC-196 Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128. https://eips.ethereum.org/EIPS/eip-196 +4. ERC-197 Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128. https://eips.ethereum.org/EIPS/eip-197 +5. Ethereum Name Service (ENS). https://ens.domains +6. RFC 2119 Key words for use in RFCs to Indicate Requirement Levels. https://www.ietf.org/rfc/rfc2119.txt + +##### Educational material: zk-SNARKs + +1. Zcash. What are zk-SNARKs? https://z.cash/technology/zksnarks.html +2. Vitalik Buterin. zk-SNARKs: Under the Hood. https://medium.com/@VitalikButerin/zk-snarks-under-the-hood-b33151a013f6 +3. Christian Reitweissner. zk-SNARKs in a Nutshell. https://blog.ethereum.org/2016/12/05/zksnarks-in-a-nutshell/ +4. Ben-Sasson, Chiesa, Tromer, et. al. Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture. https://eprint.iacr.org/2013/879.pdf + +##### Notable applications of zk-SNARKs + +1. EY. Implementation of a business agreement through Token Commitment transactions on the Ethereum mainnet. https://github.com/EYBlockchain/ZKPChallenge +2. Zcash. https://z.cash +3. Zcash. How Transactions Between Shielded Addresses Work. https://blog.z.cash/zcash-private-transactions/ + +##### Notable projects relating to zk-SNARKs + +1. libsnark: A C++ Library for zk-SNARKs ("project README)". https://github.com/scipr-lab/libsnark +2. ZoKrates: Scalable Privacy-Preserving Off-Chain Computations. https://www.ise.tu-berlin.de/fileadmin/fg308/publications/2018/2018_eberhardt_ZoKrates.pdf +3. ZoKrates Project Repository. https://github.com/JacobEberhardt/ZoKrates +4. Joseph Stockermans. zkSNARKs: Driver's Ed. https://github.com/jstoxrocky/zksnarks_example +5. Christian Reitweissner - snarktest.solidity. https://gist.github.com/chriseth/f9be9d9391efc5beb9704255a8e2989d + +##### Notable 'alternatives' to zk-SNARKs - areas of ongoing zero-knowledge proof research + +1. Vitalik Buterin. STARKs. https://vitalik.ca/general/2017/11/09/starks_part_1.html +2. Bu ̈nz, Bootle, Boneh, et. al. Bulletproofs. https://eprint.iacr.org/2017/1066.pdf +3. Range Proofs. https://www.cosic.esat.kuleuven.be/ecrypt/provpriv2012/abstracts/canard.pdf +4. Apple. Secure Enclaves. https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/storing_keys_in_the_secure_enclave +5. Intel Software Guard Extensions. https://software.intel.com/en-us/sgx + + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 1a976beaa5ba29086afcbf71080c5b29b0fa3483 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 12 Apr 2019 15:06:13 +1200 Subject: [PATCH 151/431] Update eip-1577.md --- EIPS/eip-1577.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/EIPS/eip-1577.md b/EIPS/eip-1577.md index f16af8ed..bcd1467b 100644 --- a/EIPS/eip-1577.md +++ b/EIPS/eip-1577.md @@ -42,6 +42,8 @@ When resolving a `contenthash`, applications MUST use the protocol code to deter ### Example +#### IPFS + Input data: ``` @@ -65,6 +67,35 @@ Text format: ipfs://QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4 ``` +### Swarm + +Input data: + +``` +storage system: Swarm (0xe4) +CID version: 1 (0x01) +content type: swarm-manifest (0xfa) +hash function: keccak256 (0x1b) +hash length: 32 bytes (0x20) +hash: d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162 +``` + +Binary format: +``` +0xe40101fa011b20d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162 +``` + +Text format: +``` +bzz://d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162 +``` + +Example usage with swarm hash: +``` +$ swarm hash ens contenthash d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162 +> e40101fa011b20d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162 +``` + ### Fallback In order to support names that have an IPFS or Swarm hash in their `content` field, a grace period MUST be implemented offering those name holders time to update their names. If a resolver does not support the `multihash` interface, it MUST be checked whether they support the `content` interface. If they do, the value of that field SHOULD be treated in a context dependent fashion and resolved. This condition MUST be enforced until at least March 31st, 2019. From 018840a5e099a0830a3c51c3008657775f2fc05e Mon Sep 17 00:00:00 2001 From: Bryant Eisenbach Date: Thu, 11 Apr 2019 22:49:25 -0700 Subject: [PATCH 152/431] Automatically merged updates to draft EIP(s) 1344 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1344.md | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index e0b8db3c..155e8b90 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -8,9 +8,28 @@ type: Standards Track status: Draft created: 2018-08-22 --- - ### Specification - Adds a new opcode at 0x46, which takes 0 stack arguments. It will return the chain id of the chain where the block was mined. It should cost 2 gas (G_base) to execute this opcode. - ### Motivation - [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain id to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures. - The current approach proposed by [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) is to specify the chain id on compile time. Using this approach will result in problems after a hardfork. - By adding the opcode it would be possible to access the current chain id and validate signatures based on that. + +## Abstract +This EIP adds an opcode that returns the current chain's EIP-155 unique identifier. + +## Motivation +[EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain id to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures, especially for Layer 2 signature schemes using [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). + +## Specification +Adds a new opcode at 0x46, which takes 0 stack arguments. It will return the chain id of the chain where the block was mined. It should cost 2 gas (`G_base`) to execute this opcode. + +## Rationale +The current approach proposed by EIP-712 is to specify the chain id on compile time. Using this approach will result in problems after a hardfork, as well as human error that may lead to loss of funds or replay attacks on signed messages. +By adding the opcode it would be possible to access the current chain id and validate signatures based on that. + +## Backwards Compatibility +This EIP should be fully backwards compatible for all chains which implement EIP-155 chain ID domain separator for transaction signing. + +## Test Cases +TBD + +## Implementation +A sample implementation was attempted here: https://github.com/fubuloubu/py-evm/commit/eaab5ffa2164d4cc06ae5c855a49d030965be828 + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 8e5d8c2cc61e3f31bb72758c3470801aaa840584 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Sat, 13 Apr 2019 20:49:39 +0200 Subject: [PATCH 153/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 905e7576..8ec11a8b 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -1,6 +1,6 @@ --- eip: 777 -title: A New Advanced Token Standard +title: ERC777 Token Standard author: Jacques Dafflon , Jordi Baylina , Thomas Shababi discussions-to: https://github.com/ethereum/EIPs/issues/777 status: Draft @@ -194,7 +194,7 @@ function granularity() external view returns (uint256) Get the smallest part of the token that's not divisible. -In other words, the granularity is the smallest number of tokens (in the internal denomination) +In other words, the granularity is the smallest amount of tokens (in the internal denomination) which MAY be minted, sent or burned at any time. The following rules MUST be applied regarding the *granularity*: @@ -205,6 +205,8 @@ The following rules MUST be applied regarding the *granularity*: - The *granularity* value MUST be greater or equal to `1`. +- All balances MUST be a multiple of the granularity. + - Any amount of tokens (in the internal denomination) minted, sent or burned MUST be a multiple of the *granularity* value. From 05afb41d5629d37b636fbf1218837ed087761509 Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 16 Apr 2019 00:09:14 +0200 Subject: [PATCH 154/431] ERC777: Last Call (#1939) --- EIPS/eip-777.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 8ec11a8b..c4d54cdc 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -3,7 +3,8 @@ eip: 777 title: ERC777 Token Standard author: Jacques Dafflon , Jordi Baylina , Thomas Shababi discussions-to: https://github.com/ethereum/EIPs/issues/777 -status: Draft +status: Last Call +review-period-end: 2019-04-28 type: Standards Track category: ERC created: 2017-11-20 From d79403b090a6b4e02fd0d1cb9f9d4b03e29ff76d Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Tue, 16 Apr 2019 19:20:39 -0400 Subject: [PATCH 155/431] Automatically merged updates to draft EIP(s) 615 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 99 +++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index b870dd1e..3db860cf 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -4,7 +4,7 @@ title: Subroutines and Static Jumps for the EVM status: Draft type: Standards Track category: Core -author: Greg Colvin , Brooklyn Zelenka (@expede), Paweł Bylica (@chfast), Christian Reitwiessner (@chriseth) +author: Greg Colvin , Brooklyn Zelenka (@expede) , Paweł Bylica (@chfast), Christian Reitwiessner(@chriseth) discussions-to: https://ethereum-magicians.org/t/eip-615-subroutines-and-static-jumps-for-the-evm/2728 created: 2016-12-10 --- @@ -15,57 +15,63 @@ In the 21st century, on a blockchain circulating billions of ETH, formal specifi ## Abstract -EVM code is currently difficult to statically analyze, hobbling critical tools for preventing the many expensive bugs our blockchain has experienced. Further, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to reduce the need for precompiles and otherwise meet the network's long-term demands. This proposal identifies dynamic jumps as a major reason for these issues, and proposes changes to the EVM specification to address the problem, making further efforts towards a safer and more performant EVM possible. +EVM code is currently difficult to statically analyze, hobbling critical tools for preventing the many expensive bugs our blockchain has experienced. Further, none of the current implementations of the Ethereum Virtual Machine—including the compilers—are sufficiently performant to reduce the need for precompiles and otherwise meet the network's long-term demands. This proposal identifies dynamic jumps as a major reason for these issues, and proposes changes to the EVM specification to address the problem, making further efforts towards a safer and more performant the EVM possible. -We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. Well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. +We also propose to validate—in linear time—that EVM contracts correctly use subroutines, avoid misuse of the stack, and meet other safety conditions _before_ placing them on the blockchain. Validated code precludes most runtime exceptions and the need to test for them. And well-behaved control flow and use of the stack makes life easier for interpreters, compilers, formal analysis, and other tools. ## Motivation -Currently the EVM supports dynamic jumps, where the address to jump to is an argument on the stack. These dynamic jumps obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since many jumps can potentially be to any jump destination in the code, the number of possible paths through the code can go up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses. +Currently the EVM supports only dynamic jumps, where the address to jump to is an argument on the stack. Worse, the EVM fails to provide ordinary, alternative control flow facilities like subroutines and switches provided by Wasm and most CPUs. So dynamic jumps cannot be avoided, yet they obscure the structure of the code and thus mostly inhibit control- and data-flow analysis. This puts the quality and speed of optimized compilation fundamentally at odds. Further, since many jumps can potentially be to any jump destination in the code, the number of possible paths through the code can go up as the product of the number of jumps by the number of destinations, as does the time complexity of static analysis. Many of these cases are undecidable at deployment time, further inhibiting static and formal analyses. -Absent dynamic jumps code can be statically analyzed in linear time. Static analysis includes validation, and much of optimization, compilation, and formal analysis; every part of the tool chain benefits when linear-time analysis is available. And absent dynamic jumps, and with proper subroutines the EVM is a better target for code generation from other languages, including +However, given Ethereum's security requirements, **near-linear** **`n log n`** **time complexity** is essential. Otherwise, Contracts can be crafted or discovered with quadratic complexity to use as denial of service attack vectors against validations and optimizations. + +But absent dynamic jumps code can be statically analyzed in linear time. That allows for _linear time validation_. It also allows for code generation and such optimizations as can be done in `log n` time to comprise an _`n log n`_ _time compiler_. + +And absent dynamic jumps, and with proper subroutines the EVM is a better target for code generation from other languages, including * Solidity * Vyper * LLVM IR * front ends include C, C++, Common Lisp, D, Fortran, Haskell, Java, Javascript, Kotlin, Lua, Objective-C, Pony, Pure, Python, Ruby, Rust, Scala, Scheme, and Swift -The result is that all of the following validations and optimizations can be done at deployment time with **linear** **`(n)`** **or** **near-linear** **`(n log n)`** **time complexity** +The result is that all of the following validations and optimizations can be done at deployment time with near-linear `(n log n)` time complexity. * The absence of most exceptional halting states can be validated. -* The maximum use of resources can sometimes be calculated. +* The maximum use of resources can be sometimes be calculated. * Bytecode can be compiled to machine code. * Compilation can optimize use of smaller registers. * Compilation can optimize injection of gas metering. -Note that near-linear `(n log n)` time complexity is essential. Otherwise, specially crafted contracts can be used as attack vectors against any validations and optimizations. - ## Specification +### Dependencies + +> **[EIP-1702](https://github.com/ethereum/EIPs/pull/1702). Generalized Account Versioning Scheme.** This proposal needs a versioning scheme to allow for its bytecode (and eventually eWasm bytecode) to be deployed with existing bytecode on the same blockchain. + ### Proposal We propose to deprecate two existing instructions—`JUMP` and `JUMPI`—and propose new instructions to support their legitimate uses. In particular, it must remain possible to compile Solidity and Vyper code to EVM bytecode, with no significant loss of performance or increase in gas price. -Especially important is efficient translation to and from eWasm. To that end we maintain a close correspondence between eWasm instructions and proposed EVM instructions. +Especially important is efficient translation to and from [eWasm](https://github.com/ewasm/design) and to machine code. To that end we maintain a close correspondence between [Wasm](https://webassembly.github.io/spec/core/_download/WebAssembly.pdf), [x86](https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf), [ARM](https://static.docs.arm.com/100076/0100/arm_instruction_set_reference_guide_100076_0100_00_en.pdf) and proposed EVM instructions. -| Wasm | EIP-615 | -| -------- | -------- | -| br | JUMPTO | -| br_if | JUMPIF | -| br_table | JUMPV | -| call | JUMPSUB | -| call_indirect | JUMPSUBV | -| return | RETURN | -| local.get | GETLOCAL | -| local.put | PUTLOCAL | -| tables | DATA | +| EIP-615 | Wasm | x86 | ARM +| -------- | -------- | ----- | ----- +| JUMPTO | br | JMP | B +| JUMPIF | br_if | JE | BNZ +| JUMPV | br_table | JMP | TBH +| JUMPSUB | call | CALL | BL +| JUMPSUBV | call_indirect | CALL | BLX +| RETURN | return | RET | RET +| GETLOCAL | local.get | PUSH | POP +| PUTLOCAL | local.put | PUSH | POP +| BEGINDATA | tables | .DATA | .DATA #### Preliminaries These forms > *`INSTRUCTION`* > -> *`INSTRUCTION x`* +> *`INSTRUCTION x`* > -> *`INSTRUCTION x, y`* +> *`INSTRUCTION x, y`* name an *`INSTRUCTION`* with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) @@ -96,15 +102,15 @@ To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Br #### Switches, Callbacks, and Virtual Functions -Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. +Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. -Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements, and are implemented as instructions similar to this one on most CPUs. +Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements. Wasm and most CPUs provide similar instructions. > `JUMPV n, jump_targets` > > jumps to one of a vector of `n` `JUMPDEST` offsets via a zero-based index on the stack. The vector is stored inline at the `jump_targets` offset after the BEGINDATA bytecode as MSB-first, two's-complement, two-byte positive integers. If the index is greater than or equal to `n - 1` the last (default) offset is used. -Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take just two pointer dereferences on most CPUs. +Dynamic jumps to a `BEGINSUB` are used to implement `O(1)` virtual functions and callbacks, which take at most two pointer dereferences on most CPUs. Wasm provides a similar instruction. > `JUMPSUBV n, jump_targets` > @@ -132,6 +138,12 @@ There needs to be a way to place unreachable data into the bytecode that will be > > specifies that all of the following bytes to the end of the bytecode are data, and not reachable code. +#### Structure + +Valid EIP-615 EVM bytecode begins with a valid header. This is the magic number ‘\evm’ followed by the semantic versioning number '\1\5\0\0'. (For Wasm the header is '\0asm\1'). + +Following the header is the BEGINSUB opcode for the _main_ routine. It takes no arguments and returns no values. Other subroutines may follow the _main_ routine, and an optional BEGINDATA opcode may mark the start of a data section. + ### Semantics Jumps to and returns from subroutines are described here in terms of @@ -149,11 +161,11 @@ We will adopt the following conventions to describe the machine state: * The _stack items_ between the frame pointer and the current stack pointer are called the _frame_. * The current number of items in the frame, `FP - SP`, is the _frame size_. -Defining the frame pointer so as to include the arguments is unconventional, but better fits our stack semantics and simplifies the remainder of the proposal. +> **Note**: Defining the frame pointer so as to include the arguments is unconventional, but better fits our stack semantics and simplifies the remainder of the proposal. The frame pointer and return stacks are internal to the subroutine mechanism, and not directly accessible to the program. This is necessary to prevent the program from modifying its own state in ways that could be invalid. -The first instruction of an array of EVM bytecode begins execution of a _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack—`code_size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV`—that is, in the _main_ routine—executes a `STOP`.) +Execution of EVM bytecode begins with the _main_ routine with no arguments, `SP` and `FP` set to 0, and with one value on the return stack—`code_size - 1`. (Executing the virtual byte of 0 after this offset causes an EVM to stop. Thus executing a `RETURNSUB` with no prior `JUMPSUB` or `JUMBSUBV`—that is, in the _main_ routine—executes a `STOP`.) Execution of a subroutine begins with `JUMPSUB` or `JUMPSUBV`, which @@ -181,7 +193,7 @@ frame | 21 ______|___________ 22 <- SP ``` -and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` +and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` ``` PUSH 10 PUSH 11 @@ -244,7 +256,7 @@ _Execution_ is as defined in the [Yellow Paper](https://ethereum.github.io/yello >**5** Invalid instruction -We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. +We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. To handle the return stack we expand the conditions on stack size: >**2a** The size of the data stack does not exceed 1024. @@ -278,7 +290,7 @@ All of the remaining conditions we validate statically. #### Costs & Codes -All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` should be _verylow_. Measurement will tell. +All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` and the rest should be _verylow_. Measurement will tell. We suggest the following opcodes: ``` @@ -299,9 +311,11 @@ We suggest the following opcodes: These changes would need to be implemented in phases at decent intervals: >**1.** If this EIP is accepted, invalid code should be deprecated. Tools should stop generating invalid code, users should stop writing it, and clients should warn about loading it. ->**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely. +>**2.** A later hard fork would require clients to place only valid code on the block chain. Note that despite the fork old EVM code will still need to be supported indefinitely; older contracts will continue to run, and to create new contracts. -If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying phase 2. Since we must continue to run old code this is not technically difficult. +If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying or canceling phase 2. + +Regardless, we will need a versioning scheme like [EIP-1702](https://github.com/ethereum/EIPs/pull/1702) to allow current code and EIP-615 code to coexist on the same blockchain. ## Rationale @@ -311,7 +325,9 @@ As described above, the approach was simply to deprecate the problematic dynamic ## Implementation -Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. Compiled code can use native call instructions, greatly improving performance. Further optimizations include minimizing runtime checks for exceptions, condensing gas metering, and otherwise taking advantage of validated code wherever possible. A lightly tested reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) +Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. The bulk of the effort is the validator, which in most languages can almost be transcribed from the pseudocode above. + +A lightly tested C++ reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) This version required circa 110 lines of new interpreter code and a well-commented, 178-line validator. ## Appendix A ### Validation @@ -330,7 +346,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_sub[code_size] // is there a BEGINSUB at PC? is_dest[code_size] // is there a JUMPDEST at PC? sub_for_pc[code_size] // which BEGINSUB is PC in? - + bool validate_jumps(PC) { current_sub = PC @@ -350,7 +366,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_dest[PC] = true sub_for_pc[PC] = current_sub } - + // check that targets are in subroutine for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC)) { @@ -374,7 +390,7 @@ Note that code like this is already run by EVMs to check dynamic jumps, includin #### Subroutine Validation -This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`: The sum of the number of edges and number of verticies in the graph. +This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|): The sum of the number of edges and number of verticies in the graph. The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. @@ -424,7 +440,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t return false if instruction is STOP, RETURN, or SUICIDE - return true + return true // violates single entry if instruction is BEGINSUB @@ -447,10 +463,10 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t if instruction is JUMPTO { PC = jump_target(PC) - continue + continue } - // recurse to jump to code to validate + // recurse to jump to code to validate if instruction is JUMPIF { if not validate_subroutine(jump_target(PC), return_pc, SP) @@ -470,7 +486,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t ## Appendix B ### EVM Analysis -There is a large and growing ecosystem of researchers, authors, teachers, auditors, and analytic tools--providing software and services focused on the correctness and security of EVM code. A small saample is given here. +There is a large and growing ecosystem of researchers, authors, teachers, auditors, and analytic tools--providing software and services focused on the correctness and security of EVM code. A small sample is given here. #### Some Tools @@ -498,6 +514,7 @@ There is a large and growing ecosystem of researchers, authors, teachers, audito * [Securify: Practical Security Analysis of Smart Contracts](https://arxiv.org/pdf/1806.01143.pdf) * [The Thunder Protocol](https://docs.thundercore.com/thunder-whitepaper.pdf) * [Towards Verifying Ethereum Smart Contract Bytecode in Isabelle/HOL](https://ts.data61.csiro.au/publications/csiro_full_text//Amani_BBS_18.pdf) +*[A Lem formalization of EVM 1.5](https://github.com/seed/eth-isabelle/tree/evm15) ## Copyright From a38ba29b6071f9602a3aa345bf19412874becb7e Mon Sep 17 00:00:00 2001 From: Bryant Eisenbach Date: Tue, 16 Apr 2019 18:15:51 -0700 Subject: [PATCH 156/431] EIP-1344: Move to Last Call (#1944) * EIP-1344: Move to Last Call Also added @fubuloubu as an author due to previous work * bug: Add review-period-end --- EIPS/eip-1344.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index 155e8b90..5d55c0d6 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -1,12 +1,13 @@ --- eip: 1344 title: ChainID opcode -author: Richard Meissner (@rmeissner) +author: Richard Meissner (@rmeissner), Bryant Eisenbach (@fubuloubu) discussions-to: https://ethereum-magicians.org/t/add-chain-id-opcode-for-replay-protection-when-handling-signed-messages-in-contracts/1131 category: Core type: Standards Track -status: Draft +status: Last Call created: 2018-08-22 +review-period-end: 2019-04-30 --- ## Abstract From 78a371aa40a980e9a32e69fa3fe0857bc6e2d9f4 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 17 Apr 2019 10:29:19 -0400 Subject: [PATCH 157/431] Automatically merged updates to draft EIP(s) 1344 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1344.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index 5d55c0d6..24786029 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -26,6 +26,9 @@ By adding the opcode it would be possible to access the current chain id and val ## Backwards Compatibility This EIP should be fully backwards compatible for all chains which implement EIP-155 chain ID domain separator for transaction signing. +## References +This was previously suggested as part of [EIP901](https://github.com/ethereum/EIPs/issues/901). + ## Test Cases TBD From f6ccc0a7f51f44bfe127fb28f09faeb1c376eb1e Mon Sep 17 00:00:00 2001 From: William Entriken Date: Fri, 19 Apr 2019 12:07:10 -0400 Subject: [PATCH 158/431] Automatically merged updates to draft EIP(s) 1344 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1344.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index 24786029..55d54fcf 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -14,17 +14,17 @@ review-period-end: 2019-04-30 This EIP adds an opcode that returns the current chain's EIP-155 unique identifier. ## Motivation -[EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain id to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures, especially for Layer 2 signature schemes using [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). +[EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain ID to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures, especially for Layer 2 signature schemes using [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). ## Specification -Adds a new opcode at 0x46, which takes 0 stack arguments. It will return the chain id of the chain where the block was mined. It should cost 2 gas (`G_base`) to execute this opcode. +Adds a new opcode `CHAINID` at 0x46, which uses 0 stack arguments. It will push the current chain ID onto the stack. The operation costs `G_base` to execute. ## Rationale -The current approach proposed by EIP-712 is to specify the chain id on compile time. Using this approach will result in problems after a hardfork, as well as human error that may lead to loss of funds or replay attacks on signed messages. -By adding the opcode it would be possible to access the current chain id and validate signatures based on that. +The current approach proposed by EIP-712 is to specify the chain ID at compile time. Using this approach will result in problems after a hardfork, as well as human error that may lead to loss of funds or replay attacks on signed messages. +By adding the proposed opcode it will be possible to access the current chain ID and validate signatures based on that. ## Backwards Compatibility -This EIP should be fully backwards compatible for all chains which implement EIP-155 chain ID domain separator for transaction signing. +This EIP is fully backwards compatible with all chains which implement EIP-155 chain ID domain separator for transaction signing. ## References This was previously suggested as part of [EIP901](https://github.com/ethereum/EIPs/issues/901). From 0dd8be2a10c5b4a882d0ef36112238d346b414d2 Mon Sep 17 00:00:00 2001 From: Bryant Eisenbach Date: Fri, 19 Apr 2019 10:35:04 -0700 Subject: [PATCH 159/431] Automatically merged updates to draft EIP(s) 1344 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1344.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index 55d54fcf..57f89c65 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -23,6 +23,10 @@ Adds a new opcode `CHAINID` at 0x46, which uses 0 stack arguments. It will push The current approach proposed by EIP-712 is to specify the chain ID at compile time. Using this approach will result in problems after a hardfork, as well as human error that may lead to loss of funds or replay attacks on signed messages. By adding the proposed opcode it will be possible to access the current chain ID and validate signatures based on that. +Currently, there is no specification for how chain ID is set for a particular network, relying on choices made manually by the client implementers and the chain community. There is a potential scenario where, during a "contentious split" over a divisive issue, a community using a particular value of chain ID will make a decision to split into two such chains. When this scenario occurs, it will be unsafe to maintain chain ID to the same value on both chains, as chain ID is used for replay protection for in-protocol transactions (per EIP-155), as well as for L2 and "meta-transaction" use cases (per EIP-712 as enabled by this proposal). There are two potential resolutions in this scenario under the current process: 1) one chain decides to modify their value of chain ID (while the other keeps it), or 2) both chains decide to modify their value of chain ID. + +In order to mitigate this situation, users of the proposed `CHAINID` opcode **must** ensure that their application can handle a potential update to the value of chain ID during their usage of their application in case this does occur, if required for the continued use of the application. A Trustless Oracle that logs the timestamp when a change is made to chain ID can be implemented either as an application-level feature inside the application contract system, or referenced as a globally standard contract. Failure to provide a mitigation for this scenario could lead to a sudden loss of legitimacy of previously signed off-chain messages, which could be an issue during settlement periods and other longer-term verification events for these types of messages. Not all applications of this opcode may need mitigations to handle this scenario, but developers should provide reasoning on a case-by-case basis. + ## Backwards Compatibility This EIP is fully backwards compatible with all chains which implement EIP-155 chain ID domain separator for transaction signing. From e0331e484f1127941538e34e9e8ded29a8230550 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Mon, 22 Apr 2019 10:51:50 -0700 Subject: [PATCH 160/431] Automatically merged updates to draft EIP(s) 1898 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1898.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1898.md b/EIPS/eip-1898.md index 7ea8da1a..49681053 100644 --- a/EIPS/eip-1898.md +++ b/EIPS/eip-1898.md @@ -38,11 +38,17 @@ Since there is no way to clearly distinguish between a DATA parameter and a QUAN - `blockNumber`: QUANTITY - a block number - `blockHash`: DATA - a block hash -To maintain backwards compatibility, the block number may be specified either as a hex string or using the new block parameter scheme. In other words, the following are equivalent for the default block parameter: +If the block is not found, the callee SHOULD raise a JSON-RPC error (the recommended error code is `-32001: Resource not found`). + +If the tag is `blockHash`, an additional boolean field may be supplied to the block parameter, `requireCanonical`, which defaults to `false` and defines whether the block must be a canonical block according to the callee. If `requireCanonical` is `false`, the callee should raise a JSON-RPC error only if the block is not found (as described above). If `requireCanonical` is `true`, the callee SHOULD additionally raise a JSON-RPC error if the block is not in the canonical chain (the recommended error code is `-32000: Invalid input` and in any case should be different than the error code for the block not found case so that the caller can distinguish the cases). The block-not-found check SHOULD take precedence over the block-is-canonical check, so that if the block is not found the callee raises block-not-found rather than block-not-canonical. + +To maintain backwards compatibility, the block number MAY be specified either as a hex string or using the new block parameter scheme. In other words, the following are equivalent for the default block parameter: - `"earliest"` - `"0x0"` - `{ "blockNumber": "0x0" }` - `{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" }` (hash of the genesis block on the Ethereum main chain) +- `{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true }` +- `{ "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false }` ## Rationale @@ -61,6 +67,17 @@ Backwards compatible. ## Test Cases +- `eth_getStorageAt [ "0x

    ", { "blockNumber": "0x0" }` -> return storage at given address in genesis block +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" }` -> return storage at given address in genesis block +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false }` -> return storage at given address in genesis block +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true }` -> return storage at given address in genesis block +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0x" }` -> raise block-not-found error +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0x", "requireCanonical": false }` -> raise block-not-found error +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0x", "requireCanonical": true }` -> raise block-not-found error +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0x" }` -> return storage at given address in specified block +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0x", "requireCanonical": false }` -> return storage at given address in specified block +- `eth_getStorageAt [ "0x
    ", { "blockHash": "0x", "requireCanonical": true }` -> raise block-not-canonical error + ## Implementation None yet. From 9577bb7868f641941a099d935b97ed12f72647e7 Mon Sep 17 00:00:00 2001 From: Boris Mann Date: Tue, 23 Apr 2019 06:46:18 -0700 Subject: [PATCH 161/431] Automatically merged updates to draft EIP(s) 1679, 233 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 22 +++++++++++-- EIPS/eip-233.md | 84 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 5236fb84..688930ee 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -16,11 +16,29 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - Codename: Istanbul - Activation: TBD -- Included EIPs: TBD + +### Included EIPs + +- TBD + +### Accepted EIPs + +- TBD + +### Proposed EIPs + +- TBD + +## Timeline + +* 2019-05-17 (Fri) hard deadline to accept proposals for "Istanbul" +* 2019-07-19 (Fri) soft deadline for major client implementations +* 2019-08-14 (Wed) projected date for testnet network upgrade (Ropsten, Görli, or ad-hoc testnet) +* 2019-10-16 (Wed) projected date for mainnet upgrade ("Istanbul") ## References -TBA +- [Core Dev call notes](https://github.com/ethereum/pm/issues/66#issuecomment-450840440) where timeline was proposed and accepted ## Copyright diff --git a/EIPS/eip-233.md b/EIPS/eip-233.md index dd6877f2..e3d34eed 100644 --- a/EIPS/eip-233.md +++ b/EIPS/eip-233.md @@ -18,13 +18,89 @@ Today discussions about hard forks happen at various forums and sometimes in ad- ## Specification -A Meta EIP should be created and merged as a *Draft* as soon as a new hard fork is planned. This EIP should contain: +A Meta EIP should be created and merged as a *Draft* as soon as a new hard fork is planned. + +This EIP should contain: - the desired codename of the hard fork, -- list of all the EIPs included in the hard fork and -- activation block number once decided and +- activation block number once decided +- a timeline section +- an EIPs to include section - the **Requires** header should point to the previous hard fork meta EIP. -The draft shall be updated with summaries of the decisions around the hard fork. It should move in to the `Accepted` state once the changes are frozen (i.e. all referenced EIPs are in the `Accepted` state) and in to the `Final` state once the hard fork has been activated. +The draft shall be updated with summaries of the decisions around the hard fork. + +### Timeline + +Once a timeline with key dates is agreed upon for other crucial dates. The basic outline of a hardfork timeline should include: +* Hard deadline to accept proposals for this hard fork +* Soft deadline for major client implementations +* Projected date for testnet network upgrade +* Projected date for mainnet upgrade (the activation block number / projected date for this block) + +### EIP Inclusion Process + +Anyone that wishes to propose a Core EIP for the hard fork should make a PR against the Meta EIP representing the hard fork. The EIP must be published as at least `Draft`. It enters the _Proposed EIPs_ section, along with at least one person who is a point of contact for wanting to include the EIP. + +Once the EIP has been accepted by Core Devs, the EIP should be moved to the _Accepted EIPs_ section. If the EIP has major client implementations and no security issues by the timeline date, it is scheduled for inclusion. + +--- + +The Meta EIP representing the hard fork should move in to the `Accepted` state once the changes are frozen (i.e. all referenced EIPs are in the `Accepted` state) and in to the `Final` state once the hard fork has been activated. + +## Template + +A template for the [Istanbul Hardfork Meta 1679](https://eips.ethereum.org/EIPS/eip-1679) is included below ([source file on Github](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1679.md)): + +``` +{% raw %} +--- +eip: 1679 +title: "Hardfork Meta: Istanbul" +author: Alex Beregszaszi (@axic), Afri Schoedon (@5chdn) +type: Meta +status: Draft +created: 2019-01-04 +requires: 1716 +--- + +## Abstract + +This meta-EIP specifies the changes included in the Ethereum hardfork named Istanbul. + +## Specification + +- Codename: Istanbul +- Activation: TBD + +### Included EIPs + +- TBD + +### Accepted EIPs + +- TBD + +### Proposed EIPs + +- TBD + +## Timeline + +* 2019-05-17 (Fri) hard deadline to accept proposals for "Istanbul" +* 2019-07-19 (Fri) soft deadline for major client implementations +* 2019-08-14 (Wed) projected date for testnet network upgrade (Ropsten, Görli, or ad-hoc testnet) +* 2019-10-16 (Wed) projected date for mainnet upgrade ("Istanbul") + +## References + +- TBD (e.g. link to Core Dev notes or other references) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +{% endraw %} +``` ## Rationale From 783317614aa5ffc7872eb24b7f2212363a943f6a Mon Sep 17 00:00:00 2001 From: Bryant Eisenbach Date: Wed, 24 Apr 2019 04:28:38 -0400 Subject: [PATCH 162/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 688930ee..cce201d0 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -27,7 +27,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista ### Proposed EIPs -- TBD +- [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode ## Timeline From 3e04ff2189e62a685718fc409522ce940f1d6035 Mon Sep 17 00:00:00 2001 From: Nick Gheorghita Date: Wed, 24 Apr 2019 19:29:36 +0200 Subject: [PATCH 163/431] Minor updates to EIP-1319 (#1966) --- EIPS/eip-1319.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/EIPS/eip-1319.md b/EIPS/eip-1319.md index 21d42440..e51788ee 100644 --- a/EIPS/eip-1319.md +++ b/EIPS/eip-1319.md @@ -60,7 +60,7 @@ Implementations are free to choose any scheme for generating a **releaseId**. A function generateReleaseId(string packageName, string version) public view - returns (bytes32) + returns (bytes32 releaseId) { return keccak256(abi.encodePacked(packageName, version)); } @@ -114,21 +114,21 @@ The read API consists of a set of methods that allows tooling to extract all con function getAllPackageIds(uint offset, uint limit) public view returns ( bytes32[] packageIds, - uint offset + uint pointer ); // Retrieves the unique string `name` associated with a package's id. -function getPackageName(bytes32 packageId) public view returns (string name); +function getPackageName(bytes32 packageId) public view returns (string packageName); // Retrieves the registry's unique identifier for an existing release of a package. -function getReleaseId(string packageName, string version) public view returns (bytes32); +function getReleaseId(string packageName, string version) public view returns (bytes32 releaseId); // Retrieves a slice of the list of all release ids for a package. // `offset` and `limit` enable paginated responses / retrieval of the complete set. (See note below) function getAllReleaseIds(string packageName, uint offset, uint limit) public view returns ( - bytes32[] ids, - uint offset + bytes32[] releaseIds, + uint pointer ); // Retrieves package name, release version and URI location data for a release id. @@ -144,7 +144,7 @@ function getReleaseData(bytes32 releaseId) public view function generateReleaseId(string packageName, string version) public view - returns (bytes32); + returns (bytes32 releaseId); // Returns the total number of unique packages in a registry. function numPackageIds() public view returns (uint totalCount); @@ -154,7 +154,7 @@ function numReleaseIds(string packageName) public view returns (uint totalCount) ``` **Pagination** -`getAllPackageIds` and `getAllReleaseIds` support paginated requests because it's possible that the return values for these methods could become quite large. The methods should return an `offset` that is a pointer to the next available item in a list of all items such that a caller can use it to pick up from where the previous request left off. (See [here](https://mixmax.com/blog/api-paging-built-the-right-way) for a discussion of the merits and demerits of various pagination strategies.) The `limit` parameter defines the maximum number of items a registry should return per request. +`getAllPackageIds` and `getAllReleaseIds` support paginated requests because it's possible that the return values for these methods could become quite large. The methods should return a `pointer` that points to the next available item in a list of all items such that a caller can use it to pick up from where the previous request left off. (See [here](https://mixmax.com/blog/api-paging-built-the-right-way) for a discussion of the merits and demerits of various pagination strategies.) The `limit` parameter defines the maximum number of items a registry should return per request. ## Rationale The proposal hopes to accomplish the following: From d4efb6c4d3d1aa70b554d32486a5f9d1140c9991 Mon Sep 17 00:00:00 2001 From: AlexandreBelling Date: Wed, 24 Apr 2019 19:49:37 +0200 Subject: [PATCH 164/431] EIP-1895: Support for an Elliptic Curve Cycle (#1895) --- EIPS/eip-1895.md | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 EIPS/eip-1895.md diff --git a/EIPS/eip-1895.md b/EIPS/eip-1895.md new file mode 100644 index 00000000..4067b3a5 --- /dev/null +++ b/EIPS/eip-1895.md @@ -0,0 +1,164 @@ +--- +eip: 1895 +title: Support for an Elliptic Curve Cycle +author: Alexandre Belling +discussions-to: https://ethresear.ch/t/reducing-the-verification-cost-of-a-snark-through-hierarchical-aggregation/5128 +status: Draft +type: Standards Track +category: Core +created: 2018-31-03 +--- + +## Simple Summary + +The EVM currently supports elliptic curves operations for curve *alt-bn128* thanks to precompiles `ecadd` and `ecmul` and `ecpairing`. The classes MNT4 and 6 contain cycles of curves. Those cycles enable doing operations on one curve inside a SNARK on the other curve (and reversely). This EIP suggests adding support for those curves. + +## Abstract + +Adds supports for the following operations through precompiles: + +* `ecadd` on MNT4 +* `ecmul` on MNT4 +* `ecpairing` on MNT4 + +## Motivation + +Elliptic curve is the basic block of recursive SNARKs (ie: verifying a SNARK inside a SNARK) and this addresses the issue of scalable zero-knowledge. More generally this addresses partly the scalability issue as SNARKs verification are constant time in the size of the circuit being verified. + +More concretely, today if the EVM has to deal with 1000s of SNARK verification it would take around 1.5 billion gas and would be impractical for Ethereum. Recursive SNARKs for instance make it possible to aggregate multiple proofs into a single one that can be verified like any other SNARK. It results in a massive cost reduction for the verification. + +However, this is impossible using *alt-bn128* and in my knowledge, the only family of pairing-friendly curves known to produce cycles are MNT4 and MNT6. A complete characterization of the cycles existing between those two families is proposed in [On cycles of pairing-friendly elliptic curves +](https://arxiv.org/pdf/1803.02067.pdf) + +## Specification + +### The curve + +The proposed cycle has been introduced in [Scalable Zero Knowledge via Cycles of Elliptic Curves](https://eprint.iacr.org/2014/595.pdf). + +### MNT4 definition + +The groups `G_1` and `G_2` are cyclic groups of prime order : + +```. +q = 475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137 +``` + +`G_1` is defined over the field `F_p` of prime order : + +```. +p = 475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081 +``` + +with generator P: + +```. +P = ( + 60760244141852568949126569781626075788424196370144486719385562369396875346601926534016838, + 363732850702582978263902770815145784459747722357071843971107674179038674942891694705904306 +) +``` + +Both p and q can be written in 298 bits. + +The group G_1 is defined on the curve defined by the equation `Y² = X³ + aX + b` where: + +```. + a = 2 + b = 423894536526684178289416011533888240029318103673896002803341544124054745019340795360841685 +``` + +The twisted group G_2 is defined over the field `F_p^2 = F_p / <>` + +The twisted group G_2 is defined on the curve defined by the equation `Y² = X² + aX + b` where : + +```. + a = 34 + i * 0 + b = 0 + i * 67372828414711144619833451280373307321534573815811166723479321465776723059456513877937430 +``` + +G_2 generator is generated by : + +```. + P2 = ( + 438374926219350099854919100077809681842783509163790991847867546339851681564223481322252708 + + i * 37620953615500480110935514360923278605464476459712393277679280819942849043649216370485641, + 37437409008528968268352521034936931842973546441370663118543015118291998305624025037512482 + + i * 424621479598893882672393190337420680597584695892317197646113820787463109735345923009077489 + ) +``` + +### The operations and gas cost + +The following operations and their gas cost would be implemented + +```. +MNT_X_ADD = <> +MNT_X_MUL = <> +MNT_X_PAIRING = <> +``` + +Where `X` is either 4. + +### Encoding + +The curves points P(X, Y) over F_p are represented in their compressed form C(X, Y): + +```. + C = X | s +``` + +where `s` represents `Y` as follow: + +```. + | `s'` | `Y` | + |--------|--------------------------| + | `0x00` | Point at infinity | + | `0x02` | Solution with `y` even | + | `0x03` | Solution with `y` odd | +``` + +Compression operation from affine coordinate is trivial: + +```. + s = 0x02 | (s & 0x01) +``` + +In the EVM the compressed form allows us to represents curve points with 2 uint256 instead of 3. + +### Edge cases + +* Several acceptable representations for the point at infinity + +## Rationale + +The curve has 80 bits of security (whereas MNT6 has 120 bits) which might not be considered enough for critical security level, (for instance transfering several billions), but enough for others. If it turns out this is not enough security for adoption, there is another option : another cycle is being used by Coda but is defined over a 753 bits sized field which might also be prohibitively low (no reference to this curve from Coda's publications found). + +Independently of the cycle chosen, the groups and field elements are represented with integers larger than 256 bits (even for the 80 bits of security), therefore it might be necessary to also add support for larger field size operations. + +We currently don't know more efficient pairing-friendly cycles and don't know if there are. It might be possible to circumvent this problem though by relaxing the constraint that all the curves of the cycle must be pairing friendly). If we had a cycle with only one pairing friendly curve we would still be able to compose proofs by alternating between SNARKs and any other general purpose zero-knowledge cryptosystems. + +Assuming we find a convenient cycle, we don't need to implement support for all the curves it contains, only one. The best choice would be the fastest one as the overall security of the recursive snark do not depends on which curve the verification is made. + +Proper benchmarks will be done in order to make this choice and to price the operations in gas. + +## Test Cases + + + +## References + +* *Eli-Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, [BCTV14], April 28, 2015, Scalable Zero Knowledge via Cycles of Elliptic Curves : https://eprint.iacr.org/2014/595.pdf* +* *Alessandro Chiesa, Lynn Chua, Matthew Weidner, [CCW18], November 5, 2018, On cycles of pairing-friendly elliptic curves : https://arxiv.org/pdf/1803.02067.pdf* + +## Implementation + + + +* [go-boojum](https://github.com/AlexandreBelling/go-boojum) : A PoC demo of an application of recursive SNARKs +* [libff](https://github.com/scipr-lab/libff) : a C++ library for finite fields and elliptic curves +* [coda](https://github.com/CodaProtocol/coda) : a new cryptocurrency protocol with a lightweight, constant sized blockchain. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 0fd0e5aed7d17ddbe5d22b7907bcf8ad12d42c07 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Apr 2019 16:15:15 +0100 Subject: [PATCH 165/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index cce201d0..f50d3d6d 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -2,6 +2,7 @@ eip: 1679 title: "Hardfork Meta: Istanbul" author: Alex Beregszaszi (@axic), Afri Schoedon (@5chdn) +discussions-to: https://ethereum-magicians.org/t/hardfork-meta-istanbul-discussion/3207 type: Meta status: Draft created: 2019-01-04 From e7dac5b8287106143d361b1de3704ce0bba31983 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 26 Apr 2019 16:38:51 +0100 Subject: [PATCH 166/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index f50d3d6d..88039f4b 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -29,6 +29,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista ### Proposed EIPs - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode +- [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts ## Timeline From 66d8fc8741a9b7cb7e2ce72caaddc088147f1b9b Mon Sep 17 00:00:00 2001 From: Lee Raj Date: Sat, 27 Apr 2019 02:12:12 -0400 Subject: [PATCH 167/431] Scalable Rewards (#1973) * added EIP * spacing * reorder * reorder * formats * <> brackets * edit * eip number * renaminng --- EIPS/eip-1973.md | 271 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 EIPS/eip-1973.md diff --git a/EIPS/eip-1973.md b/EIPS/eip-1973.md new file mode 100644 index 00000000..ed108da1 --- /dev/null +++ b/EIPS/eip-1973.md @@ -0,0 +1,271 @@ +--- +eip: 1973 +title: Scalable Rewards +author: Lee Raj (@lerajk), Qin Jian (@qinjian) +type: Standards Track +category: ERC +status: Draft +created: 2019-04-01 +--- + +## Simple Summary + + A mintable token rewards interface that mints 'n' tokens per block which are distributed equally among the 'm' participants in the DAPP's ecosystem. + +## Abstract + + The mintable token rewards interface allows DApps to build a token economy where token rewards are distributed equally among the active participants. The tokens are minted based on per block basis that are configurable (E.g. 10.2356 tokens per block, 0.1 token per block, 1350 tokens per block) and the mint function can be initiated by any active participant. The token rewards distributed to each participant is dependent on the number of participants in the network. At the beginning, when the network has low volume, the tokens rewards per participant is high but as the network scales the token rewards decreases dynamically. + + + ## Motivation + +Distributing tokens through a push system to a large amount of participants fails due to block gas limit. As the number of participants in the network grow to tens of thousands, keeping track of the iterable registry of participants and their corresponding rewards in a push system becomes unmanagable. E.g. Looping through 5000 addresses to distribute 0.0000001 reward tokens is highly inefficient. Furthermore, the gas fees in these transactions are high and needs to be undertaken by the DApp developer or the respective company, leading to centralization concerns. + +A pull system is required to keep the application completely decentralized and to avoid the block gas limit problem. However, no standard solution has been proposed to distribute scalable rewards to tens of thousands participants with a pull system. This is what we propose with this EIP through concepts like TPP, round mask, participant mask. + +## Specification + +### Definitions + + `token amount per participant in the ecosytem or TPP (token per participant)`: TPP = (token amount to mint / total active participants) + + `roundMask`: the cummulative snapshot of TPP over time for the token contract. E.g. transactionOne = 10 tokens are minted with 100 available participants (TPP = 10 / 100) , transactionTwo = 12 tokens are minted with 95 participants (TPP = 12 / 95 ) + + roundMask = (10/100) + (12/95) + + `participantMask`: is used to keep track of a `msg.sender` (participant) rewards over time. When a `msg.sender` joins or leaves the ecosystem, the player mask is updated + + participantMask = previous roundMask OR (current roundMask - TPP) + + `rewards for msg.sender`: roundMask - participantMask + + E.g. Let's assume a total of 6 transactions (smart contract triggers or functions calls) are in place with 10 exising participants (denominator) and 20 tokens (numerator) are minted per transaction. At 2nd transaction, the 11th participant joins the network and exits before 5th transaction, the 11th participant's balance is as follows: + + ``` + t1 roundMask = (20/10) + t2 roundMask = (20/10) + (20/11) + t3 roundMask = (20/10) + (20/11) + (20/11) + t4 roundMask = (20/10) + (20/11) + (20/11) + (20/11) + t5 roundMask = (20/10) + (20/11) + (20/11) + (20/11)+ (20/10) + t6 roundMask = (20/10) + (20/11) + (20/11) + (20/11)+ (20/10) + (20/10) + ``` + + Total tokens released in 6 transactions = 60 tokens + + As the participant joins at t2 and leaves before t5, the participant deserves the rewards between t2 and t4. When the participant joins at t2, the 'participantMask = (20/10)', when the participant leaves before t5, the cummulative deserved reward tokens are : + + rewards for msg.sender: `[t4 roundMask = (20/10) + (20/11)+ (20/11) + (20/11)] - [participantMask = (20/10)] = [rewards = (20/11)+ (20/11) + (20/11)]` + + When the same participant joins the ecosystem at a later point (t27 or t35), a new 'participantMask' is given that is used to calculate the new deserved reward tokens when the participant exits. This process continues dynamically for each participant. + + `tokensPerBlock`: the amount of tokens that will be released per block + + `blockFreezeInterval`: the number of blocks that need to pass until the next mint. E.g. if set to 50 and 'n' tokens were minted at block 'b', the next 'n' tokens won't be minted until 'b + 50' blocks have passed + + `lastMintedBlockNumber`: the block number on which last 'n' tokens were minted + + `totalParticipants` : the total number of participants in the DApp network + + `tokencontractAddress` : the contract address to which tokens will be minted, default is address(this) + +``` +SOLIDITY + +pragma solidity ^0.5.2; + +import "openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol"; +import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol"; + +contract Rewards is ERC20Mintable, ERC20Detailed { + +using SafeMath for uint256; + +uint256 public roundMask; +uint256 public lastMintedBlockNumber; +uint256 public totalParticipants = 0; +uint256 public tokensPerBlock; +uint256 public blockFreezeInterval; +address public tokencontractAddress = address(this); +mapping(address => uint256) public participantMask; + +/** + * @dev constructor, initilizes variables. + * @param _tokensPerBlock The amount of token that will be released per block, entered in wei format (E.g. 1000000000000000000) + * @param _blockFreezeInterval The amount of blocks that need to pass (E.g. 1, 10, 100) before more tokens are brought into the ecosystem. + */ + constructor(uint256 _tokensPerBlock, uint256 _blockFreezeInterval) public ERC20Detailed("Simple Token", "SIM", 18){ +lastMintedBlockNumber = block.number; +tokensPerBlock = _tokensPerBlock; +blockFreezeInterval = _blockFreezeInterval; +} + +/** + * @dev Modifier to check if msg.sender is whitelisted as a minter. + */ +modifier isAuthorized() { +require(isMinter(msg.sender)); +_; +} + +/** + * @dev Function to add participants in the network. + * @param _minter The address that will be able to mint tokens. + * @return A boolean that indicates if the operation was successful. + */ +function addMinters(address _minter) external returns (bool) { +_addMinter(_minter); +totalParticipants = totalParticipants.add(1); +updateParticipantMask(_minter); +return true; +} + + +/** + * @dev Function to remove participants in the network. + * @param _minter The address that will be unable to mint tokens. + * @return A boolean that indicates if the operation was successful. + */ +function removeMinters(address _minter) external returns (bool) { +totalParticipants = totalParticipants.sub(1); +_removeMinter(_minter); +return true; +} + + +/** + * @dev Function to introduce new tokens in the network. + * @return A boolean that indicates if the operation was successful. + */ +function trigger() external isAuthorized returns (bool) { +bool res = readyToMint(); +if(res == false) { +return false; +} else { +mintTokens(); +return true; +} +} + +/** + * @dev Function to withdraw rewarded tokens by a participant. + * @return A boolean that indicates if the operation was successful. + */ +function withdraw() external isAuthorized returns (bool) { +uint256 amount = calculateRewards(); +require(amount >0); +ERC20(tokencontractAddress).transfer(msg.sender, amount); +} + +/** + * @dev Function to check if new tokens are ready to be minted. + * @return A boolean that indicates if the operation was successful. + */ +function readyToMint() public view returns (bool) { +uint256 currentBlockNumber = block.number; +uint256 lastBlockNumber = lastMintedBlockNumber; +if(currentBlockNumber > lastBlockNumber + blockFreezeInterval) { +return true; +} else { +return false; +} +} + +/** + * @dev Function to calculate current rewards for a participant. + * @return A uint that returns the calculated rewards amount. + */ +function calculateRewards() private returns (uint256) { +uint256 playerMask = participantMask[msg.sender]; +uint256 rewards = roundMask.sub(playerMask); +updateParticipantMask(msg.sender); +return rewards; +} + +/** + * @dev Function to mint new tokens into the economy. + * @return A boolean that indicates if the operation was successful. + */ +function mintTokens() private returns (bool) { +uint256 currentBlockNumber = block.number; +uint256 tokenReleaseAmount = (currentBlockNumber.sub(lastMintedBlockNumber)).mul(tokensPerBlock); +lastMintedBlockNumber = currentBlockNumber; +mint(tokencontractAddress, tokenReleaseAmount); +calculateTPP(tokenReleaseAmount); +return true; +} + + /** +* @dev Function to calculate TPP (token amount per participant). +* @return A boolean that indicates if the operation was successful. +*/ +function calculateTPP(uint256 tokens) private returns (bool) { +uint256 tpp = tokens.div(totalParticipants); +updateRoundMask(tpp); +return true; +} + + /** +* @dev Function to update round mask. +* @return A boolean that indicates if the operation was successful. +*/ +function updateRoundMask(uint256 tpp) private returns (bool) { +roundMask = roundMask.add(tpp); +return true; +} + + /** +* @dev Function to update participant mask (store the previous round mask) +* @return A boolean that indicates if the operation was successful. +*/ +function updateParticipantMask(address participant) private returns (bool) { +uint256 previousRoundMask = roundMask; +participantMask[participant] = previousRoundMask; +return true; +} + +} +``` + +## Rationale + +Currently, there is no standard for a scalable reward distribution mechanism. In order to create a sustainable cryptoeconomic environment within DAPPs, incentives play a large role. However, without a scalable way to distribute rewards to tens of thousands of participants, most DAPPs lack a good incentive structure. The ones with a sustainable cryptoeconomic environment depend heavily on centralized servers or a group of selective nodes to trigger the smart contracts. But, in order to keep an application truly decentralized, the reward distribution mechanism must depend on the active participants itself and scale as the number of participants grow. This is what this EIP intends to accomplish. + +## Backwards Compatibility + +Not Applicable. + +## Test Cases + +WIP, will be added. + +## Implementation + +WIP, a proper implementation will be added later.A sample example is below: + +`etherscan rewards contract` : https://ropsten.etherscan.io/address/0x8b0abfc541ab7558857816a67e186221adf887bc#tokentxns + +`Step 1` : deploy Rewards contract with the following parameters_tokensPerBlock = 1e18, _blockFreezeInterval = 1 + +`Step 2` : add Alice(0x123) and Bob(0x456) as minters, addMinters(address _minter) + +`Step 3` : call trigger() from Alice / Bob's account. 65 blocks are passed, hence 65 SIM tokens are minted. The RM is 32500000000000000000 + +`Step 4` : Alice withdraws and receives 32.5 SIM tokens (65 tokens / 2 participants) and her PM = 32500000000000000000 + +`Step 5` : add Satoshi(0x321) and Vitalik(0x654) as minters, addMinters(address _minter) + +`Step 6` : call trigger() from Alice / Bob's / Satoshi / Vitalik account. 101 blocks are passed, hence 101 SIM tokens are minted. The RM is 57750000000000000000 + +`Step 7` : Alice withdraws and receives 25.25 SIM tokens (101 tokens / 4 participants) and her PM = 57750000000000000000 + +`Step 8` : Bob withdraws and receives 57.75 SIM tokens ((65 tokens / 2 participants) + (101 tokens / 4 participants)). Bob's PM = 57750000000000000000 + +## Copyright + +Copyright and related rights waived via CC0. + +## References + +1. Scalable Reward Distribution on the Ethereum Blockchain by Bogdan Batog, Lucian Boca and Nick Johnson + +2. Fomo3d DApp, https://fomo3d.hostedwiki.co/ \ No newline at end of file From 988ed8d548b88101dba1657b2f8e86575eb3978f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 27 Apr 2019 15:55:23 +0200 Subject: [PATCH 168/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 88039f4b..f363c13a 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -30,6 +30,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts +- [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme ## Timeline From 0f98e038fd346ac91708c4ad5fc78713bcab9a5b Mon Sep 17 00:00:00 2001 From: econoar Date: Mon, 29 Apr 2019 01:20:21 -0500 Subject: [PATCH 169/431] EIP-1559: Fee market change for ETH 1.0 chain (#1943) --- EIPS/eip-1559.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 EIPS/eip-1559.md diff --git a/EIPS/eip-1559.md b/EIPS/eip-1559.md new file mode 100644 index 00000000..c91120dc --- /dev/null +++ b/EIPS/eip-1559.md @@ -0,0 +1,74 @@ +--- +eip: 1559 +title: Fee market change for ETH 1.0 chain +authors: Vitalik Buterin (@vbuterin), Eric Conner (@econoar) +discussions-to: https://ethereum-magicians.org/t/eip-1559-fee-market-change-for-eth-1-0-chain/2783 +status: Draft +type: Standard +category: Core +created: 2019-04-13 +--- + + + +## Simple Summary + +The current "first price auction" fee model in Ethereum is inefficient and needlessly costly to users. This EIP proposes a way to replace this with a mechanism that adjusts a base network fee based on network demand, creating better fee price efficiency and reducing the complexity of client software needed to avoid paying unnecessarily high fees. + +## Abstract + +There is a BASEFEE value in protocol, which can move up or down by a maximum of 1/8 in each block; initially, miners adjust this value to target an average gas usage of 8 million, increasing BASEFEE if usage is higher and decreasing it if usage is lower. Transaction senders specify their fees by providing two values: + +* A "premium" gasprice which gets added onto the BASEFEE gasprice, which can either be set to a fairly low value (eg. 1 gwei) to compensate miners for uncle rate risk or to a high value to compete during sudden bursts of activity. The BASEFEE gets burned, the premium is given to the miner. + +* A "cap" which represents the maximum total that the transaction sender would be willing to pay to get included. + +## Motivation + +Ethereum currently prices transaction fees using a simple auction mechanism, where users send transactions with bids ("gasprices") and miners choose transactions with the highest bids, and transactions that get included pay the bid that they specify. This leads to several large sources of inefficiency: + +* **Mismatch between volatility of transaction fee levels and social cost of transactions**: transaction fees on mature public blockchains, that have enough usage so that blocks are full, tend to be extremely volatile. On Ethereum, minimum fees are typically around 2 gwei (10^9 gwei = 1 ETH), but sometimes go up to 20-50 gwei and have even on one occasion gone up to over 200 gwei: https://etherscan.io/chart/gasprice. This clearly creates many inefficiencies, because it's absurd to suggest that the cost incurred by the network from accepting one more transaction into a block actually is 100x more when gas prices are 200 gwei than when they are 2 gwei; in both cases, it's a difference between 8 million gas and 8.02 million gas. +* **Needless delays for users**: because of the hard per-block gas limit coupled with natural volatility in transaction volume, transactions often wait for several blocks before getting included, but this is socially unproductive; no one significantly gains from the fact that there is no "slack" mechanism that allows one block to be bigger and the next block to be smaller to meet block-by-block differences in demand. +* **Inefficiencies of first price auctions**: see https://ethresear.ch/t/first-and-second-price-auctions-and-improved-transaction-fee-markets/2410 for a detailed writeup. In short, the current approach, where transaction senders publish a transaction with a fee, miners choose the highest-paying transactions, and everyone pays what they bid, is well-known in mechanism design literature to be highly inefficient, and so complex fee estimation algorithms are required, and even these algorithms often end up not working very well, leading to frequent fee overpayment. See also https://blog.bitgo.com/the-challenges-of-bitcoin-transaction-fee-estimation-e47a64a61c72 for a Bitcoin core developer's description of the challenges involved in fee estimation in the status quo. +* **Instability of blockchains with no block reward**: in the long run, blockchains where there is no issuance (including Bitcoin and Zcash) at present intend to switch to rewarding miners entirely through transaction fees. However, there are [known results](http://randomwalker.info/publications/mining_CCS.pdf) showing that this likely leads to a lot of instability, incentivizing mining "sister blocks" that steal transaction fees, opening up much stronger selfish mining attack vectors, and more. There is at present no good mitigation for this. + +The proposal in this EIP is to start with a BASEFEE amount which is adjusted up and down by the protocol based on how congested the network is. To accommodate this system, the network capacity would be increased to 16 million gas, so that 50% utilization matches up with our current 8 million gas limit. Then, when the network is at >50% capacity, the BASEFEE increments up slightly and when capacity is at <50%, it decrements down slightly. Because these increments are constrained, the maximum difference in BASEFEE from block to block is predictable. This then allows wallets to auto-set the gas fees for users in a highly reliable fashion. It is expected that most users will not have to manually adjust gas fees, even in periods of high network activity. For most users, the BASEFEE will be automatically set by their wallet, along with the addition of a small fixed amount, called a ‘tip’, to compensate miners (e.g. 0.5 gwei). + +An important aspect of this upgraded fee system is that miners only get to keep the tips. The BASEFEE is always burned (i.e. it is destroyed by the protocol). Burning this is important because it prevents miners from manipulating the fee in order to extract more fees from users. It also ensures that only ETH can ever be used to pay for transactions on Ethereum, cementing the economic value of ETH within the Ethereum platform. + + +## Specification + +**Parameters** +* `FORK_BLKNUM`: TBD +* `BASEFEE_MAX_CHANGE_DENOMINATOR`: 8 +* `SLACK_COEFFICIENT`: 3 +* `TARGET_GASUSED`: 8,000,000 + + +**Proposal** +For all blocks where `block.number >= FORK_BLKNUM`: + +* Impose a hard in-protocol gas limit of `SLACK_COEFFICIENT * TARGET_GASUSED`, used instead of the gas limit calculated using the previously existing formulas +* Replace the `GASLIMIT` field in the block header with a BASEFEE field (the same field can be used) +* Let `PARENT_BASEFEE` be the parent block's `BASEFEE` (or 1 billion wei if `block.number == FORK_BLKNUM`). A valid `BASEFEE` is one such that `abs(BASEFEE - PARENT_BASEFEE) <= max(1, PARENT_BASEFEE // BASEFEE_MAX_CHANGE_DENOMINATOR)` +* Redefine the way the `tx.gasprice` field is used: define `tx.fee_premium = tx.gasprice // 2**128` and `tx.fee_cap = tx.gasprice % 2**128` +* During transaction execution, we calculate the cost to the `tx.origin` and the gain to the `block.coinbase` as follows: + * Let `gasprice = min(BASEFEE + tx.fee_premium, tx.fee_cap)`. The `tx.origin` initially pays `gasprice * tx.gas`, and gets refunded `gasprice * (tx.gas - gasused)`. + * The `block.coinbase` gains `(gasprice - BASEFEE) * gasused`. If `gasprice < BASEFEE` (due to the `fee_cap`), this means that the `block.coinbase` _loses_ funds from this operation; in this case, check that the post-balance is non-negative and throw an exception if it is negative. +As a default strategy, miners set `BASEFEE` as follows. Let `delta = block.gas_used - TARGET_GASUSED` (possibly negative). Set `BASEFEE = PARENT_BASEFEE + PARENT_BASEFEE * delta // TARGET_GASUSED // BASEFEE_MAX_CHANGE_DENOMINATOR`, clamping this result inside of the allowable bounds if needed (with the parameter setting above clamping will not be required). + +## Backwards Compatibility +Transactions published before this EIP or by wallets that do not support this EIP will be interpreted by the above formulas as having a `fee_premium` of zero and a `fee_cap` of the fee that they submit. Provided that at least some miners are temporarily willing to be altruistic and accept zero-fee-premium transactions for a short period of time after the fork, this should not greatly affect usability. There is an invariant that a `gasprice` constructed "the old way" still constitutes an upper bound on the amount that a user will pay. + + +## Test Cases + + + +## Implementation + + + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 4d8e8fa46edc0841ede1681c6f589f929c2a221e Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 29 Apr 2019 07:36:55 +0100 Subject: [PATCH 170/431] Automatically merged updates to draft EIP(s) 1884 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1884.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1884.md b/EIPS/eip-1884.md index 1a1f64da..19faa357 100644 --- a/EIPS/eip-1884.md +++ b/EIPS/eip-1884.md @@ -7,6 +7,7 @@ category: Core discussions-to: https://ethereum-magicians.org/t/opcode-repricing/3024 status: Draft created: 2019-03-28 +requires: 150 --- @@ -33,8 +34,8 @@ If operations are well-balanced, we can maximise the block gaslimit and have a m At block `N`, -- The `SLOAD` operation changes from `200` to `800` gas, -- The `BALANCE` operation changes from `400` to `700` gas, +- The `SLOAD` (`0x54`) operation changes from `200` to `800` gas, +- The `BALANCE` (`0x31`) operation changes from `400` to `700` gas, - A new opcode, `SELFBALANCE` is introduced at `0x46`. - `SELFBALANCE` pops `0` arguments off the stack, - `SELFBALANCE` pushes the `balance` of the current address to the stack, @@ -47,7 +48,7 @@ Here are two charts, taken from a full sync using Geth. The execution time was m ![bars1](../assets/eip-1884/run3.total-bars-5.png) ![bars2](../assets/eip-1884/run3.total-bars-6.png) -Note: It can also be seen that the `SLOAD` moves towards the top position. The `GASPRICE` opcode has position one which I believe can be optimized away within the client -- which is not the case with `SLOAD`/`BALANCE`. +Note: It can also be seen that the `SLOAD` moves towards the top position. The `GASPRICE` (`0x3a`) opcode has position one which I believe can be optimized away within the client -- which is not the case with `SLOAD`/`BALANCE`. Here is another chart, showing a full sync with Geth. It represents the blocks `0` to `5.7M`, and highlights what the block processing time is spent on. From 31a12ca4ccdec35f2c6ea72c012ca7bd9e52829b Mon Sep 17 00:00:00 2001 From: Nick Savers Date: Mon, 29 Apr 2019 08:41:58 +0200 Subject: [PATCH 171/431] Fix authors and type-fields in eip-1559.md (#1974) --- EIPS/eip-1559.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1559.md b/EIPS/eip-1559.md index c91120dc..4dec83e8 100644 --- a/EIPS/eip-1559.md +++ b/EIPS/eip-1559.md @@ -1,10 +1,10 @@ --- eip: 1559 title: Fee market change for ETH 1.0 chain -authors: Vitalik Buterin (@vbuterin), Eric Conner (@econoar) +author: Vitalik Buterin (@vbuterin), Eric Conner (@econoar) discussions-to: https://ethereum-magicians.org/t/eip-1559-fee-market-change-for-eth-1-0-chain/2783 status: Draft -type: Standard +type: Standards Track category: Core created: 2019-04-13 --- From c3e063c8ffb4b1c3ba5737f898aea70aad47c183 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 29 Apr 2019 09:49:36 +0200 Subject: [PATCH 172/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index f363c13a..52e4f896 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -31,6 +31,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme +- [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes ## Timeline From e1ed3eb66f4ff9e519b3904d8c29fde0d180ce75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 29 Apr 2019 15:42:41 +0200 Subject: [PATCH 173/431] Automatically merged updates to draft EIP(s) 1344 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1344.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index 57f89c65..1bea3780 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -17,10 +17,10 @@ This EIP adds an opcode that returns the current chain's EIP-155 unique identifi [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md) proposes to use the chain ID to prevent replay attacks between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling signatures, especially for Layer 2 signature schemes using [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). ## Specification -Adds a new opcode `CHAINID` at 0x46, which uses 0 stack arguments. It will push the current chain ID onto the stack. The operation costs `G_base` to execute. +Adds a new opcode `CHAINID` at 0x46, which uses 0 stack arguments. It pushes the current chain ID onto the stack. The operation costs `G_base` to execute. ## Rationale -The current approach proposed by EIP-712 is to specify the chain ID at compile time. Using this approach will result in problems after a hardfork, as well as human error that may lead to loss of funds or replay attacks on signed messages. +The current approach proposed by EIP-712 is to specify the chain ID at compile time. Using this approach will result in problems after a hardfork, as well as human error that may lead to loss of funds or replay attacks on signed messages. By adding the proposed opcode it will be possible to access the current chain ID and validate signatures based on that. Currently, there is no specification for how chain ID is set for a particular network, relying on choices made manually by the client implementers and the chain community. There is a potential scenario where, during a "contentious split" over a divisive issue, a community using a particular value of chain ID will make a decision to split into two such chains. When this scenario occurs, it will be unsafe to maintain chain ID to the same value on both chains, as chain ID is used for replay protection for in-protocol transactions (per EIP-155), as well as for L2 and "meta-transaction" use cases (per EIP-712 as enabled by this proposal). There are two potential resolutions in this scenario under the current process: 1) one chain decides to modify their value of chain ID (while the other keeps it), or 2) both chains decide to modify their value of chain ID. From 86a1620c4abea3012787b7b45070d0eb2f106441 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Mon, 29 Apr 2019 09:38:22 -0600 Subject: [PATCH 174/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 52e4f896..7e27d649 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -28,6 +28,12 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista ### Proposed EIPs +- [EIP-1057](https://eips.ethereum.org/EIPS/eip-1344): ProgPoW, a Programmatic + Proof-of-Work + - There is a + [pending audit](https://medium.com/ethereum-cat-herders/progpow-audit-goals-expectations-75bb902a1f01), + above and beyond standard security considerations, that should be evaluated + prior to inclusion. - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme From 09e56171a8f64ac21c5a11c1a764332e693d96bb Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Mon, 29 Apr 2019 23:52:54 +0200 Subject: [PATCH 175/431] Automatically merged updates to draft EIP(s) 777 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index c4d54cdc..460482f2 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -4,7 +4,7 @@ title: ERC777 Token Standard author: Jacques Dafflon , Jordi Baylina , Thomas Shababi discussions-to: https://github.com/ethereum/EIPs/issues/777 status: Last Call -review-period-end: 2019-04-28 +review-period-end: 2019-05-06 type: Standards Track category: ERC created: 2017-11-20 From 72fa017d2f43b586fe029b8f54eb79778a26a292 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 09:45:06 +0100 Subject: [PATCH 176/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 7e27d649..a6f9bd68 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -28,7 +28,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista ### Proposed EIPs -- [EIP-1057](https://eips.ethereum.org/EIPS/eip-1344): ProgPoW, a Programmatic +- [EIP-1057](https://eips.ethereum.org/EIPS/eip-1057): ProgPoW, a Programmatic Proof-of-Work - There is a [pending audit](https://medium.com/ethereum-cat-herders/progpow-audit-goals-expectations-75bb902a1f01), From 132ef7be628e4eb73c16f95e23f211f000e1449b Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 10:27:35 +0100 Subject: [PATCH 177/431] Automatically merged updates to draft EIP(s) 1679 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index a6f9bd68..f29042ca 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -36,6 +36,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista prior to inclusion. - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts +- [EIP-1380](https://eips.ethereum.org/EIPS/eip-1380): Reduced gas cost for call to self - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme - [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes From 71fdaa7828be5c0c14f27e3af6839a7f98f658d2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 21:46:14 +0100 Subject: [PATCH 178/431] Remove obsolete layer field (#1978) --- EIPS/eip-4.md | 1 - EIPS/eip-6.md | 1 - 2 files changed, 2 deletions(-) diff --git a/EIPS/eip-4.md b/EIPS/eip-4.md index 75272712..666436bc 100644 --- a/EIPS/eip-4.md +++ b/EIPS/eip-4.md @@ -1,6 +1,5 @@ --- eip: 4 -layer: Process title: EIP Classification author: Joseph Chow status: Draft diff --git a/EIPS/eip-6.md b/EIPS/eip-6.md index ea1b1032..3e097521 100644 --- a/EIPS/eip-6.md +++ b/EIPS/eip-6.md @@ -5,7 +5,6 @@ author: Hudson Jameson status: Final type: Standards Track category: Interface -layer: Applications created: 2015-11-22 --- From f4cdc2313c4ee031efa6bddf21387d92a6b5629b Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 21:46:40 +0100 Subject: [PATCH 179/431] Document eip_validator and eip-automerger (#1977) --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index c313bcde..03278d56 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ When you believe your EIP is mature and ready to progress past the draft phase, - **For all other EIPs**, open a PR changing the state of your EIP to 'Final'. An editor will review your draft and ask if anyone objects to its being finalised. If the editor decides there is no rough consensus - for instance, because contributors point out significant issues with the EIP - they may close the PR and request that you fix the issues in the draft before trying again. # EIP Status Terms + * **Draft** - an EIP that is undergoing rapid iteration and changes. * **Last Call** - an EIP that is done with its initial iteration and ready for review by a wide audience. * **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP wil move to final. @@ -32,3 +33,17 @@ When you believe your EIP is mature and ready to progress past the draft phase, # Preferred Citation Format The canonical URL for a EIP that has achieved draft status at any point is at https://eips.ethereum.org/. For example, the canonical URL for ERC-165 is https://eips.ethereum.org/EIPS/eip-165. + +# Validation + +EIPs must pass some validation tests. The EIP repository ensures this by running tests using [html-proofer](https://rubygems.org/gems/html-proofer) and [eip_validator](https://rubygems.org/gems/eip_validator). + +It is possible to run the EIP validator locally: +``` +gem install eip_validator +eip_validator +``` + +# Automerger + +The EIP repository contains an "auto merge" feature to ease the workload for EIP editors. If a change is made via a PR to a draft EIP, then the authors of the EIP can Github approve the change to have it auto-merged by the [eip-automerger](https://github.com/eip-automerger/automerger) bot. From c36b30176e37c55ab845b10bc7c9523f9e04d1e7 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 21:54:20 +0100 Subject: [PATCH 180/431] EIP-1803: Rename opcodes for clarity (#1803) --- EIPS/eip-1803.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 EIPS/eip-1803.md diff --git a/EIPS/eip-1803.md b/EIPS/eip-1803.md new file mode 100644 index 00000000..45e19a2a --- /dev/null +++ b/EIPS/eip-1803.md @@ -0,0 +1,40 @@ +--- +eip: 1803 +title: Rename opcodes for clarity +author: Alex Beregszaszi (@axic) +type: Standards Track +category: Interface +status: Draft +created: 2017-07-28 +requires: 141 +--- + +## Abstract + +Rename the `BALANCE`, `SHA3`, `NUMBER`, `GASLIMIT`, `GAS` and `INVALID` opcodes to reflect their true meaning. + +## Specification + +Rename the opcodes as follows: +- `BALANCE` (`0x31`) to `EXTBALANCE` to be in line with `EXTCODESIZE`, `EXTCODECOPY` and `EXTCODEHASH` +- `SHA3` (`0x20`) to `KECCAK256` +- `NUMBER` (`0x43`) to `BLOCKNUMBER` +- `GASLIMIT` (`0x45`) to `BLOCKGASLIMIT` to avoid confusion with the gas limit of the transaction +- `GAS` (`0x5a`) to `GASLEFT` to be clear what it refers to +- `INVALID` (`0xfe`) to `ABORT` to clearly articulate when someone refers this opcode as opposed to "any invalid opcode" + +## Backwards Compatibility + +This has no effect on any code. It can influence what mnemonics assemblers will use. + +## Implementation + +Not applicable. + +## References + +Renaming `SHA3` was previously proposed by [EIP-59](https://github.com/ethereum/EIPs/issues/59). + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 240cabc7b5ec42049275a03bbe7c9a7147be492a Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 09:57:13 +0100 Subject: [PATCH 181/431] Change the citation format in README to point to EIP-1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 03278d56..4bb44a25 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ When you believe your EIP is mature and ready to progress past the draft phase, # Preferred Citation Format -The canonical URL for a EIP that has achieved draft status at any point is at https://eips.ethereum.org/. For example, the canonical URL for ERC-165 is https://eips.ethereum.org/EIPS/eip-165. +The canonical URL for a EIP that has achieved draft status at any point is at https://eips.ethereum.org/. For example, the canonical URL for EIP-1 is https://eips.ethereum.org/EIPS/eip-1. # Validation From bda2a4f723080b68503fe6ecf318551999ac6818 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 30 Apr 2019 22:25:25 +0100 Subject: [PATCH 182/431] Automatically merged updates to draft EIP(s) 1679, 1803 Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + EIPS/eip-1803.md | 1 + 2 files changed, 2 insertions(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index f29042ca..dee8b794 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -38,6 +38,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts - [EIP-1380](https://eips.ethereum.org/EIPS/eip-1380): Reduced gas cost for call to self - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme +- [EIP-1803](https://eips.ethereum.org/EIPS/eip-1803): Rename opcodes for clarity - [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes ## Timeline diff --git a/EIPS/eip-1803.md b/EIPS/eip-1803.md index 45e19a2a..303879c3 100644 --- a/EIPS/eip-1803.md +++ b/EIPS/eip-1803.md @@ -33,6 +33,7 @@ Not applicable. ## References +[EIP-6](https://eips.ethereum.org/EIPS/eip-6) previously renamed `SUICIDE` (`0xff`) to `SELFDESTRUCT`. Renaming `SHA3` was previously proposed by [EIP-59](https://github.com/ethereum/EIPs/issues/59). ## Copyright From 62d0a0a6593f072b972521fdd40b202d49158909 Mon Sep 17 00:00:00 2001 From: WTRMQDev <44411763+WTRMQDev@users.noreply.github.com> Date: Fri, 3 May 2019 20:45:12 +0300 Subject: [PATCH 183/431] EIP-1057 Update progpow test-vectors (#1855) --- EIPS/eip-1057.md | 5 +- assets/eip-1057/test-vectors-0.9.2.json | 107 +++++++++++++++++++++++ assets/eip-1057/test-vectors-0.9.3.json | 108 ++++++++++++++++++++++++ assets/eip-1057/test-vectors.md | 66 ++++++++------- 4 files changed, 255 insertions(+), 31 deletions(-) create mode 100644 assets/eip-1057/test-vectors-0.9.2.json create mode 100644 assets/eip-1057/test-vectors-0.9.3.json diff --git a/EIPS/eip-1057.md b/EIPS/eip-1057.md index 41a27c9d..b3b897b9 100644 --- a/EIPS/eip-1057.md +++ b/EIPS/eip-1057.md @@ -478,6 +478,7 @@ This algorithm is not backwards compatible with the existing Ethash, and will re ## Test Cases +### progpow 0.9.2 The algorithm run on block 30,000 produces the following digest and result: ``` header ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff @@ -488,6 +489,8 @@ result: 5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece ``` Additional test vectors can be found [in the test vectors file](../assets/eip-1057/test-vectors.md#progPowHash). +### progpow 0.9.3 +[Machine-readable test vectors](https://github.com/ethereum/EIPs/blob/ad4e73f239d53d72a21cfd8fdc89dc81eb9d2688/assets/eip-1057/test-vectors-0.9.3.json) ## Implementation @@ -496,4 +499,4 @@ The reference ProgPoW mining implementation located at [ProgPOW](https://github. The ProgPoW algorithm and this specification are a new work. Copyright and related rights are waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). -The reference ProgPoW mining implementation located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) is a derivative of ethminer so retains the GPL license. \ No newline at end of file +The reference ProgPoW mining implementation located at [ProgPOW](https://github.com/ifdefelse/ProgPOW) is a derivative of ethminer so retains the GPL license. diff --git a/assets/eip-1057/test-vectors-0.9.2.json b/assets/eip-1057/test-vectors-0.9.2.json new file mode 100644 index 00000000..b10408ae --- /dev/null +++ b/assets/eip-1057/test-vectors-0.9.2.json @@ -0,0 +1,107 @@ +[ + { + "block_height": 30000, + "nonce": "123456789abcdef0", + "header_hash": "ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff", + "mix_hash": "11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d", + "final_hash": "5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece" + }, + { + "block_height": 0, + "nonce": "0000000000000000", + "header_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "mix_hash": "faeb1be51075b03a4ff44b335067951ead07a3b078539ace76fd56fc410557a3", + "final_hash": "63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b" + }, + { + "block_height": 49, + "nonce": "0000000006ff2c47", + "header_hash": "63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b", + "mix_hash": "c789c1180f890ec555ff42042913465481e8e6bc512cb981e1c1108dc3f2227d", + "final_hash": "9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922" + }, + { + "block_height": 50, + "nonce": "00000000076e482e", + "header_hash": "9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922", + "mix_hash": "c7340542c2a06b3a7dc7222635f7cd402abf8b528ae971ddac6bbe2b0c7cb518", + "final_hash": "de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d" + }, + { + "block_height": 99, + "nonce": "000000003917afab", + "header_hash": "de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d", + "mix_hash": "f5e60b2c5bfddd136167a30cbc3c8dbdbd15a512257dee7964e0bc6daa9f8ba7", + "final_hash": "ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce" + }, + { + "block_height": 29950, + "nonce": "005d409dbc23a62a", + "header_hash": "ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce", + "mix_hash": "07393d15805eb08ee6fc6cb3ad4ad1010533bd0ff92d6006850246829f18fd6e", + "final_hash": "e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5" + }, + { + "block_height": 29999, + "nonce": "005db5fa4c2a3d03", + "header_hash": "e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5", + "mix_hash": "7551bddf977491da2f6cfc1679299544b23483e8f8ee0931c4c16a796558a0b8", + "final_hash": "d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454" + }, + { + "block_height": 30000, + "nonce": "005db8607994ff30", + "header_hash": "d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454", + "mix_hash": "f1c2c7c32266af9635462e6ce1c98ebe4e7e3ecab7a38aaabfbf2e731e0fbff4", + "final_hash": "8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64" + }, + { + "block_height": 30049, + "nonce": "005e2e215a8ca2e7", + "header_hash": "8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64", + "mix_hash": "57fe6a9fbf920b4e91deeb66cb0efa971e08229d1a160330e08da54af0689add", + "final_hash": "c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047" + }, + { + "block_height": 30050, + "nonce": "005e30899481055e", + "header_hash": "c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047", + "mix_hash": "ba30c61cc5a2c74a5ecaf505965140a08f24a296d687e78720f0b48baf712f2d", + "final_hash": "ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71" + }, + { + "block_height": 30099, + "nonce": "005ea6aef136f88b", + "header_hash": "ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71", + "mix_hash": "cfd5e46048cd133d40f261fe8704e51d3f497fc14203ac6a9ef6a0841780b1cd", + "final_hash": "49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6" + }, + { + "block_height": 59950, + "nonce": "02ebe0503bd7b1da", + "header_hash": "49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6", + "mix_hash": "21511fbaa31fb9f5fc4998a754e97b3083a866f4de86fa7500a633346f56d773", + "final_hash": "f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf" + }, + { + "block_height": 59999, + "nonce": "02edb6275bd221e3", + "header_hash": "f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf", + "mix_hash": "653eda37d337e39d311d22be9bbd3458d3abee4e643bee4a7280a6d08106ef98", + "final_hash": "341562d10d4afb706ec2c8d5537cb0c810de02b4ebb0a0eea5ae335af6fb2e88" + }, + { + "block_height": 10000000, + "nonce": "005e30899481055e", + "header_hash": "efda178de857b2b1703d8d5403bd0f848e19cff5c50ba5c0d6210ddb16250ec3", + "mix_hash": "b2403f56c426177856eaf0eedd707c86ae78a432b9169c3689a67058fcf2a848", + "final_hash": "206aee640c0fd21473d5cc3654d63c80442d9e2dfa676d2801d3ec1fbab38a6d" + }, + { + "block_height": 100000000, + "nonce": "02abe0589481055e", + "header_hash": "49e15ba4bf501ce8fe88765403bd0f848e19cff5c50ba5c0d6210ddb16250ec3", + "mix_hash": "ac452084d6f4e6eacf4282ad58dbd4ce7ef2653fb5e6b5c877f56928c907432a", + "final_hash": "b879f84923e71b812ef5a42ece0b5b9366c31cab218f40afe65f8a2cae448a6f" + } +] diff --git a/assets/eip-1057/test-vectors-0.9.3.json b/assets/eip-1057/test-vectors-0.9.3.json new file mode 100644 index 00000000..054c3dad --- /dev/null +++ b/assets/eip-1057/test-vectors-0.9.3.json @@ -0,0 +1,108 @@ +[ + { + "block_height": 30000, + "nonce": "123456789abcdef0", + "header_hash": "ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff", + "mix_hash": "6018c151b0f9895ebe44a4ca6ce2829e5ba6ae1a68a4ccd05a67ac01219655c1", + "final_hash": "34d8436444aa5c61761ce0bcce0f11401df2eace77f5c14ba7039b86b5800c08" + }, + { + "block_height": 0, + "nonce": "0000000000000000", + "header_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "mix_hash": "f4ac202715ded4136e72887c39e63a4738331c57fd9eb79f6ec421c281aa8743", + "final_hash": "b3bad9ca6f7c566cf0377d1f8cce29d6516a96562c122d924626281ec948ef02" + }, + { + "block_height": 49, + "nonce": "0000000006ff2c47", + "header_hash": "63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b", + "mix_hash": "8f744dec9140938453c8a502a489861aedec7e98ce7e11b10a3b661940c38786", + "final_hash": "ca0c365f1290ede4ee0d19cab08cd827030425ae8aba96b5248faafe732f1f80" + }, + { + "block_height": 50, + "nonce": "00000000076e482e", + "header_hash": "9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922", + "mix_hash": "bd772e573609acead3b0f27d7935022ea0bf72f22ecf0980f0c21a74cc2fa3ef", + "final_hash": "75439f6c6e153d3c798309f01ba37e7a284d172f50841c7b523e81c1b8247083" + }, + { + "block_height": 99, + "nonce": "000000003917afab", + "header_hash": "de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d", + "mix_hash": "18a5d2f1eaa3df5a54f254c3f90bfa8e40c63913664175c93a9e5136f4dc7c5c", + "final_hash": "2618185c024ad29fd75bc350da388cc0d47cdebbd6798400f17692a7ccf3314c" + }, + { + "block_height": 29950, + "nonce": "005d409dbc23a62a", + "header_hash": "ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce", + "mix_hash": "d98cd262f73f9e110d994e592ad793ffca5fa92d8aff0e6f40fe3e84940e09e5", + "final_hash": "8ec8a0486e759c59c6f7ba586450dc2a5c8c3586b52345efb9b604fa82f40f65" + }, + { + "block_height": 29999, + "nonce": "005db5fa4c2a3d03", + "header_hash": "e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5", + "mix_hash": "53979a1e55d7b1987664570920a3d9121052f06326b99c6698b38255ed419003", + "final_hash": "de03c1354159e07cf804ecc9a53f82b0187dd4a24837d20e56cae28b65c35eb0" + }, + { + "block_height": 30000, + "nonce": "005db8607994ff30", + "header_hash": "d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454", + "mix_hash": "ec3eed8a744b1950ae72439e8d28a47b868f4cdc26e5c37084e441cceb289c21", + "final_hash": "a717a28081999625860cbb09262dbbcc6090427411a5a3c60fb86a0ded8d369e" + }, + { + "block_height": 30049, + "nonce": "005e2e215a8ca2e7", + "header_hash": "8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64", + "mix_hash": "ed3764d1cf0abc3798c594a372679dd076f7dda15b552e7ec83d3ba8b27cbe0c", + "final_hash": "dd85d293db9b1063c6428ac9ca74e8d5d4d9fee49e0123bafb914fa787f58e89" + }, + { + "block_height": 30050, + "nonce": "005e30899481055e", + "header_hash": "c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047", + "mix_hash": "732a4c5f7de1cc6d2a3702e9ea717b4f9da0de66e75897a2d5dc6cf407e883fc", + "final_hash": "4e83a686a5390b8105a261c4c1480b23a17938d4d029d1239042be7515e980fa" + }, + { + "block_height": 30099, + "nonce": "005ea6aef136f88b", + "header_hash": "ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71", + "mix_hash": "be8789da582670b3b5091d3693b7584b5a554cd258c9a3f299645cfaf13acff9", + "final_hash": "72a6b01403faf90b2e74cb28920e953016d2c04f3e22d64aa4712ed00b5b6681" + }, + { + "block_height": 59950, + "nonce": "02ebe0503bd7b1da", + "header_hash": "49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6", + "mix_hash": "3d1093e05b7ac6f23bda5afecf36f01379f05df06a28bcefd3459b70941bbc41", + "final_hash": "56c9fefbfe93eac6de18b1bd4e42d6bf784f9dc5a112955d2ffa6d5fb3cc0657" + }, + { + "block_height": 59999, + "nonce": "02edb6275bd221e3", + "header_hash": "f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf", + "mix_hash": "855c62aba873a0955345556f2ba33cb1d74b7d42067402e6ec145dd031087b23", + "final_hash": "116053ccb7866e23df4263a359794fa84afceb0d11d97cb9389ffa763b7be43a" + }, + { + "block_height": 10000000, + "nonce": "005e30899481055e", + "header_hash": "efda178de857b2b1703d8d5403bd0f848e19cff5c50ba5c0d6210ddb16250ec3", + "mix_hash": "3cb394b257046429e7a18528f2d1bc64e3b712031534ecb1f60f5c6d61fd60ca", + "final_hash": "5dca7eab5997b489420b5d05d56394b8be83824bcb5916b84d8b39d54186a6d6" + }, + { + "block_height": 100000000, + "nonce": "02abe0589481055e", + "header_hash": "49e15ba4bf501ce8fe88765403bd0f848e19cff5c50ba5c0d6210ddb16250ec3", + "mix_hash": "cc8a24ce78d5df7787f7b47bad87c7ef5d4e159ba5d32d5d6b01a6c5c4a2b536", + "final_hash": "eba819f45d27b39cc0a8deb68b6dde03c37a9790634eeb6a1d0edb40ed26ee1d" + } +] + diff --git a/assets/eip-1057/test-vectors.md b/assets/eip-1057/test-vectors.md index a47c7e89..991e2509 100644 --- a/assets/eip-1057/test-vectors.md +++ b/assets/eip-1057/test-vectors.md @@ -336,122 +336,128 @@ loop 1 are as follows. ## progPowHash +### 0.9.2 +[Machine-readable data](https://github.com/ethereum/EIPs/blob/ad4e73f239d53d72a21cfd8fdc89dc81eb9d2688/assets/eip-1057/test-vectors-0.9.3.json) + Block 30000: - `prog_seed` - 600 - `nonce` - `123456789abcdef0` - `header` - `ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff` -- _digest_ - `11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d` -- _result_ - `5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece` +- `mix_hash` - `11f19805c58ab46610ff9c719dcf0a5f18fa2f1605798eef770c47219274767d` +- `final_hash` - `5b7ccd472dbefdd95b895cac8ece67ff0deb5a6bd2ecc6e162383d00c3728ece` Block 0: - `prog_seed` - 0 - `nonce` - `0000000000000000` - `header` - `0000000000000000000000000000000000000000000000000000000000000000` -- _digest_ - `faeb1be51075b03a4ff44b335067951ead07a3b078539ace76fd56fc410557a3` -- _result_ - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12` +- `mix_hash` - `faeb1be51075b03a4ff44b335067951ead07a3b078539ace76fd56fc410557a3` +- `final_hash` - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b` Block 49: - `prog_seed` - 0 - `nonce` - `0000000006ff2c47` - `header` - `63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b` -- _digest_ - `c789c1180f890ec555ff42042913465481e8e6bc512cb981e1c1108dc3f2227d` -- _result_ - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd92` +- `mix_hash` - `c789c1180f890ec555ff42042913465481e8e6bc512cb981e1c1108dc3f2227d` +- `final_hash` - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922` Block 50: - `prog_seed` - 1 - `nonce` - `00000000076e482e` - `header` - `9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922` -- _digest_ - `c7340542c2a06b3a7dc7222635f7cd402abf8b528ae971ddac6bbe2b0c7cb518` -- _result_ - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188` +- `mix_hash` - `c7340542c2a06b3a7dc7222635f7cd402abf8b528ae971ddac6bbe2b0c7cb518` +- `final_hash` - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d` Block 99: - `prog_seed` - 1 - `nonce` - `000000003917afab` - `header` - `de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d` -- _digest_ - `f5e60b2c5bfddd136167a30cbc3c8dbdbd15a512257dee7964e0bc6daa9f8ba7` -- _result_ - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcc` +- `mix_hash` - `f5e60b2c5bfddd136167a30cbc3c8dbdbd15a512257dee7964e0bc6daa9f8ba7` +- `final_hash` - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce` Block 29,950: - `prog_seed` - 599 - `nonce` - `005d409dbc23a62a` - `header` - `ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce` -- _digest_ - `07393d15805eb08ee6fc6cb3ad4ad1010533bd0ff92d6006850246829f18fd6e` -- _result_ - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f` +- `mix_hash` - `07393d15805eb08ee6fc6cb3ad4ad1010533bd0ff92d6006850246829f18fd6e` +- `final_hash` - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5` Block 29,999: - `prog_seed` - 599 - `nonce` - `005db5fa4c2a3d03` - `header` - `e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5` -- _digest_ - `7551bddf977491da2f6cfc1679299544b23483e8f8ee0931c4c16a796558a0b8` -- _result_ - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c645` +- `mix_hash` - `7551bddf977491da2f6cfc1679299544b23483e8f8ee0931c4c16a796558a0b8` +- `final_hash` - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454` Block 30,000: - `prog_seed` - 600 - `nonce` - `005db8607994ff30` - `header` - `d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454` -- _digest_ - `f1c2c7c32266af9635462e6ce1c98ebe4e7e3ecab7a38aaabfbf2e731e0fbff4` -- _result_ - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef6` +- `mix_hash` - `f1c2c7c32266af9635462e6ce1c98ebe4e7e3ecab7a38aaabfbf2e731e0fbff4` +- `final_hash` - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64` Block 30,049: - `prog_seed` - 600 - `nonce` - `005e2e215a8ca2e7` - `header` - `8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64` -- _digest_ - `57fe6a9fbf920b4e91deeb66cb0efa971e08229d1a160330e08da54af0689add` -- _result_ - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe0904` +- `mix_hash` - `57fe6a9fbf920b4e91deeb66cb0efa971e08229d1a160330e08da54af0689add` +- `final_hash` - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047` Block 30,050: - `prog_seed` - 601 - `nonce` - `005e30899481055e` - `header` - `c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047` -- _digest_ - `ba30c61cc5a2c74a5ecaf505965140a08f24a296d687e78720f0b48baf712f2d` -- _result_ - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc7` +- `mix_hash` - `ba30c61cc5a2c74a5ecaf505965140a08f24a296d687e78720f0b48baf712f2d` +- `final_hash` - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71` Block 30,099: - `prog_seed` - 601 - `nonce` - `005ea6aef136f88b` - `header` - `ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71` -- _digest_ - `cfd5e46048cd133d40f261fe8704e51d3f497fc14203ac6a9ef6a0841780b1cd` -- _result_ - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd` +- `mix_hash` - `cfd5e46048cd133d40f261fe8704e51d3f497fc14203ac6a9ef6a0841780b1cd` +- `final_hash` - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6` Block 59,950: - `prog_seed` - 1,199 - `nonce` - `02ebe0503bd7b1da` - `header` - `49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6` -- _digest_ - `21511fbaa31fb9f5fc4998a754e97b3083a866f4de86fa7500a633346f56d773` -- _result_ - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19c` +- `mix_hash` - `21511fbaa31fb9f5fc4998a754e97b3083a866f4de86fa7500a633346f56d773` +- `final_hash` - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf` Block 59,999: - `prog_seed` - 1,199 - `nonce` - `02edb6275bd221e3` - `header` - `f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf` -- _digest_ - `653eda37d337e39d311d22be9bbd3458d3abee4e643bee4a7280a6d08106ef98` -- _result_ - `341562d10d4afb706ec2c8d5537cb0c810de02b4ebb0a0eea5ae335af6fb2e8` +- `mix_hash` - `653eda37d337e39d311d22be9bbd3458d3abee4e643bee4a7280a6d08106ef98` +- `final_hash` - `341562d10d4afb706ec2c8d5537cb0c810de02b4ebb0a0eea5ae335af6fb2e88` Block 10,000,000: - `prog_seed` - 200,000 - `nonce` - `005e30899481055e` - `header` - `efda178de857b2b1703d8d5403bd0f848e19cff5c50ba5c0d6210ddb16250ec3` -- _digest_ - `b2403f56c426177856eaf0eedd707c86ae78a432b9169c3689a67058fcf2a848` -- _result_ - `206aee640c0fd21473d5cc3654d63c80442d9e2dfa676d2801d3ec1fbab38a6d` +- `mix_hash` - `b2403f56c426177856eaf0eedd707c86ae78a432b9169c3689a67058fcf2a848` +- `final_hash` - `206aee640c0fd21473d5cc3654d63c80442d9e2dfa676d2801d3ec1fbab38a6d` Block 100,000,000: - `prog_seed` - 2,000,000 - `nonce` - `02abe0589481055e` - `header` - `49e15ba4bf501ce8fe88765403bd0f848e19cff5c50ba5c0d6210ddb16250ec3` -- _digest_ - `ac452084d6f4e6eacf4282ad58dbd4ce7ef2653fb5e6b5c877f56928c907432a` -- _result_ - `b879f84923e71b812ef5a42ece0b5b9366c31cab218f40afe65f8a2cae448a6f` \ No newline at end of file +- `mix_hash` - `ac452084d6f4e6eacf4282ad58dbd4ce7ef2653fb5e6b5c877f56928c907432a` +- `final_hash` - `b879f84923e71b812ef5a42ece0b5b9366c31cab218f40afe65f8a2cae448a6f` + +### 0.9.3 +[Machine-readable data](https://github.com/ethereum/EIPs/blob/ad4e73f239d53d72a21cfd8fdc89dc81eb9d2688/assets/eip-1057/test-vectors-0.9.3.json) From 7cdf2de23473798c2ec55ee8197a2dc942d67132 Mon Sep 17 00:00:00 2001 From: Greg Colvin Date: Fri, 3 May 2019 15:34:38 -0600 Subject: [PATCH 184/431] Add editors --- EIPS/eip-1.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 8fc28d16..039a2148 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -205,6 +205,10 @@ The current EIP editors are ` * Martin Becze (@wanderer)` +` * Greg Colvin (@gcolvin)` + +` * Alex Beregszaszi (@axic)` + ## EIP Editor Responsibilities For each new EIP that comes in, an editor does the following: From dd6e4f76193d20badf20d23507694e423a5421bc Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Fri, 3 May 2019 17:51:49 -0400 Subject: [PATCH 185/431] Automatically merged updates to draft EIP(s) 1155 (#1993) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 135 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 37 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index edda721e..23801061 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -1,7 +1,7 @@ --- eip: 1155 title: ERC-1155 Multi Token Standard -author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet +author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet type: Standards Track category: ERC status: Draft @@ -34,7 +34,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S **Smart contracts implementing the ERC-1155 standard MUST implement the `ERC1155` and `ERC165` interfaces.** ```solidity -pragma solidity ^0.5.7; +pragma solidity ^0.5.8; /** @title ERC-1155 Multi Token Standard @@ -63,7 +63,7 @@ interface ERC1155 /* is ERC165 */ { event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values); /** - @dev MUST emit when an approval is updated. + @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absense of an event assumes disabled). */ event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); @@ -77,34 +77,34 @@ interface ERC1155 /* is ERC165 */ { /** @notice Transfers value amount of an _id from the _from address to the _to address specified. @dev MUST emit TransferSingle event on success. - Caller must be approved to manage the _from account's tokens (see isApprovedForAll). - MUST throw if `_to` is the zero address. - MUST throw if balance of sender for token `_id` is lower than the `_value` sent. - MUST throw on any other error. - When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). If so, it MUST call `onERC1155Received` on `_to` and revert if the return value is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`. + Caller must be approved to manage the _from account's tokens (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if balance of sender for token `_id` is lower than the `_value` sent. + MUST revert on any other error. + After the transfer succeeds, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param _from Source address @param _to Target address @param _id ID of the token type @param _value Transfer amount - @param _data Additional data with no specified format, sent in call to `_to` + @param _data Additional data with no specified format, sent in call to `onERC1155Received` on `_to` */ function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; /** @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call). @dev MUST emit TransferBatch event on success. - Caller must be approved to manage the _from account's tokens (see isApprovedForAll). - MUST throw if `_to` is the zero address. - MUST throw if length of `_ids` is not the same as length of `_values`. - MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_values` sent. - MUST throw on any other error. - When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return value is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`. + Caller must be approved to manage the _from account's tokens (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if length of `_ids` is not the same as length of `_values`. + MUST revert if any of the balance of sender for token `_ids` is lower than the respective `_values` sent. + MUST revert on any other error. Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc). + After all the transfer(s) in the batch succeed, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155BatchReceived` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param _from Source addresses @param _to Target addresses - @param _ids IDs of each token type - @param _values Transfer amounts per token type - @param _data Additional data with no specified format, sent in call to `_to` + @param _ids IDs of each token type (order and length must match _values array) + @param _values Transfer amounts per token type (order and length must match _ids array) + @param _data Additional data with no specified format, sent in call to `onERC1155BatchReceived` on `_to` */ function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external; @@ -144,58 +144,116 @@ interface ERC1155 /* is ERC165 */ { ### ERC-1155 Token Receiver -Smart contracts **MUST** implement this interface to accept transfers. +Smart contracts **MUST** implement this interface to accept transfers. See "Safe Transfer Rules" for further detail. ```solidity -pragma solidity ^0.5.7; +pragma solidity ^0.5.8; interface ERC1155TokenReceiver { /** @notice Handle the receipt of a single ERC1155 token type. - @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. - This function MAY throw to revert and reject the transfer. - Return of other than the magic value MUST result in the transaction being reverted. + @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. + This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. + Return of any other value than the prescribed keccak256 generated values WILL result in the transaction being reverted. Note: The contract address is always the message sender. - @param _operator The address which called the `safeTransferFrom` function + @param _operator The address which initiated the transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _id The id of the token being transferred @param _value The amount of tokens being transferred @param _data Additional data with no specified format - @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + @return `bytes4(keccak256("accept_erc1155_tokens()"))`==0x4dc21a2f or `bytes4(keccak256("reject_erc1155_tokens()"))`==0xafed434d */ function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4); - + /** @notice Handle the receipt of multiple ERC1155 token types. - @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. - This function MAY throw to revert and reject the transfer. - Return of other than the magic value WILL result in the transaction being reverted. + @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. + This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. + Return of any other value than the prescribed keccak256 generated values WILL result in the transaction being reverted. Note: The contract address is always the message sender. - @param _operator The address which called the `safeBatchTransferFrom` function + @param _operator The address which initiated the batch transfer (i.e. msg.sender) @param _from The address which previously owned the token - @param _ids An array containing ids of each token being transferred - @param _values An array containing amounts of each token being transferred + @param _ids An array containing ids of each token being transferred (order and length must match _values array) + @param _values An array containing amounts of each token being transferred (order and length must match _ids array) @param _data Additional data with no specified format - @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + @return `bytes4(keccak256("accept_batch_erc1155_tokens()"))`==0xac007889 or `bytes4(keccak256("reject_erc1155_tokens()"))`==0xafed434d */ function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4); } ``` +### Safe Transfer Rules + +To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate, a list of rules follows: + +* onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA account. +* onERC1155Received and onERC1155BatchReceived MUST NOT be called outside of a mint or transfer process. + +##### When the recipient is a contract: + +* The onERC1155Received hook MUST be called every time one and only one token type is transferred to an address in the transaction. +* The onERC1155Received hook MUST NOT be called when more than one token type is transferred to an address in the transaction. +* The onERC1155BatchReceived hook MUST be called when more than one token type is transferred to an address in the transaction with the entire list of what was transferred to it. +* The onERC1155BatchReceived hook MUST NOT be called when only one token type is transferred to an address in the transaction. + +* If implementation specific functions are used to transfer 1155 tokens to a contract the appropriate hook MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. +* If the destination/to contract does not implement the appropriate hook the transfer MUST be reverted with the one caveat below. + - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. + +* When calling either onERC1155Received or onERC1155BatchReceived: + - operator MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). + - from MUST be the address of the holder whose balance is decreased. + - to MUST be the address of the recipient whose balance is increased. + - from MUST be 0x0 for a mint. + - data MUST contain the extra information provided by the sender (if any) for a transfer. + - the hook MUST be called after all the balances in the transaction have been updated to match the senders intent. + +* When calling onERC1155Received + - id MUST be the token type being transferred. + - value MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + - If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. + +* When calling onERC1155BatchReceived + - ids MUST be the list of tokens being transferred. + - values MUST be the list of number of tokens (specified in ids) the holder balance is decreased by and match what the recipient balance is increased by. + - If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. + +* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` for onERC1155Received or `bytes4(keccak256("accept_batch_erc1155_tokens()"))` for onERC1155BatchReceived. + - If such explicit acceptance happens the transfer MUST be completed, unless other conditions apply. +* The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. + - If such explicit rejection happens, the transfer MUST be reverted with the one caveat below. + - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. + +* A solidity example of the keccak256 generated constants for the return magic is: + - bytes4 constant public ERC1155_REJECTED = 0xafed434d; // keccak256("reject_erc1155_tokens()") + - bytes4 constant public ERC1155_ACCEPTED = 0x4dc21a2f; // keccak256("accept_erc1155_tokens()") + - bytes4 constant public ERC1155_BATCH_ACCEPTED = 0xac007889; // keccak256("accept_batch_erc1155_tokens()") + +##### Compatibility with other standards + +There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC721 at time of writing. +To cater for this there is some leeway with the rejection logic should a contract return `bytes4(keccack256("reject_erc1155_tokens()"))` from the call to onERC1155Received/onERC1155BatchReceived as detailed in the main "Safe Transfer Rules" section above. +In this case the hybrid implementation MAY now follow the secondary standard's rules when transferring token(s) to a contract address. + +Note however it is recommended that a hybrid solution NOT be followed and a pure implementation of a single standard is followed instead, as a hybrid solution is an unproven method to date. + +An example of a hybrid 1155+721 contract is linked in the references section under implementations. + ### Metadata -The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/780000000000001e000000000000000000000000000000000000000000000000.json` if the client is referring to token ID `780000000000001e000000000000000000000000000000000000000000000000`. +The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004CCE0.json` if the client is referring to token ID 314592/0x4CCE0. The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix. +The string format of the substituted hexadecimal ID MUST be leading zero padded to 64 hex characters length if necessary. #### Metadata Extensions The following optional extensions can be identified with the (ERC-165 Standard Interface Detection)[https://eips.ethereum.org/EIPS/eip-165]. -Changes to the URI MUST emit the `URI` event if the change can be expressed with an event. If the optional ERC1155Metadata_URI extension is included, the value returned by this function SHOULD be used to retrieve values for which no event was emitted. The function MUST return the same value as the event if it was emitted. +Changes to the URI MUST emit the `URI` event if the change can be expressed with an event (i.e. it isn't dynamic). If the optional ERC1155Metadata_URI extension is included, the 'uri' function SHOULD be used to retrieve values for which no event was emitted. The function MUST return the same value as the event if it was emitted. ```solidity -pragma solidity ^0.5.7; +pragma solidity ^0.5.8; /** Note: The ERC-165 identifier for this interface is 0x0e89341c. @@ -277,7 +335,7 @@ An example of an ERC-1155 Metadata JSON file follows. The properties array propo ##### Localization -Metadata localization should be standardized to increase presentation uniformity accross all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content MAY be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. +Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content MAY be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software. ##### JSON Schema @@ -362,6 +420,9 @@ fr.json: ### Approval The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) is suggested. +The counterpart `isAprrovedForAll` provides introspection into status set by `setApprovalForAll`. + +An owner SHOULD be assumed to always be able to operate on their own tokens regardless of approval status, so should SHOULD NOT have to call `setApprovalForAll` to approve themselves as an operator before they can operate on them. ## Rationale From b859ddbb4663775f71f2c3f6c7036d73ae880e7a Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Fri, 3 May 2019 20:16:07 -0400 Subject: [PATCH 186/431] Automatically merged updates to draft EIP(s) 1155 (#1995) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 23801061..afcd5bfb 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -241,7 +241,7 @@ An example of a hybrid 1155+721 contract is linked in the references section und ### Metadata -The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004CCE0.json` if the client is referring to token ID 314592/0x4CCE0. +The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for large number of tokens to use the same on-chain string by defining a URI once, for a large collection of tokens. Example of such a URI: `https://token-cdn-domain/{id}.json` would be replaced with `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` if the client is referring to token ID 314592/0x4CCE0. The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix. The string format of the substituted hexadecimal ID MUST be leading zero padded to 64 hex characters length if necessary. From b922d593401c67c1473b334fdb6919b31a27d34f Mon Sep 17 00:00:00 2001 From: Vincent Date: Sun, 5 May 2019 23:09:31 +0200 Subject: [PATCH 187/431] EIP-1775 - App Keys, application specific wallet accounts (#1775) --- EIPS/eip-1775.md | 634 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 634 insertions(+) create mode 100644 EIPS/eip-1775.md diff --git a/EIPS/eip-1775.md b/EIPS/eip-1775.md new file mode 100644 index 00000000..1c623887 --- /dev/null +++ b/EIPS/eip-1775.md @@ -0,0 +1,634 @@ +--- +eip: 1775 +title: App Keys, application specific wallet accounts +author: Vincent Eli (@Bunjin), Dan Finlay (@DanFinlay) +discussions-to: https://ethereum-magicians.org/t/eip-erc-app-keys-application-specific-wallet-accounts/2742 +status: Draft +type: Standards Track +category: ERC +created: 2019-02-20 +requires: 137 +--- + + +## Simple Summary + + +Among others cryptographic applications, scalability and privacy solutions for ethereum blockchain require that an user performs a significant amount of signing operations. It may also require her to watch some state and be ready to sign data automatically (e.g. sign a state or contest a withdraw). The way wallets currently implement accounts poses several obstacles to the development of a complete web3.0 experience both in terms of UX, security and privacy. + +This proposal describes a standard and api for a new type of wallet accounts that are derived specifically for a each given application. We propose to call them `app keys`. They allow to isolate the accounts used for each application, thus potentially increasing privacy. They also allow to give more control to the applications developpers over account management and signing delegation. For these app keys, wallets can have a more permissive level of security (e.g. not requesting user's confirmation) while keeping main accounts secure. Finally wallets can also implement a different behavior such as allowing to sign transactions without broadcasting them. + +This new accounts type can allow to significantly improve UX and permit new designs for applications of the crypto permissionned web. + +## Abstract + +In a wallet, an user often holds most of her funds in her main accounts. These accounts require a significant level of security and should not be delegated in any way, this significantly impacts the design of cryptographic applications if a user has to manually confirm every action. Also often an user uses the same accounts across apps, which is a privacy and potentially also a security issue. + +We introduce here a new account type, app keys, which permits signing delegation and accounts isolation across applications for privacy and security. + +In this EIP, we provide a proposal on how to uniquely identify and authenticate each application, how to derive the accounts along an Hierachical Deterministic (HD) path restricted for the domain and we finally define an API for applications to derive and use these app keys. This ERC aims at finding a standard that will fit the needs of wallets and application developers while also allowing app keys to be used across wallets and yield the same accounts for the user for each application. + +## Motivation + +Wallets developers have agreed on an HD derivation path for ethereum accounts using BIP32, BIP44, SLIP44, [(see the discussion here)](https://github.com/ethereum/EIPs/issues/84). Web3 wallets have implemented in a roughly similar way the rpc eth api. [EIP1102](https://eips.ethereum.org/EIPS/eip-1102) introduced privacy through non automatic opt-in of a wallet account into an app increasing privacy. + +However several limitations remain in order to allow for proper design and UX for crypto permissioned apps. + +Most of GUI based current wallets don't allow to: +* being able to automatically and effortlessly use different keys / accounts for each apps, +* being able to sign some app's action without prompting the user with the same level of security as sending funds from their main accounts, +* being able to use throwable keys to improve anonymity, +* effortlessly signing transactions for an app without broadcasting these while still being able to perform other transaction signing as usual from their main accounts, +* All this while being fully restorable using the user's mnemonic or hardware wallet and the HD Path determined uniquely by the app's ens name. + +We try to overcome these limitations by introducing a new account's type, app keys, made to be used along side the existing main accounts. + +These new app keys can permit to give more power and flexibility to the crypto apps developers. This can allow to improve a lot the UX of crypto dapps and to create new designs that were not possible before leveraging the ability to create and handle many accounts, to presign messages and broadcast them later. These features were not compatible with the level of security we were requesting for main accounts that hold most of an user's funds. + + +## Specification + + +### Applications + +An app is a website (or other) that would like to request from a wallet to access app keys. It can be any form of cryptography/identity relying application, ethereum but not only. + +Once connected to a wallet, an application can request to access a set of accounts derived exclusively for that application using the hierarchical deterministic (HD) paths. + +### Applications' HD path + +Using the BIP32 and BIP43 standards, we propose to use the following HD path for each app keys: + +`m / [standardized Path Beginning]' / [persona path]' / [application uniquely assigned path]' / [app's custom subpath]` + +Where: + +`standardized HD Path Beginning` is based on the EIP number that will be assigned to this EIP and we harden it. We use a different path than 44' since it's not bip44 compliant. At this point, I'm not sure if there is a list of BIP43 codes of standards following the `purpose` field specification of [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki). + +`persona path` allows to use applications with different and isolated personas (or in other words accounts) that are tracable by the application. They will still be fully restorable from the same mnemonic. + +`application uniquely assigned path` isolate each application along unique branches of the tree through these unique subPath combination. + +`app's custom subPath` give freedom to application to use this BIP32 compliant subPath to manage accounts and other needed parameters. + +Note that we suggest that each of these indexes, except those belonging to the app's custom subpath, must be hardened to fully isolate the public keys across personas and applications. + +### Standardized HD Path Beginning + +For the path header, several alternative are possible depending on what the cryptocommunities agree upon. + +The least contentious is the following one (as suggested [here in the BIP repository](https://github.com/bitcoin/bips/pull/523)): + +` 43' / 60' / 1775 ' ` + +However, there may be benefits to use only one depth instead of 3. We could use the `EIP Number'` (ie. 1775) or a ` BIP Number'` if we attain some cross crypto agreement that would avoid collision. + + +### Personas + +We allow the user to use different personas in combination to her mnemonic to potentially fully isolate her interaction with a given app accross personas. One can use this for instance to create a personal and business profile for a given's domain both backup up from the same mnemonic, using 2 different personnas indexes. The app or domain, will not be aware that it is the same person and mnemonic behind both. + +We use a string following BIP32 format (can be hardened) to define personas. +The indexes should be hex under 0x80000000, 31 bits. + +E.g. `0'` or `0'/1/2'/0` or `1d7b'/a41c'` + +### Applications' Unique Identifiers + +#### Applications Names + +We need a way to uniquely identify each application. We will use a naming and a hashing scheme. + +In our favored spec, each application is uniquely defined and authenticated by its name, a domain string. It can be a Domain Name Service DNS name or and Ethereum Name Service ENS name. + +There are a few restrictions however on the characters used and normalisation, each name should be passed through the [NamePrep Algorithm](https://tools.ietf.org/html/rfc3491) + +In addition there must be a maximum size to the domain string that we need to determine such that the mapping from strings to nodes remains injective, to avoid collision. + +We recommend this standard to be following the [ENS Specs](http://docs.ens.domains/en/latest/implementers.html#namehash), reproduced below for convinience and reference. + +``` +Normalising and validating names +Before a name can be converted to a node hash using Namehash, the name must first be normalised and checked for validity - for instance, converting fOO.eth into foo.eth, and prohibiting names containing forbidden characters such as underscores. It is crucial that all applications follow the same set of rules for normalisation and validation, as otherwise two users entering the same name on different systems may resolve the same human-readable name into two different ENS names. +``` + +#### Hashing and Applications UIDs + +The ENS uses an hashing scheme to associate a domain to a unique hash, `node`, through the `namehash` function. We will use this hashing scheme both for ENS and for DNS names. + +This gives an unique identifier (UID) of 32 bytes. + +``` +e.g. for foo.bar.eth +app's uid 0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 +``` + +For reference, here are the specs of ENS: + +``` +domain - the complete, human-readable form of a name; eg, ‘vitalik.wallet.eth’. +label - a single component of a domain; eg, ‘vitalik’, ‘wallet’, or ‘eth’. A label may not contain a period (‘.’). +label hash - the output of the keccak-256 function applied to a label; eg, keccak256(‘eth’) = 0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0. +node - the output of the namehash function, used to uniquely identify a name in ENS. +Algorithm +First, a domain is divided into labels by splitting on periods (‘.’). So, ‘vitalik.wallet.eth’ becomes the list [‘vitalik’, ‘wallet’, ‘eth’]. + +The namehash function is then defined recursively as follows: + +namehash([]) = 0x0000000000000000000000000000000000000000000000000000000000000000 +namehash([label, …]) = keccak256(namehash(…), keccak256(label)) + +keccak256(‘eth’) = 0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0 + +``` + +We thus propose to use the node of each app's domain as a unique identifier for each app but one can think of other UIDs, we include some alternative specs in the [Rationale](#Rationale) section below. + +### Applications' authentication + +If the application is using a DNS name then we simply authenticate the application by using the url of the loaded browser webpage. + +For applications using ENS, we can authenticate the application through ENS resolution. +The ENS can also allow to register and resolve metadata for the application such as `url`, and other parameters. + +If we use for instance this resolver profile defined in [EIP634](https://eips.ethereum.org/EIPS/eip-634) which permits the lookup of arbitrary key-value text data, we can for instance use the key `url` to point to a website. + +``` +A new resolver interface is defined, consisting of the following method: + +function text(bytes32 node, string key) constant returns (string text); +The interface ID of this interface is 0x59d1d43c. + +The text data may be any arbitrary UTF-8 string. If the key is not present, the empty string must be returned. +``` + +One can think of other authentication methods and even use some of them alongside the url-resolution method through ENS. We mention other methods in the [Rationale](#Rationale) section. + +We suggest for instance to also add an `authorEthAddress` text metadata field that can be used to authenticate messages from the application, with for instance a sign challenge. + +### Applications UID decomposition to get a BIP32 HD path + +Since each child index in an HD path only has 31 bits we will decompose the domain's hash as several child indexes, first as hex bytes then parsed as integers. + +For the applications's uid we use an `ENS namehash node` of 32 bytes, 256 bits (removing the leading `0x`). + +e.g. `foo.bar.eth` which gives the following namehash node: `0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3` + +We can decompose it in several ways, here are 2 potential ways: + +* First approach could favor having the least indexes: + +This requires to first convert the hex uid to 256 bits then decompose it as 8 * 31 bits + 8 bits + +``` +x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7 || x8 +``` +where `x0` to `x7` are 31 bits and `x8` is 8 bits + +then we convert the `x_i` to uints. + +The derivation sub-path would be: +`x0'/x1'/x2'/x3'/x4'/x5'/x6'/x7'/x8'` + + +``` +E.g. + +foo.bar.eth + + +0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 + +converted to binary (256 bits) + +6033644d673b +011000000011001101100100010011010110011100111011 +47b3bea04e79 +010001111011001110111110101000000100111001111001 +bbe06d78ce76 +101110111110000001101101011110001100111001110110 +b8be2fb8704f +101110001011111000101111101110000111000001001111 +9c2a80fd139c +100111000010101010000000111111010001001110011100 +81d3 +1000000111010011 + +256 bits: +0110000000110011011001000100110101100111001110110100011110110011101111101010000001001110011110011011101111100000011011010111100011001110011101101011100010111110001011111011100001110000010011111001110000101010100000001111110100010011100111001000000111010011 + +converted to less than or equal to 31 bits indexes: + +8 * 31 bits + 1 * 8 bits + +0110000000110011011001000100110 +1011001110011101101000111101100 +1110111110101000000100111001111 +0011011101111100000011011010111 +1000110011100111011010111000101 +1111000101111101110000111000001 +0011111001110000101010100000001 +1111101000100111001110010000001 +11010011 + +and converted to uints + +806990374'/1506726380'/2010384847'/465438423'/1181988293'/2025775553'/523785473'/2098437249'/211' + + +``` + + +* Second approach favors an homogenous decomposition: + +Equal lenght indexes would be 16 * 16 bits or in other words 16 * 2 bytes, cleanest and favored spec: + +``` +x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7 || x8 || x9 || x10 || x11 || x12 || x13 || x14 || x15 + +where || is concatenation +``` + + +``` +E.g. + +foo.bar.eth +0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 +6033 644d 673b 47b3 bea0 4e79 bbe0 6d78 ce76 b8be 2fb8 704f 9c2a 80fd 139c 81d3 +6033'/644d'/673b'/47b3'/bea0'/4e79'/bbe0'/6d78'/ce76'/b8be'/2fb8'/704f'/9c2a'/80fd'/139c'/81d3' +24627'/25677'/26427'/18355'/48800'/20089'/48096'/28024'/52854'/47294'/12216'/28751'/39978'/33021'/5020'/33235' +``` + + +Between these 2 decomposition approaches, there is a trade-off between computational efficiency (having less depth) and having an homegenous decomposition. We tend to favor the first approach with least indexes. + + +### Application customisable HD sub path + +Finally, the last part of the hd path is under the application's control. This will allow applications developers to use the HD path structure that best fits their needs. Developers can for instance, among any combination of other parameters they like, choose to include a `version` field if they would like to use different signing accounts when updating to a new version. They can then also manage the user accounts in the way they would like, for instance including or not an index for `sets of accounts` (called `accounts` in BIP44), an index for `change` and an index for `account` (called `address_index` in BIP44). +We consider that a given child on the HD tree should be called an `account` and not an `address` since it is composed of a private key, a public key and an address. + +Similarly to the persona path, this sub path must follow bip32, with hex under 0x80000000, 31 bits. +It can be hardened depending on each application's needs and can be writen as hex or unsigned integers. +It can include a large number of indexes. + +Q [Should we set a limit on the persona and application customsable hd path number of indexes?] + +### Example HD paths for app keys: + +``` +Dummy data: +EIP Number: 1775 +personaPath: 0'/712' +application's name: foo.bar.eth +uid: 0x6033644d673b47b3bea04e79bbe06d78ce76b8be2fb8704f9c2a80fd139c81d3 +app custom path params: app_version, set_of_accounts_index, account_index +``` + +`m/43'/60'/1775'/0'/712'/806990374'/1506726380'/2010384847'/465438423'/1181988293'/2025775553'/523785473'/2098437249'/211'/0'/0'/0` + +## API: + +We propose to introduce new RPC methods but they should be restricted and wrapped such that some parameters (e.g. domain name) are imposed by the wallet on the caller depending on the caller's authentication. + +[TBD] Specify scope of RPC methods (some params should be forced to the authenticated domain value) and how to integrate them into web3 api. + +### App keys exposure: + +* `wallet.appkey.enable(options)` +This method allows to enable app keys (getting user permission to use and allow him to select the persona she would like to use). + +[TBD] Could return the account public key from the HD path before `the app's custom subPath`. Hence from this app's root account, one could derive all non hardened childs public keys of the app's keys. + +[TBD] where `options` is a javascript object containing the permissions requested for these app keys. +Options could also include a challenge to be signed by the app's root account (would serve as authentication of the users from the app's perspective). The signature should then be also returned. + +Options should also include a parameter for the application to indicate which name should be used to compute the domain's HD path. That's required for applications that are loaded through ENS. They could be authenticated either through ENS or through DNS. These applications may like to use the DNS name even when they are resolved through ENS. (e.g. an application that just upgraded to ENS may like to continue using DNS paths to be retro-compatible for its former users). + +Uses the persona selected by the user (not known nor controllable by application). + +Uses the domain ens namehash (node) that was resolved to load window (not provided by application itself) + +### Ethereum accounts methods: + +* `appKey_eth_getPublicKey(hdSubPath) returns publicKey 64 bytes`: + +`hdSubPath` string with BIP32 format, "index_i / index_(i+1) '", can use hardening + +`publicKey` returns e.g. 0x80b994e25fb98f69518b1a03e59ddf4494a1a86cc66019131a732ff4a85108fbb86491e2bc423b2cdf6f1f0f4468ec73db0535a1528ca192d975116899289a4b + +* `appKey_eth_getAddress(hdSubPath) returns address 20 bytes`: + +`hdSubPath`: string with BIP32 format, "index_i / index_(i+1) '", can use hardening + +`address` e.g. 0x9df77328a2515c6d529bae90edf3d501eaaa268e + +* `appKey_eth_derivePublicKeyFromParent(parentPublicKey, hdSubPath) returns publicKey 64 bytes` + +`hdSubPath`: string with BIP32 format, "index_i / index_(i+1) '", should not use hardening here. + +* `appKey_eth_getAddressForPublicKey(publicKey) returns address 20 bytes` + +`publicKey` 64 bytes + +### Ethereum signing methods: + +* `appKey_eth_signTransaction(fromAddress, tx)` +tx is ethereum-js tx object + +* `appKey_eth_sign(fromAddress, message)` +* `appKey_eth_personalSign(fromAddress, message)` +* `appKey_eth_signTypedMessage(fromAddress, message)` +EIP712 + +### Ethereum broadcasting methods: + +* `appKey_eth_broadcastTransaction(tx, signedTx)` +tx is ethereum-js tx object + + +### Other potential methods: + +#### Other cryptocurrencies: +We defined for now Ethereum accounts and signing methods. However, one could do the same for other cryptocurrencies deriving accounts along their standards. This may open to some very interesting cross-blockchains application designs. + +#### Other cryptographic methods: +Similarly, using entropy provided by the HD Path, one could think of other cryptographic methods such as encryption and also other curve types. + + +#### Storage: +The HD path for each application can also be used as a key to isolate databases for user's persistent data. We could introduce methods that allow to read and write in a database specific to the application. + +Q [Benefit of this compared to using classical browser local storage?] + +### API permissions and confirmations from users: + +#### Initial permission request and full access afterwards: + +Each wallet has freedom in the way they implement their permission system along with this EIP and this API. We tend to favor a design where the applications would request once and for all full access to the applications keys (for their domain) and that the user has to confirm this once. From then on, any account derivation or signing for those applications keys will not prompt a confirmation request on the wallet side. +However applications themselves are free to reproduce some confirmation at their own level if they would like the users to double check the transactions or signatures they are making at the application level. This will be of course dependent on trusting the application code. + +#### Paranoia mode: +However, we would like to give users the option to monitor at any point applications keys and how applications user them. We therefore encourage wallets to introduce a `paranoia mode` that users can activate (for instance in the wallet advanced settings) to force confirmations request for all the applications keys actions. + +## Rationale + +### Isolated paths but customisable +The proposed specifications permit to have isolation between personas and between applications. Each persona / application combination will yield a unique subtree that can be explored by the application using the structure it would like to use. + +Personas are known only by the user and its wallet, application' UID based path is computable by everyone from the application's name. And then the application decides and communicates the final levels of the path. + +Only the wallet and the user will know the full tree and where we are in the tree (depth, parents). Applications will have knowledge only of the subtree, starting after the persona. + + +### API not exposing private keys + +Applications can derive accounts and request signing from them but they will not get access to the private keys of these accounts. So when the user closes her wallet entirely, the application can not continue signing for the user. This is of course in order to keep an user's ultimate control over its accounts. + +If there is a strong demand, we could add a method that exposes the private keys for the application accounts but it would be an optional to request upon app keys initial setup. + +We indeed think that writing applications that don't need to manipulate the user private keys is a better pattern. For instance, if one needs the user to sign data while being offline, one should for instance rather implement a delegation method to an external application's controlled account rather than storing the user private key on a server that stays online. + +### Persona isolation accross applications for privacy + +The persona path is set by the user-wallet interaction and known only by them. There is thus a strict isolation between 2 different persona subpaths as if they were generated by different mnemonics. + + +Instead of personas, an alternative proposal would be to make the `application UID based path` a subset of a user's ethereum main accounts) + +Most wallets use the following derivation path for ethereum accounts: +`m/44'/60'/a'/0/n` +where a is a set of account number and n is the account index + +We could use: +`m/44'/60'/a'/0/n / [Application UID based path] / [App controlled HD subPath]` + +This way, we could use accounts as personas. + +However it does not necessarily make sense to anchor an application to a single main account. Some applications may like to interact with several "main accounts" or allow the user to change the main account they are using to deposit while keeping the same signing `app keys` accounts. Some applications may even like to use non ethereum accounts. + +Also this alternative specification HD path would not be BIP44 compliant but would be using this purpose field. + +Also it may add complexity to restore a wallet and the used accounts, one should remember which account is associated with which application and application can not suggest you which account to use because they are not aware of this part of the path. +If we don't harden the level indexes after the main account index, we could however enumerate all app keys of an user given a list a applications. We would first enumerate over the main accounts (assuming the wallet uses an [account gap limit](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#Address_gap_limit)), then over the Applications list and then over the `Application controlled HD subPath` if it allows to do so and has an account gap limit. + +For the persona specification this may not be possible, unless we impose some structure on the personas such as using a basic index. + +### Hardened and non-hardened indexes: privacy and functionality + +Hardening allows to increase privacy. If the extended public key of a parent level in the HD tree is known, public keys of its childs can not be computed if they are hardened. On the contrary if the child indexes are not hardened one can enumerate the child public keys and use that for the application design or to easily restore a wallet and it increases functionality. + +For the first parts of the HD tree, we need isolation and privacy. Thus we use hardened indexes for the persona and application paths in case some extended public key leaks at some previous level of the tree, it would protect the sub trees (of course this has no impact if private keys leak). + +For instance if we don't harden the application path, in case a persona public key is known and the application subpath does not use hardening either, one could get all `app keys` public keys for every application for this persona. + +However the app can use non hardened indexes in their custom path part to be able to benefit from guessing child public keys from parent one (for instance for counterfactual state channel interaction accross 2 peers that would like to use new keys every time they counterfactually instantiate a new sub app). + +### Alternatives for the HD derivation path + +Our proposed specification follows [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki): + +`m / purpose' / *` + +It is of course not be BIP44 compliant which uses the following tree level structure: +`m / purpose' / coin_type' / account' / change / address_index` + +One could think of alternative specifications deviating from BIP43 or even BIP32. Or on the contrary, one could try to become BIP44 compliant, although we do not really see the benefit of that for app keys and it would impose serious limitations on how to identify the applications using potentially the `coin_type` field. + + +### HD derivation path purpose field + +If we agree on not using BIP44 but following BIP32 and BIP43, we need to settle on a purpose field. We can either use the 3 depth path proposed here (https://github.com/bitcoin/bips/pull/523) or try to rech agreement on a one depth path. A one depth path should however avoid collision. This can be achieves by either submitting a BIP or by maintening a list of BIP 43 purpose fields. + +We did not find a list of BIP43 purpose code so here is what we could gather: + + +| code | Reference | Title | +|------|--------------------------------------------------------------------------|-------| +| 44 | [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) | Multi-Account Hierarchy for Deterministic Wallets | +| 45 | [BIP45](https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki) | Structure for Deterministic P2SH Multisignature Wallets| +| 48 | [SLIP48](https://github.com/satoshilabs/slips/issues/49) | Deterministic Key Hierarchy for Graphene-based Networks | +| 49 | [BIP49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki) | Derivation scheme for P2WPKH-nested-in-P2SH based accounts | +| 80 | [BIP80](https://github.com/bitcoin/bips/blob/master/bip-0080.mediawiki) | Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets | +| 84 | [BIP84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki) | Derivation scheme for P2WPKH based accounts | +| 535348 | [Ledger app ssh](https://github.com/LedgerHQ/ledger-app-ssh-agent/blob/master/getPublicKey.py#L49) | | +| 80475047| [GPG/SSH Ledger](https://github.com/LedgerHQ/ledger-app-openpgp-card/blob/master/doc/developper/gpgcard3.0-addon.rst#deterministic-key-derivation)| | +| 1775 | EIP1775 | App Keys: application specific wallet accounts | + + +### Application's identification + +#### Favoring a deterministic scheme for application uids + +Quoting Vitalik in his post [Meta: we should value privacy more](https://ethereum-magicians.org/t/meta-we-should-value-privacy-more/2475), we indeed favor a deterministic scheme for applications specific accounts generation: + +``` +It would be nice to keep wallet software stateless, so users can easily export and import their keys between wallets; this implies using some deterministic scheme like privkey_for_dapp = hash(master_key + dapp_id). But then what is the dapp_id? How would that work for multi-contract dapps? +``` +And we proposed to use the ENS domain hash, or node, as the dapp_id and to use a BIP32 structure instead to derive the private keys. + +#### Alternative: using a centraly maintened index of application uids + +[EIP1581: Non-wallet usage of keys derived from BIP32 trees](https://eips.ethereum.org/EIPS/eip-1581) +also discussed [here](https://ethereum-magicians.org/t/non-wallet-usage-of-keys-derived-from-bip-32-trees/1817/4) proposes a scheme that relies on a list of indexes where application should register (similar to SLIP44 list for instance). + +We think our approach while also being more englobing benefits from not requiring a centrally maintained registry. In our approach every application has already a potential unique identifier assigned to it. + + +#### Shortening the Hash node + +Our current approach uses identification through an ENS name converted to a hash node and sliced fully but one could potentially keep only the first 16 bytes of the node for instance and slice them similarly. This may increase the chance of app collision but we probably can reduce the lenght while retaining an injective mapping from strings to hashes. + +#### Alternative application identification specification + +For the application unique identifiers, an alternative specification could favor using an `ethereum author address` and including a signed message challenge for author for authentication. + +It would also need to specify how to decompose this address. +The same reasoning as before would apply, if we use an `eth address` of 20 bytes, 160 bits + +e.g. 0x9df77328a2515c6d529bae90edf3d501eaaa268e + +``` +x = x0 || x1 || x2 || x3 || x4 || x5 +``` +where `x0` to `x4` are 30 bits and `x5` is 10 bits. + + +or alternatively equal length +``` +x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7 +``` +where `x0` to `x7` are 20 bits. + + +Another alternative could be to use the plain website url and get rid of ens altogether but it would require another way to authenticate applications. See for instance [SLIP13](https://github.com/satoshilabs/slips/blob/master/slip-0013.md) for such a proposal. + +### Application's authentication + +For authentication we use DNS and ENS resolution, and browsing to a given url resolved. A few comments on this: + +A few comments in case of ENS resolution: +* First connection requires the wallet to connect to ethereum mainnet, but once first resolution is done we could use some metadata paramater such as `author address` for a blockchain less authentication of the application (e.g. application server signs a challenge message with the author address resolved in the ENS metadata). + +* The url the name resolves to through ENS can change without the user knowing and then a different application/website may be granted access to his app keys. But this means the ENS name owner address was copromised. This would be similar to using a signing challenge authentified by a known public key. If this known public key is compromised we have a similar problem. + +* Homoglyph attacks are not a bigger problem for `app keys` than it is for ENS since it will not grant access to `app keys` from the real domain (they would be derived along a different path). However homoglyph applications may lure the user to send funds from her main account to an `app key` of a malicious homoglyphic domain. + +Other metadata resolution through ENS that can be used alongside: +* `author address`: already mentionned above +* `contract address`: For app keys that would be designed to interact with a given ethereum contract (for instance app keys for a given token, if one desires to do so), other metadata fields could be used such as contract addresses. +* [TBD] + +In relation to the SLIP13 proposal mentionned above, one could think of alternative specifications that would use some certificate for authentication similar to https. + +### An Account gap limit standard for application controlled hd sub-path? + +If applications don't enumerate through their hd sub-path structure, we won't be able to restore `app keys` accounts by enumeration. However it has benefits to give total freedom to applications over the way they create accounts and use their sub-path. Also, it may be safe to assume that the part of the restoring procedure will be carried by the application itself and not by the wallets. The application will need a way to remember what accounts were derived for each user. + + +### Privacy and the funding trail + +If all an application needs to do with its keys is to sign messages and it does not require funding, then this EIP allows for privacy through the use of distinct keys for each application with a simple deterministic standard compatible across wallets. + +However if these application keys require funding, there can be trail and the use of app keys would not fully solve the privacy problem there. + +Mixers or anonymous ways of funding an ethereum address (ring signatures) along with this proposal would guarantee privacy. + +Even if privacy is not solved fully without this anonymous funding method, we still need a way to easily create and restore different accounts/addresses for each application + +## Backwards Compatibility + +From a wallet point of view, there does not seem to be incompatibities since these are separate accounts from those that were used previously by wallets and they are supposed to be used along-side in synergy. + +However, for applications that associated in some way their users to their main accounts ethereum addresses may want to reflect on if and how they would like to leverage the power offered by `app keys` to migrate to them and increase their user's privacy, security and potentially also user-flow. + + + +## Test Cases + +[TBD] + +Provide some examples of accounts derived from a given mnemonic, persona, application and application's custom subpath. + +## Implementation + +[WIP] +[See here for an early implementation of the HD methods](https://github.com/Bunjin/appKeys) + +## Example use cases + +* signing transactions without broadcasting them +https://github.com/MetaMask/metamask-extension/issues/3475 + +* token contract +https://github.com/ethereum/EIPs/issues/85 + +* default account for dapps +https://ethereum-magicians.org/t/default-accounts-for-dapps/904 + +* non wallet/crypto accounts +[EIP1581: Non-wallet usage of keys derived from BIP32 trees](https://eips.ethereum.org/EIPS/eip-1581) + +* state channel application + +* privacy solution + +* non custodian cross cryptocurrency exchange... + +## Acknowledgements +MetaMask team, Christian Lundkvist, Counterfactual team, Liam Horne, Erik Bryn, Richard Moore, Jeff Coleman. + + +## References + +### HD and mnemonics +#### BIPs +* [BIP32: Hierarchical Deterministic Wallets:](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) + +* [BIP39: Mnemonic code for generating deterministic keys:](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) + +* [BIP43: Purpose Field for Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) + +* [BIP44: Multi-Account Hierarchy for Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#Address_gap_limit) + +* [SLIP44: Registered coin types for BIP44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) + +* [Is there a comprehensive list of registered BIP43 purposes?](https://bitcoin.stackexchange.com/questions/60470/is-there-a-comprehensive-list-of-registered-bip43-purposes) + +#### Derivation path for eth +* [Issue 84](https://github.com/ethereum/EIPs/issues/84) + +* [Issue 85](https://github.com/ethereum/EIPs/issues/85) + +* [EIP600 Ethereum purpose allocation for Deterministic Wallets](https://eips.ethereum.org/EIPS/eip-600) + + +* [EIP601 Ethereum hierarchy for deterministic wallets](https://eips.ethereum.org/EIPS/eip-601) + +#### Accounts Privacy + + +### ENS +* [EIP137: Ethereum Domain Name Service - specification](https://eips.ethereum.org/EIPS/eip-137) + +* [EIP165: Standard Interface Detection](https://eips.ethereum.org/EIPS/eip-165) + +* [EIP634: Storage of text record in ENS](https://eips.ethereum.org/EIPS/eip-634) + +* [ENS docs about namehash:](http://docs.ens.domains/en/latest/implementers.html#namehash) + +### Previous proposals and discussions related to app keys +* [Meta: we should value privacy more](https://ethereum-magicians.org/t/meta-we-should-value-privacy-more/2475) + +* [EIP1102: Opt-in account exposure](https://eips.ethereum.org/EIPS/eip-1102) + +* [EIP1581: Non-wallet usage of keys derived from BIP-32 trees](https://eips.ethereum.org/EIPS/eip-1581) + +* [EIP1581: discussion](https://ethereum-magicians.org/t/non-wallet-usage-of-keys-derived-from-bip-32-trees/1817/4) + +* [SLIP13: Authentication using deterministic hierarchy](https://github.com/satoshilabs/slips/blob/master/slip-0013.md) + + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 8e0595b9c697b1ba225d1c61c7780772fc167e7c Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Tue, 7 May 2019 01:20:07 -0400 Subject: [PATCH 188/431] Automatically merged updates to draft EIP(s) 1155 (#1997) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 107 +++++++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index afcd5bfb..cb1f8459 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -184,60 +184,95 @@ interface ERC1155TokenReceiver { ### Safe Transfer Rules -To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate, a list of rules follows: +To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate with respect to the ERC1155TokenReceiver, a list of scenarios and rules follows. +#### Scenarios + +**_Scenario:_** The recipient is not a contract. * onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA account. + +**_Scenario:_** The transaction is not a mint/transfer of a token. * onERC1155Received and onERC1155BatchReceived MUST NOT be called outside of a mint or transfer process. -##### When the recipient is a contract: +**_Scenario:_** The receiver does not implement the necessary ERC1155TokenReceiver interface function(s). +* The transfer MUST be reverted with the one caveat below. + - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. -* The onERC1155Received hook MUST be called every time one and only one token type is transferred to an address in the transaction. -* The onERC1155Received hook MUST NOT be called when more than one token type is transferred to an address in the transaction. -* The onERC1155BatchReceived hook MUST be called when more than one token type is transferred to an address in the transaction with the entire list of what was transferred to it. -* The onERC1155BatchReceived hook MUST NOT be called when only one token type is transferred to an address in the transaction. +**_Scenario:_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but returns an unknown value. +* The transfer MUST be reverted. -* If implementation specific functions are used to transfer 1155 tokens to a contract the appropriate hook MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. -* If the destination/to contract does not implement the appropriate hook the transfer MUST be reverted with the one caveat below. - - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. +**_Scenario:_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but throws an error. +* The transfer MUST be reverted. -* When calling either onERC1155Received or onERC1155BatchReceived: - - operator MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). - - from MUST be the address of the holder whose balance is decreased. - - to MUST be the address of the recipient whose balance is increased. - - from MUST be 0x0 for a mint. - - data MUST contain the extra information provided by the sender (if any) for a transfer. - - the hook MUST be called after all the balances in the transaction have been updated to match the senders intent. +**_Scenario:_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of one and only one balance change in the transaction (eg. safeTransferFrom called). +* All the balances in the transaction MUST have been updated to match the senders intent before any hook is called on a recipient. +* The appropriate choice of either onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. +* The onERC1155Received hook SHOULD be called on the recipient contract and its rules followed. + - If this hook is called it MUST NOT be called again on the recipient in this transaction. + - See "onERC1155Received common rules" for further rules that MUST be followed. +* The onERC1155BatchReceived hook MAY be called on the recipient contract and its rules followed + - See "onERC1155BatchReceived common rules" for further rules that MUST be followed. -* When calling onERC1155Received - - id MUST be the token type being transferred. - - value MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. - - If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. +**_Scenario:_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of more than one balance change in the transaction (eg. safeBatchTransferFrom called). +* All the balances in the transaction MUST have been updated to match the senders intent before any hook is called on a recipient. +* The appropriate choice of either onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. +* The onERC1155BatchReceived hook SHOULD be called on the recipient contract and its rules followed. + - If called the arguments MUST contain/list information on every balance change for the recipient (and only the recipient) in this transaction. + - See "onERC1155BatchReceived common rules" for further rules that MUST be followed. +* The onERC1155Received hook MAY be called on the recipient contract and its rules followed. + - If called it MUST be repeatedly called until information has been passed and return value checked for every balance change for the recipient (and only the recipient) in this transaction. + - See "onERC1155Received common rules" for further rules that MUST be followed. + +#### Rules -* When calling onERC1155BatchReceived - - ids MUST be the list of tokens being transferred. - - values MUST be the list of number of tokens (specified in ids) the holder balance is decreased by and match what the recipient balance is increased by. - - If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. - -* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` for onERC1155Received or `bytes4(keccak256("accept_batch_erc1155_tokens()"))` for onERC1155BatchReceived. - - If such explicit acceptance happens the transfer MUST be completed, unless other conditions apply. +**_onERC1155Received common rules:_** +* If this hook is called onERC1155BatchReceived MUST NOT also be called on the recipient in this transaction. +* The _operator argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +* The _from argument MUST be the address of the holder whose balance is decreased. + - _from MUST be 0x0 for a mint. +* The _id argument MUST be the token type being transferred. +* The _value MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. +* The _data argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` + - If the return value is `bytes4(keccak256("accept_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. * The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - - If such explicit rejection happens, the transfer MUST be reverted with the one caveat below. - - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. - -* A solidity example of the keccak256 generated constants for the return magic is: + - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. +* If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. + +**_onERC1155BatchReceived common rules:_** +* If this hook is called onERC1155Received MUST NOT also be called on the recipient in this transaction. +* If this hook is called it MUST NOT be called again on the recipient in this transaction. +* The _operator argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +* The _from argument MUST be the address of the holder whose balance is decreased. + - _from MUST be 0x0 for a mint. +* The _ids argument MUST be the list of tokens being transferred. +* The _values argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. +* The _data argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` + - If the return value is `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. +* The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. + - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. +* If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. + +**_Implementation specific functions are used to transfer 1155 tokens to a contract:_** +* If implementation specific functions are used to transfer 1155 tokens to a contract the appropriate hook(s) MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. +* The appropriate events MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. + +###### A solidity example of the keccak256 generated constants for the return magic is: - bytes4 constant public ERC1155_REJECTED = 0xafed434d; // keccak256("reject_erc1155_tokens()") - bytes4 constant public ERC1155_ACCEPTED = 0x4dc21a2f; // keccak256("accept_erc1155_tokens()") - bytes4 constant public ERC1155_BATCH_ACCEPTED = 0xac007889; // keccak256("accept_batch_erc1155_tokens()") -##### Compatibility with other standards +#### Compatibility with other standards There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC721 at time of writing. -To cater for this there is some leeway with the rejection logic should a contract return `bytes4(keccack256("reject_erc1155_tokens()"))` from the call to onERC1155Received/onERC1155BatchReceived as detailed in the main "Safe Transfer Rules" section above. -In this case the hybrid implementation MAY now follow the secondary standard's rules when transferring token(s) to a contract address. +To cater for this there is some leeway with the rejection logic should a contract not implement the ERC1155TokenReceiver as per "Safe Transfer Rules" section above, specifically the scenario "The receiver does not implement the necessary ERC1155TokenReceiver interface function(s)". +In that particular scenario if the 1155 implementation is also a hybrid implementation of another token standard, it MAY now follow the secondary standard's rules when transferring token(s) to a contract address. -Note however it is recommended that a hybrid solution NOT be followed and a pure implementation of a single standard is followed instead, as a hybrid solution is an unproven method to date. +*__Note that a pure implementation of a single standard is recommended__* rather than a hybrid solution, but an example of a hybrid 1155+721 contract is linked in the references section under implementations. + +An important consideration is that even if the tokens are sent with another standard's rules the *__1155 transfer events MUST still be emitted.__* This is so the balances can still be determined via events alone as per 1155 standard rules. -An example of a hybrid 1155+721 contract is linked in the references section under implementations. ### Metadata From b54ebee91a21fcff62a3d36ef583c7e2a9a926bb Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Tue, 7 May 2019 01:55:36 -0400 Subject: [PATCH 189/431] Automatically merged updates to draft EIP(s) 1155 (#1998) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index cb1f8459..6ceeeb4e 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -254,8 +254,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. * If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. -**_Implementation specific functions are used to transfer 1155 tokens to a contract:_** -* If implementation specific functions are used to transfer 1155 tokens to a contract the appropriate hook(s) MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. +**_Implementation specific transfer api rules:_** +* If implementation specific api functions are used to transfer 1155 tokens to a contract the appropriate hook(s) MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. * The appropriate events MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. ###### A solidity example of the keccak256 generated constants for the return magic is: From 3230d9eabc7b1373851db80d813a670ffe385bbb Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 7 May 2019 21:36:14 +0200 Subject: [PATCH 190/431] Automatically merged updates to draft EIP(s) 777 (#1945) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-777.md | 317 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 267 insertions(+), 50 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 460482f2..298dd755 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -67,7 +67,10 @@ interface ERC777Token { function granularity() external view returns (uint256); function defaultOperators() external view returns (address[] memory); - function isOperatorFor(address operator, address holder) external view returns (bool); + function isOperatorFor( + address operator, + address holder + ) external view returns (bool); function authorizeOperator(address operator) external; function revokeOperator(address operator) external; @@ -81,7 +84,12 @@ interface ERC777Token { ) external; function burn(uint256 amount, bytes calldata data) external; - function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external; + function operatorBurn( + address from, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; event Sent( address indexed operator, @@ -91,9 +99,24 @@ interface ERC777Token { bytes data, bytes operatorData ); - event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); - event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); - event AuthorizedOperator(address indexed operator, address indexed holder); + event Minted( + address indexed operator, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); + event Burned( + address indexed operator, + address indexed from, + uint256 amount, + bytes data, + bytes operatorData + ); + event AuthorizedOperator( + address indexed operator, + address indexed holder + ); event RevokedOperator(address indexed operator, address indexed holder); } ``` @@ -101,9 +124,11 @@ The token contract MUST implement the above interface. The implementation MUST follow the specifications described below. The token contract MUST register the `ERC777Token` interface with its own address via [ERC1820]. -This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry -with the token contract address as both the address and the implementer -and the `keccak256` hash of `ERC777Token` as the interface hash. + +> This is done by calling the `setInterfaceImplementer` function on the [ERC1820] registry +> with the token contract address as both the address and the implementer +> and the `keccak256` hash of `ERC777Token` (`0xac7fbab5f54a3ca8194167523c6753bfeb96a445279294b6125b68cce2177054`) +> as the interface hash. If the contract has a switch to enable or disable ERC777 functions, every time the switch is triggered, the token MUST register or unregister the `ERC777Token` interface for its own address accordingly via ERC1820. @@ -112,7 +137,7 @@ the `keccak256` hash of `ERC777Token` as the interface hash and `0x0` as the imp (See [Set An Interface For An Address][erc1820-set] in [ERC1820] for more details.) When interacting with the token contract, all amounts and balances MUST be unsigned integers. -I.e. Internally, all values are stored as a denomination of 1E-18 of a token. +I.e. internally, all values are stored as a denomination of 1E-18 of a token. The display denomination—to display any amount to the end user—MUST be 1018 of the internal denomination. @@ -204,7 +229,7 @@ The following rules MUST be applied regarding the *granularity*: - The *granularity* value MUST NOT be changed, ever. -- The *granularity* value MUST be greater or equal to `1`. +- The *granularity* value MUST be greater than or equal to `1`. - All balances MUST be a multiple of the granularity. @@ -214,7 +239,7 @@ The following rules MUST be applied regarding the *granularity*: - Any operation that would result in a balance that's not a multiple of the *granularity* value MUST be considered invalid, and the transaction MUST `revert`. -*NOTE*: Most of the tokens SHOULD be fully partition-able. +*NOTE*: Most tokens SHOULD be fully partition-able. I.e., this function SHOULD return `1` unless there is a good reason for not allowing any fraction of the token. > **identifier:** `556f0dc7` @@ -258,7 +283,7 @@ The rules below apply to *default operators*: - `AuthorizedOperator` events MUST NOT be emitted when defining *default operators*. -- A *holder* MUST be allowed revoke a *default operator* +- A *holder* MUST be allowed to revoke a *default operator* (unless the *holder* is the *default operator* in question). - A *holder* MUST be allowed to re-authorize a previously revoked *default operator*. @@ -371,7 +396,10 @@ as an *operator* for itself (i.e., if `operator` is equal to `msg.sender`). **`isOperatorFor` function** ``` solidity -function isOperatorFor(address operator, address holder) external view returns (bool) +function isOperatorFor( + address operator, + address holder +) external view returns (bool) ``` Indicate whether the `operator` address is an *operator* of the `holder` address. @@ -427,6 +455,10 @@ The token contract MUST `revert` when sending in any of the following cases: - Any of the resulting balances becomes negative, i.e. becomes less than zero (`0`). +- The `tokensToSend` hook of the *holder* `revert`s. + +- The `tokensReceived` hook of the *recipient* `revert`s. + The token contract MAY send tokens from many *holders*, to many *recipients*, or both. In this case: - The previous send rules MUST apply to all the *holders* and all the *recipients*. @@ -438,7 +470,7 @@ The token contract MAY send tokens from many *holders*, to many *recipients*, or *NOTE*: Mechanisms such as applying a fee on a send is considered as a send to multiple *recipients*: the intended *recipient* and the fee *recipient*. -*NOTE*: Transfer of tokens MAY be chained. +*NOTE*: Movements of tokens MAY be chained. For example, if a contract upon receiving tokens sends them further to another address. In this case, the previous send rules apply to each send, in order. @@ -468,7 +500,14 @@ In most of the cases the recipient would ignore the `operatorData`, or at most, **`Sent` event** ``` solidity -event Sent(address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData) +event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData +) ``` Indicate a send of `amount` of tokens from the `from` address to the `to` address by the `operator` address. @@ -505,7 +544,13 @@ The *operator* and the *holder* MUST both be the `msg.sender`. **`operatorSend` function** ``` solidity -function operatorSend(address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external +function operatorSend( + address from, + address to, + uint256 amount, + bytes calldata data, + bytes calldata operatorData +) external ``` Send the `amount` of tokens on behalf of the address `from` to the address `to`. @@ -536,7 +581,7 @@ as the minting process is generally specific for every token. Nonetheless, the rules below MUST be respected when minting for a *recipient*: -- Tokens MAY be minted for any *recipient* address. +- Tokens MAY be minted for any *recipient* address (except `0x0`). - The total supply MUST be increased by the amount of tokens minted. @@ -557,6 +602,7 @@ The token contract MUST `revert` when minting in any of the following cases: - The resulting *recipient* balance after the mint is not a multiple of the *granularity* defined by the token contract. - The *recipient* is a contract, and it does not implement the `ERC777TokensRecipient` interface via [ERC1820]. - The address of the *recipient* is `0x0`. +- The `tokensReceived` hook of the *recipient* `revert`s. *NOTE*: The initial token supply at the creation of the token contract MUST be considered as minting for the amount of the initial supply to the address(es) receiving the initial supply. @@ -588,7 +634,13 @@ The `tokensReceived()` hooks MAY use the information to decide if it wish to rej **`Minted` event** ``` solidity -event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData) +event Minted( + address indexed operator, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData +) ``` Indicate the minting of `amount` of tokens to the `to` address by the `operator` address. @@ -612,7 +664,7 @@ The token contract MAY also define other functions to burn tokens. The rules below MUST be respected when burning the tokens of a *holder*: -- Tokens MAY be burned from any *holder* address. +- Tokens MAY be burned from any *holder* address (except `0x0`). - The total supply MUST be decreased by the amount of tokens burned. @@ -640,6 +692,8 @@ The token contract MUST `revert` when burning in any of the following cases: - The address of the *holder* is `0x0`. +- The `tokensToSend` hook of the *holder* `revert`s. + *[ERC20] compatibility requirement*: While a `Sent` event MUST NOT be emitted when burning; if the token contract is [ERC20] enabled, a `Transfer` event with the `to` parameter set to `0x0` SHOULD be emitted. @@ -664,7 +718,13 @@ MAY use the information to decide if they wish to reject the transaction. **`Burned` event** ``` solidity -event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); +event Burned( + ddress indexed operator, + address indexed from, + uint256 amount, + bytes data, + bytes operatorData +); ``` Indicate the burning of `amount` of tokens from the `from` address by the `operator` address. @@ -674,7 +734,7 @@ Indicate the burning of `amount` of tokens from the `from` address by the `opera > **parameters** > `operator`: Address which triggered the burn. > `from`: *Holder* whose tokens were burned. -> `amount`: Number of tokens burned. +> `amount`: Number of tokens burned. > `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. @@ -693,13 +753,18 @@ The *operator* and the *holder* MUST both be the `msg.sender`. > **identifier:** `fe9d9303` > **parameters** -> `amount`: Number of tokens to burn. +> `amount`: Number of tokens to burn. > `data`: Information provided by the *holder*. **`operatorBurn` function** ``` solidity -function operatorBurn(address from, uint256 amount, bytes calldata data, bytes calldata operatorData) external +function operatorBurn( + address from, + uint256 amount, + bytes calldata data, + bytes calldata operatorData +) external ``` Burn the `amount` of tokens on behalf of the address `from`. @@ -729,6 +794,12 @@ The `tokensToSend` hook notifies of any request to decrement the balance (send a Any address (regular or contract) wishing to be notified of token debits from their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. +> This is done by calling the `setInterfaceImplementer` function on the [ERC1820] registry +> with the *holder* address as the address, +> the `keccak256` hash of `ERC777TokensSender` +> (`0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895`) as the interface hash, +> and the address of the contract implementing the `ERC777TokensSender` as the implementer. + ``` solidity interface ERC777TokensSender { function tokensToSend( @@ -750,7 +821,14 @@ but said address MUST implement the interface on its behalf. **`tokensToSend`** ``` solidity -function tokensToSend(address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData) external +function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData +) external ``` Notify a request to send or burn (if `to` is `0x0`) an `amount` tokens from the `from` address to the `to` address @@ -769,26 +847,26 @@ by the `operator` address. The following rules apply when calling the `tokensToSend` hook: -- The `tokensToSend` hook MUST be called every time the balance is decremented. +- The `tokensToSend` hook MUST be called for every send and burn processes. - The `tokensToSend` hook MUST be called *before* the state is updated—i.e. *before* the balance is decremented. -- `operator` MUST be the address which triggered the decrease of the balance. +- `operator` MUST be the address which triggered the send or burn process. -- `from` MUST be the address of the *holder* whose balance is decreased. +- `from` MUST be the address of the *holder* whose tokens are sent or burned. -- `to` MUST be the address of the *recipient* whose balance is increased for a send. +- `to` MUST be the address of the *recipient* which receives the tokens for a send. - `to` MUST be `0x0` for a burn. -- `amount` MUST be the number of tokens the *holder* balance is decreased by. +- `amount` MUST be the number of tokens the *holder* sent or burned. -- `data` MUST contain the extra information provided by the *holder* (if any) for a send. +- `data` MUST contain the extra information (if any) provided to the send or the burn process. - `operatorData` MUST contain the extra information provided by the address which triggered the decrease of the balance (if any). -- The *holder* MAY block a decrease of its balance by `revert`ing. +- The *holder* MAY block a send or burn process by `revert`ing. (I.e., reject the withdrawal of tokens from its account.) *NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensSender`. @@ -809,6 +887,12 @@ The `tokensReceived` hook notifies of any increment of the balance (send and min Any address (regular or contract) wishing to be notified of token credits to their address MAY register the address of a contract implementing the `ERC777TokensSender` interface described below via [ERC1820]. +> This is done by calling the `setInterfaceImplementer` function on the [ERC1820] registry +> with the *recipient* address as the address, +> the `keccak256` hash of `ERC777TokensRecipient` +> (`0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b`) as the interface hash, +> and the address of the contract implementing the `ERC777TokensRecipient` as the implementer. + ``` solidity interface ERC777TokensRecipient { function tokensReceived( @@ -838,7 +922,14 @@ but said address MUST implement the interface on its behalf. **`tokensReceived`** ``` solidity -function tokensReceived(address operator, address from, address to, uint256 amount, bytes calldata data, bytes calldata operatorData) external +function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata data, + bytes calldata operatorData +) external ``` Notify a send or mint (if `from` is `0x0`) of `amount` tokens from the `from` address to the `to` address @@ -852,28 +943,32 @@ by the `operator` address. > `from`: *Holder* whose tokens were sent (or `0x0` for a mint). > `to`: Recipient of the tokens. > `amount`: Number of tokens the *recipient* balance is increased by. -> `data`: Information provided by the *holder*. +> `data`: Information provided by the *holder*. > `operatorData`: Information provided by the *operator*. The following rules apply when calling the `tokensReceived` hook: -- The `tokensReceived` hook MUST be called every time the balance is incremented. +- The `tokensReceived` hook MUST be called for every send and mint processes. - The `tokensReceived` hook MUST be called *after* the state is updated—i.e. *after* the balance is incremented. -- `operator` MUST be the address which triggered the increase of the balance. +- `operator` MUST be the address which triggered the send or mint process. -- `from` MUST be the address of the *holder* whose balance is decreased for a send. +- `from` MUST be the address of the *holder* whose tokens are sent for a send. - `from` MUST be `0x0` for a mint. -- `to` MUST be the address of the *recipient* whose balance is increased. +- `to` MUST be the address of the *recipient* which receives the tokens. -- `amount` MUST be the number of tokens the *recipient* balance is increased by. +- `amount` MUST be the number of tokens the *recipient* sent or minted. + +- `data` MUST contain the extra information (if any) provided to the send or the mint process. - `operatorData` MUST contain the extra information provided by the address which triggered the increase of the balance (if any). -- The *holder* MAY block an increase of its balance by `revert`ing. (I.e., reject the reception of tokens.) + +- The *holder* MAY block a send or mint process by `revert`ing. + (I.e., reject the reception of tokens.) *NOTE*: Multiple *holders* MAY use the same implementation of `ERC777TokensRecipient`. @@ -913,14 +1008,123 @@ If needed, other sizes MAY be created by converting from `SVG` into `PNG`. ## Rationale -This standard solves some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20]. -It avoids the problems and vulnerabilities of [EIP223]. +The principal intent for this standard is +to solve some of the shortcomings of [ERC20] while maintaining backward compatibility with [ERC20], +and avoiding the problems and vulnerabilities of [EIP223]. -It goes a step further by allowing *operators* (generally contracts) -which can manage the tokens in the same way that the [ERC20] with infinite `approve` was allowed. -Finally, it adds hooks to provide further control to *holders* over their tokens. -Note that, the usage of [ERC1820] provides backward compatibility with wallets and existing contracts -without having to be redeployed thanks proxy contracts implementing the hooks. +Below are the rationales for the decisions regarding the main aspects of the standards. + +*NOTE*: Jacques Dafflon ([0xjac]), one of the authors of the standard, +conjointly wrote his [master thesis] on the standard, +which goes in more details than could reasonably fit directly within the standard, +and can provide further clarifications regarding certain aspects or decisions. + +### Lifecycle + +More than just sending tokens, [ERC777] defines the entire lifecycle of a token, +starting with the minting process, followed by the sending process and terminating with the burn process. + +Having a lifecycle clearly defined is important for consistency and accuracy, +especially when value is derived from scarcity. +In contrast when looking at some [ERC20] tokens, a discrepancy can be observed +between the value returned by the `totalSupply` and the actual circulating supply, +as the standard does not clearly define a process to create and destroy tokens. + +### Data + +The mint, send and burn processes can all make use of a `data` and `operatorData` fields +which are passed to any movement (mint, send or burn). +Those fields may be empty for simple use cases, +or they may contain valuable information related to the movement of tokens, +similar to information attached to a bank transfer by the sender or the bank itself. + +The use of a `data` field is equally present in other standard proposals such as [EIP223], +and was requested by multiple members of the community who reviewed this standard. + +### Hooks + +In most cases, [ERC20] requires two calls to safely transfer tokens to a contract without locking them. +A call from the sender, using the `approve` function +and a call from the recipient using `transferFrom`. +Furthermore, this requires extra communication between the parties which is not clearly defined. +Finally, holders can get confused between `transfer` and `approve`/`transferFrom`. +Using the former to transfer tokens to a contract will most likely result in locked tokens. + +Hooks allow streamlining of the sending process and offer a single way to send tokens to any recipient. +Thanks to the `tokensReceived` hook, contracts are able to react and prevent locking tokens upon reception. + +#### **Greater Control For Holders** + +The `tokensReceived` hook also allows holders to reject the reception of some tokens. +This gives greater control to holders who can accept or reject incoming tokens based on some parameters, +for example located in the `data` or `operatorData` fields. + +Following the same intentions and based on suggestions from the community, +the `tokensToSend` hook was added to give control over and prevent the movement of outgoing tokens. + +#### **[ERC1820] Registry** + +The [ERC1820] Registry allows holders to register their hooks. +Other alternatives were examined beforehand to link hooks and holders. + +The first was for hooks to be defined at the sender's or recipient's address. +This approach is similar to [EIP223] which proposes a `tokenFallback` function on recipient contracts +to be called when receiving tokens, +but improves on it by relying on [ERC165] for interface detection. +While straightforward to implement, this approach imposes several limitations. +In particular, the sender and recipient must be contracts in order to provide their implementation of the hooks. +Preventing externally owned addresses to benefit from hooks. +Existing contracts have a strong probability not to be compatible, +as they undoubtedly were unaware and do not define the new hooks. +Consequently existing smart contract infrastructure such as multisig wallets +which potentially hold large amounts of ether and tokens would need to be migrated to new updated contracts. + +The second approach considered was to use [ERC672] which offered pseudo-introspection for addresses using reverse-ENS. +However, this approach relied heavily on ENS, on top of which reverse lookup would need to be implemented. +Analysis of this approach promptly revealed a certain degree of complexity and security concerns +which would transcend the benefits of approach. + +The third solution—used in this standard—is to rely on a unique registry +where any address can register the addresses of contracts implementing the hooks on its behalf. +This approach has the advantage that externally owned accounts and contracts can benefit from hooks, +including existing contracts which can rely on hooks deployed on proxy contracts. + +The decision was made to keep this registry in a separate EIP, +as to not over complicate this standard. +More importantly, the registry is designed in a flexible fashion, +such that other EIPs and smart contract infrastructures can benefit from it +for their own use cases, outside the realm of [ERC777] and tokens. +The first proposal for this registry was [ERC820]. +Unfortunately, issues emanating from upgrades in the Solidity language to versions 0.5 and above +resulted in a bug in a separated part of the registry, which required changes. +This was discovered right after the last call period. +Attempts made to avoid creating a separate EIP, such as [ERC820a], were rejected. +Hence the standard for the registry used for [ERC777] became [ERC1820]. +[ERC1820] and [ERC820] are functionally equivalent. [ERC1820] simply contains the fix for newer versions of Solidity. + +### Operators + +The standard defines the concept of operators as any address which moves tokens. +While intuitively every address moves its own tokens, +separating the concepts of holder and operator allows for greater flexibility. +Primarily, this originates from the fact that the standard defines a mechanism for holders +to let other addresses become their operators. +Moreover, unlike the approve calls in [ERC20] where the role of an approved address is not clearly defined, +[ERC777] details the intent of and interactions with operators, +including an obligation for operators to be approved, +and an irrevocable right for any holder to revoke operators. + +#### **Default Operators** + +Default operators were added based on community demand for pre-approved operators. +That is operators which are approved for all holders by default. +For obvious security reasons, the list of default operators is defined at the token contract creation time, +and cannot be changed. +Any holder still has the right to revoke default operators. +One of the obvious advantages of default operators is to allow ether-less movements of tokens. +Default operators offer other usability advantages, +such as allowing token providers to offer functionality in a modular way, +and to reduce the complexity for holders to use features provided through operators. ## Backward Compatibility @@ -949,7 +1153,8 @@ If the token implements [ERC20], it MUST register the `ERC20Token` interface with its own address via [ERC1820]. This is done by calling the `setInterfaceImplementer` function on the ERC1820 registry with the token contract address as both the address and the implementer -and the `keccak256` hash of `ERC20Token` as the interface hash. +and the `keccak256` hash of `ERC20Token` (`0xaea199e31a596269b42cdafd93407f14436db6e4cad65417994c2eb37381e05a`) +as the interface hash. If the contract has a switch to enable or disable ERC20 functions, every time the switch is triggered, the token MUST register or unregister the `ERC20Token` interface for its own address accordingly via ERC1820. @@ -992,17 +1197,23 @@ when sending, minting and transferring token via [ERC777] and [ERC20]: ERC777TokensRecipient
    not registered regular address - continue - continue + continue contract MUST revert + SHOULD continue1 +> 1. +> The transaction SHOULD continue for clarity as ERC20 is not aware of hooks. +> However, this can result in accidentally locked tokens. +> If avoiding accidentally locked tokens is paramount, the transaction MAY revert. + + There is no particular action to take if `tokensToSend` is not implemented. -The transfer MUST proceed and only be canceled if another condition is not respected +The movement MUST proceed and only be canceled if another condition is not respected such as lack of funds or a `revert` in `tokensReceived` (if present). During a send, mint and burn, the respective `Sent`, `Minted` and `Burned` events MUST be emitted. @@ -1035,10 +1246,16 @@ Copyright and related rights waived via [CC0]. [operators]: #operators [ERC20]: https://eips.ethereum.org/EIPS/eip-20 +[ERC165]: https://eips.ethereum.org/EIPS/eip-165 +[ERC672]: https://github.com/ethereum/EIPs/issues/672 [ERC777]: https://eips.ethereum.org/EIPS/eip-777 +[ERC820]: https://eips.ethereum.org/EIPS/eip-820 +[ERC820a]: https://github.com/ethereum/EIPs/pull/1758 [ERC1820]: https://eips.ethereum.org/EIPS/eip-1820 [erc1820-set]: https://eips.ethereum.org/EIPS/eip-1820#set-an-interface-for-an-address +[0xjac]: https://github.com/0xjac [0xjac/ERC777]: https://github.com/0xjac/ERC777 +[master thesis]: https://github.com/0xjac/master-thesis [npm/erc777]: https://www.npmjs.com/package/erc777 [ref tests]: https://github.com/0xjac/ERC777/blob/master/test/ReferenceToken.test.js [reference implementation]: https://github.com/0xjac/ERC777/blob/master/contracts/examples/ReferenceToken.sol From b0240fcbe9acee73d7735dfee5460dbfba83358c Mon Sep 17 00:00:00 2001 From: Jacques Dafflon Date: Tue, 7 May 2019 22:59:23 +0200 Subject: [PATCH 191/431] ERC777: Move to final (#1999) --- EIPS/eip-777.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EIPS/eip-777.md b/EIPS/eip-777.md index 298dd755..e57a19e6 100644 --- a/EIPS/eip-777.md +++ b/EIPS/eip-777.md @@ -3,8 +3,7 @@ eip: 777 title: ERC777 Token Standard author: Jacques Dafflon , Jordi Baylina , Thomas Shababi discussions-to: https://github.com/ethereum/EIPs/issues/777 -status: Last Call -review-period-end: 2019-05-06 +status: Final type: Standards Track category: ERC created: 2017-11-20 From 44073f86a3748f2d9494a444e2278c8ff8546764 Mon Sep 17 00:00:00 2001 From: Zachary James Williamson Date: Wed, 8 May 2019 02:10:16 +0100 Subject: [PATCH 192/431] Automatically merged updates to draft EIP(s) 1108 (#1987) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1108.md | 78 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/EIPS/eip-1108.md b/EIPS/eip-1108.md index c702d25e..94fcdf69 100644 --- a/EIPS/eip-1108.md +++ b/EIPS/eip-1108.md @@ -1,7 +1,8 @@ --- eip: 1108 title: Reduce alt_bn128 precompile gas costs -author: Antonio Salazar Cardozo (@shadowfiend) +author: Antonio Salazar Cardozo (@shadowfiend), Zachary Williamson (@zac-williamson) +discussions-to: https://ethereum-magicians.org/t/eip-1108-reduce-alt-bn128-precompile-gas-costs/3206 status: Draft type: Standards Track category: Core @@ -9,14 +10,18 @@ created: 2018-05-21 requires: 196, 197 --- -## Short Description +## Simple Summary -Recent changes to the underlying library used by the official Go reference +The elliptic curve arithmetic precompiles are currently overpriced. Re-pricing the precompiles would greatly assist a number of privacy solutions and scaling solutions on Ethereum. + +## Abstract + +Changes in 2018 to the underlying library used by the official Go reference implementation led to significant performance gains for the `ECADD`, `ECMUL`, and pairing check precompiled contracts on the `alt_bn128` elliptic curve. -What is more, the performance boost for those operations can be also observed -for Parity client. +In the Parity client, field operations used by the precompile algorithms were optimized in 2018, +and recent changes to the pairing algorithm used by the `bn` crate have brought considerable speedups. Faster operations on Ethereum clients should be reflected in reduced gas costs. @@ -33,12 +38,13 @@ note](https://github.com/ethereum/go-ethereum/pull/16301#issuecomment-372687543) the computational cost of `ECADD`, `ECMUL`, and pairing checks (excepting the constant) has dropped roughly an order of magnitude across the board. -Also, [optimisations in the bn library](https://github.com/paritytech/bn/pull/9) +Also, optimizations in the bn library [in 2018](https://github.com/paritytech/bn/pull/9) and [2019](https://github.com/paritytech/bn/pull/14) used by the [Parity client](https://github.com/paritytech/parity-ethereum) led to a significant performance boost we -[benchmarked](https://gist.github.com/pdyraga/4649b74436940a01e8221d85e80bfeef) +[benchmarked](https://gist.github.com/zac-williamson/838410a3da179d47d31b25b586c15e53) and compared against the [previous -results](https://github.com/ethereum/benchmarking/blob/master/constantinople/analysis2.md). +results](https://gist.github.com/pdyraga/4649b74436940a01e8221d85e80bfeef). + ## Specification @@ -48,15 +54,65 @@ Following is a table with the current gas cost and new gas cost: | ------------- | --------- | ----------------------------- | ------------------- | | `ECADD` | `0x06` | 500[1] | 150 | | `ECMUL` | `0x07` | 40 000[1] | 6 000 | -| Pairing check | `0x08` | 80 000 * k + 100 000[2]| 28 300 * k + 35 450 | +| Pairing check | `0x08` | 80 000 * k + 100 000[2]| 34 000 * k + 45 000 | The gas costs for `ECADD` and `ECMUL` are updates to the costs listed in EIP-196, while the gas costs for the pairing check are updates to the cost listed in EIP-197. Updated gas costs have been adjusted to the less performant -client which is Parity, according to benchmarks[3]. +client which is Parity, according to benchmarks[3]. The updated gas costs are scaled relative to the `ecrecover` precompile. i.e. in the benchmark, `ecrecover` ran in 116 microseconds. If we consider 3,000 gas the fair price for `ecrecover`, we can obtain a metric how much gas should be charged per microsecond of an algorithm's runtime, and use that to price the elliptic curve precompiles. [1]- Per [EIP-196](https://github.com/ethereum/EIPs/blob/984cf5de90bbf5fbe7e49be227b0c2f9567e661e/EIPS/eip-196.md#gas-costs). [2]- Per [EIP-197](https://github.com/ethereum/EIPs/blob/df132cd37efb3986f9cd3ef4922b15a767d2c54a/EIPS/eip-197.md#specification). -[3]- [Parity benchmarks.](https://gist.github.com/pdyraga/4649b74436940a01e8221d85e80bfeef) +[3]- [Parity benchmarks.](https://gist.github.com/zac-williamson/838410a3da179d47d31b25b586c15e53) + +## Rationale + +### Existing protocols would benefit immensely from cheaper elliptic curve cryptography + +Fast elliptic curve cryptography is a keystone of a growing number of protocols built on top of Ethereum. To list a few: + +* [The AZTEC protocol](https://github.com/AztecProtocol/AZTEC) utilizes the elliptic curve precompiles to construct private tokens, with zero-knowledge transaction logic, via the [ERC1723](https://github.com/ethereum/EIPs/issues/1723) and [ERC1724](https://github.com/ethereum/EIPs/issues/1724) standard. +* [Matter Labs](https://github.com/matter-labs/matter-network) utilizes the precompiles to implement Ignis, a scaling solution with a throughput of 500txns per second +* [Rollup](https://github.com/rollup/rollup) utilizes the precompiles to create L2 scaling solutions, where the correctness of transactions is gauranteed by main-net, without an additional consensus layer +* [ZEther](https://crypto.stanford.edu/~buenz/papers/zether.pdf) uses precompiles `ECADD` and `ECMUL` to construct confidential transactions + +These are all technologies that have been, or are in the process of being, deployed to main-net. There protocols would all benefit from reducing the gas cost of the precompiles. + +To give a concrete example, it currently costs `820,000` gas to validate the cryptography in a typical AZTEC confidential transaction. If the gas schedule for the precompiles correctly reflected their load on the Ethereum network, this cost would be `197,000` gas. This significantly increases the potential use cases for private assets on Ethereum. AZTEC is planning to deploy several cryptographic protocols Ethereum, but these are at the limits of what is practical given the current precompile costs: + +* Confidential weighted voting +* Partial-order filling over encrypted orders, for private decentralized exchanges +* Anonymous identity sharing proofs (e.g. proving you are on a whitelist, without revealing who you are) +* Many-to-one payments and one-to-many confidential payments, as encrypted communication channels between main-net and L2 applications + +For zk-SNARK based protocols on Ethereum, EIP-1108 will not only reduce the gas costs of verifying zk-SNARKs substantially, but can also aid in [batching together multiple zk-SNARK proofs](https://github.com/matter-labs/Groth16BatchVerifier). This is also a technique that can be used to split up monolithic zk-SNARK circuits into a batch of zk-SNARKs with smaller individual circuit sizes, which makes zk-SNARKs both easier to construct and deploy. + +ZEther transactions currently cost ~`6,000,000` gas. This EIP would reduce this to ~`1,000,000` gas, which makes the protocol more practical. + +To summarise, there are several protocols that currently exist on main-net, that would benefit immensely from this EIP. Elliptic curve cryptography can provide valuable solutions for Ethereum, such as scaling and privacy, and the scope and scale of these solutions can be increased if the gas costs for the `bn128` precompiles accurately reflects their computational load on the network. + +### Cheaper elliptic curve cryptography can be used to trade storage for computation + +Solutions such as Rollup and Ignis can be used to batch groups of individual transactions into a zk-SNARK proof, with the on-chain state being represented by a small Merkle root, instead of multiple account balances. + +If zk-SNARK verification costs are decreased, these solutions can be deployed for a wider range of use cases and more Rollup-style transactions can be processed per block. + +### Parity and Geth already have fast algorithms that justify reduced gas costs + +This EIP does not require Parity or Geth to deploy new cryptographic libraries, as fast bn128 algorithms have already been integrated into these clients. This goal of proposing this EIP for Istanbul, is to supplement [EIP-1829](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1829.md) (arithmetic over generic elliptic curves), providing an immediate solution to the pressing problem of expensive cryptography, while more advanced solutions are developed, defined and deployed. + + +## Test Cases + +As no underlying algorithms are not being changed, there are no additional test cases to specify. + +## Implementation + +Both the Parity and Geth clients have already implemented cryptographic libraries that are fast enough to justify reducing the precompile gas costs. As a reference, here are a list of elliptic curve libraries, in `C++`, `golang` and `rust`, that support the `bn128` curve, and have run-times that are equal to or faster than the Parity benchmarks. + +* [Parity bn crate (rust)](https://github.com/paritytech/bn) +* [Geth bn256 library (golang)](https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare) +* [MCL, a portable C++ pairing library](https://github.com/herumi/mcl) +* [Libff, a C++ pairing library used in many zk-SNARK libraries](https://github.com/scipr-lab/libff) From 6f4a947ff039135b62c732464e7ceabeb6587a35 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 8 May 2019 10:36:26 -0400 Subject: [PATCH 193/431] Fix typos (#1899) --- EIPS/eip-1.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 039a2148..0cdc16e7 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -23,7 +23,7 @@ For Ethereum implementers, EIPs are a convenient way to track the progress of th There are three types of EIP: -- A **Standard Track EIP** describes any change that affects most or all Ethereum implementations, such as a change to the 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 Ethereum. Furthermore Standard EIPs can be broken down into the following categories. Standards Track EIPs consist of three parts, a design document, implementation, and finally if warranted an update to the [formal specification]. +- A **Standard Track EIP** describes any change that affects most or all Ethereum 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 Ethereum. Furthermore Standard EIPs can be broken down into the following categories. Standards Track EIPs consist of three parts, a design document, implementation, and finally if warranted an update to the [formal specification]. - **Core** - improvements requiring a consensus fork (e.g. [EIP5], [EIP101]), as well as changes that are not necessarily consensus critical but may be relevant to [“core dev” discussions](https://github.com/ethereum/pm) (for example, [EIP90], and the miner/node strategy changes 2, 3, and 4 of [EIP86]). - **Networking** - includes improvements around [devp2p] ([EIP8]) and [Light Ethereum Subprotocol], as well as proposed improvements to network protocol specifications of [whisper] and [swarm]. - **Interface** - includes improvements around client [API/RPC] specifications and standards, and also certain language-level standards like method names ([EIP6]) and [contract ABIs]. The label “interface” aligns with the [interfaces repo] and discussion should primarily occur in that repository before an EIP is submitted to the EIPs repository. @@ -39,7 +39,7 @@ An EIP must meet certain minimum criteria. It must be a clear and complete descr Parties involved in the process are you, the champion or *EIP author*, the [*EIP editors*](#eip-editors), and the [*Ethereum Core Developers*](https://github.com/ethereum/pm). -:warning: Before you begin, vet your idea, this will save you time. Ask the Ethereum community first if an idea is original to avoid wasting time on something that will be be rejected based on prior research (searching the Internet does not always do the trick). 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 Ethereum is used. Examples of appropriate public forums to gauge interest around your EIP include [the Ethereum subreddit], [the Issues section of this repository], and [one of the Ethereum Gitter chat rooms]. In particular, [the Issues section of this repository] is an excellent place to discuss your proposal with the community and start creating more formalized language around your EIP. +:warning: Before you begin, vet your idea, this will save you time. Ask the Ethereum 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). 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 Ethereum is used. Examples of appropriate public forums to gauge interest around your EIP include [the Ethereum subreddit], [the Issues section of this repository], and [one of the Ethereum Gitter chat rooms]. In particular, [the Issues section of this repository] is an excellent place to discuss your proposal with the community and start creating more formalized language around your EIP. Your role as the champion is to write the EIP using the style and format described below, shepherd the discussions in the appropriate forums, and build community consensus around the idea. Following is the process that a successful EIP will move along: @@ -89,7 +89,7 @@ Each EIP should have the following parts: ## EIP Formats and Templates EIPs should be written in [markdown] format. -Image files should be included in a subdirectory of the `assets` folder for that EIP as follow: `assets/eip-X` (for eip **X**). When linking to an image in the EIP, use relative links such as `../assets/eip-X/image.png`. +Image files should be included in a subdirectory of the `assets` folder for that EIP as follows: `assets/eip-X` (for eip **X**). When linking to an image in the EIP, use relative links such as `../assets/eip-X/image.png`. ## EIP Header Preamble @@ -169,7 +169,7 @@ The `created` header records the date that the EIP was assigned a number. Both h #### `updated` header -The `updated` header records the date(s) when the EIP was updated with "substantional" changes. This header is only valid for EIPs of Draft and Active status. +The `updated` header records the date(s) when the EIP was updated with "substantial" changes. This header is only valid for EIPs of Draft and Active status. #### `requires` header From 0797b928db3ffc50ff980aacfe3496bd1dfe2209 Mon Sep 17 00:00:00 2001 From: Mohamed Abdulaziz Date: Wed, 8 May 2019 18:22:40 +0300 Subject: [PATCH 194/431] Fixed typos and grammar (#1847) --- EIPS/eip-1829.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1829.md b/EIPS/eip-1829.md index c19892e6..0a075ea3 100644 --- a/EIPS/eip-1829.md +++ b/EIPS/eip-1829.md @@ -14,7 +14,7 @@ created: 2019-03-06 ## Simple Summary -Currently the EVM only supports *secp261k1* in a limited way through `ecrecover` and *altbn128* through two pre-compiles. There are draft proposals to add more curves. There are many more elliptic curve that have useful application for integration with existing systems or newly developed curves for zero-knownledge proofs. +Currently the EVM only supports *secp261k1* in a limited way through `ecrecover` and *altbn128* through two pre-compiles. There are draft proposals to add more curves. There are many more elliptic curve that have useful application for integration with existing systems or newly developed curves for zero-knowledge proofs. This EIP adds a precompile that allows whole classes of curves to be used. @@ -59,7 +59,7 @@ The total gas cost is `BASE_GAS` plus `ADD_GAS` for each `s_i` that is `1` and ` ### Encoding of points -Encode as `(x, y')` where `s` is the indicates the wheter `y` or `-y` is to be taken. It follows SEC 1 v 1.9 2.3.4, except uncompressed points (`y' = 0x04`) are not supported. +Encode as `(x, y')` where `s` indicates whether `y` or `-y` is to be taken. It follows SEC 1 v 1.9 2.3.4, except uncompressed points (`y' = 0x04`) are not supported. | `y'` | `(x, y)` | |--------|-----| @@ -110,14 +110,14 @@ TODO: The special cases for `α` and `β` might be worth implementing and offere **Compressed Coordinates.** Compressed coordinates allow contract to work with only `x` coordinates and sign bytes. It also prevents errors around points not being on-curve. Conversion to compressed coordinates is trivial. -**Linear Combination.** We could instead have a simple multiply `C = r ⋅ A`. In this case we would need a separate pre-compile for addition. In addtion, a linear combination allows for optimizations that like Shamir's trick that are not available in a single scalar multiplication. ECDSA requires `s₀ ⋅ A₀ + s₁ ⋅ A₁` and would benfit from this. +**Linear Combination.** We could instead have a simple multiply `C = r ⋅ A`. In this case we would need a separate pre-compile for addition. In addition, a linear combination allows for optimizations that like Shamir's trick that are not available in a single scalar multiplication. ECDSA requires `s₀ ⋅ A₀ + s₁ ⋅ A₁` and would benefit from this. -The BN254 (aka alt_bn8) multiplication operation introduced by the [EIP-196][eip196] precompile only handles a single scalar multiplication. The missed performance is such that for two or more points it is cheaper to use EVM, as pratically demonstrated by [Weierstrudel][ws]. +The BN254 (aka alt_bn8) multiplication operation introduced by the [EIP-196][eip196] precompile only handles a single scalar multiplication. The missed performance is such that for two or more points it is cheaper to use EVM, as practically demonstrated by [Weierstrudel][ws]. [eip196]: https://eips.ethereum.org/EIPS/eip-196 [ws]: https://medium.com/aztec-protocol/huffing-for-crypto-with-weierstrudel-9c9568c06901 -**Variable Time Math.** When called during a transaction, there is no assumption of privacy and no mittigations for side-channel attacks are necessary. +**Variable Time Math.** When called during a transaction, there is no assumption of privacy and no mitigations for side-channel attacks are necessary. **Prime Fields.** This EIP is for fields of large characteristic. It does not cover Binary fields and other fields of non-prime characteristic. From a808619d70ffb521dd39b9d6fd41a61bc393a85a Mon Sep 17 00:00:00 2001 From: Zachary James Williamson Date: Thu, 9 May 2019 10:41:55 +0100 Subject: [PATCH 195/431] Automatically merged updates to draft EIP(s) 1679 (#1988) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index dee8b794..44c53751 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -34,6 +34,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista [pending audit](https://medium.com/ethereum-cat-herders/progpow-audit-goals-expectations-75bb902a1f01), above and beyond standard security considerations, that should be evaluated prior to inclusion. +- [EIP-1108](https://eips.ethereum.org/EIPS/eip-1108): Reduce alt_bn128 precompile gas costs - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts - [EIP-1380](https://eips.ethereum.org/EIPS/eip-1380): Reduced gas cost for call to self From eca49ded75fa691ed8ceb47ba06b9f7466dbeabe Mon Sep 17 00:00:00 2001 From: Bryant Eisenbach Date: Thu, 9 May 2019 10:42:19 -0400 Subject: [PATCH 196/431] Automatically merged updates to draft EIP(s) 1344 (#2004) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1344.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1344.md b/EIPS/eip-1344.md index 1bea3780..29193030 100644 --- a/EIPS/eip-1344.md +++ b/EIPS/eip-1344.md @@ -5,6 +5,7 @@ author: Richard Meissner (@rmeissner), Bryant Eisenbach (@fubuloubu) discussions-to: https://ethereum-magicians.org/t/add-chain-id-opcode-for-replay-protection-when-handling-signed-messages-in-contracts/1131 category: Core type: Standards Track +requires: 155 status: Last Call created: 2018-08-22 review-period-end: 2019-04-30 From 5de9e0c367007706604856933500c37f2fa8dfa8 Mon Sep 17 00:00:00 2001 From: Antonio Salazar Cardozo Date: Thu, 9 May 2019 13:23:40 -0400 Subject: [PATCH 197/431] Automatically merged updates to draft EIP(s) 1108 (#2005) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1108.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1108.md b/EIPS/eip-1108.md index 94fcdf69..b77e50df 100644 --- a/EIPS/eip-1108.md +++ b/EIPS/eip-1108.md @@ -106,7 +106,7 @@ This EIP does not require Parity or Geth to deploy new cryptographic libraries, ## Test Cases -As no underlying algorithms are not being changed, there are no additional test cases to specify. +As no underlying algorithms are being changed, there are no additional test cases to specify. ## Implementation From 4b4a53382ff1c24439f700dd61bd55dca82e58f3 Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Thu, 9 May 2019 13:58:31 -0400 Subject: [PATCH 198/431] Automatically merged updates to draft EIP(s) 1155 (#2006) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 141 +++++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 60 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 6ceeeb4e..ca70cc43 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -43,20 +43,20 @@ pragma solidity ^0.5.8; */ interface ERC1155 /* is ERC165 */ { /** - @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning. - Operator MUST be msg.sender. - When minting/creating tokens, the `_from` field MUST be set to `0x0` - When burning/destroying tokens, the `_to` field MUST be set to `0x0` + @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). + `_operator` MUST be msg.sender. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address) + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address) The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value); /** - @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning. - Operator MUST be msg.sender. - When minting/creating tokens, the `_from` field MUST be set to `0x0` - When burning/destroying tokens, the `_to` field MUST be set to `0x0` + @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). + `_operator` MUST be msg.sender. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address) + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address) The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ @@ -70,7 +70,7 @@ interface ERC1155 /* is ERC165 */ { /** @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. - The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata JSON Schema". + The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". */ event URI(string _value, uint256 indexed _id); @@ -154,8 +154,7 @@ interface ERC1155TokenReceiver { @notice Handle the receipt of a single ERC1155 token type. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. - Return of any other value than the prescribed keccak256 generated values WILL result in the transaction being reverted. - Note: The contract address is always the message sender. + Return of any other value than the prescribed keccak256 generated values MUST result in the transaction being reverted. @param _operator The address which initiated the transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _id The id of the token being transferred @@ -169,8 +168,7 @@ interface ERC1155TokenReceiver { @notice Handle the receipt of multiple ERC1155 token types. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. - Return of any other value than the prescribed keccak256 generated values WILL result in the transaction being reverted. - Note: The contract address is always the message sender. + Return of any other value than the prescribed keccak256 generated values MUST result in the transaction being reverted. @param _operator The address which initiated the batch transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _ids An array containing ids of each token being transferred (order and length must match _values array) @@ -188,75 +186,98 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op #### Scenarios -**_Scenario:_** The recipient is not a contract. -* onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA account. +**_Scenario#1 :_** The recipient is not a contract. +* onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA (Externally Owned Account). -**_Scenario:_** The transaction is not a mint/transfer of a token. +**_Scenario#2 :_** The transaction is not a mint/transfer of a token. * onERC1155Received and onERC1155BatchReceived MUST NOT be called outside of a mint or transfer process. -**_Scenario:_** The receiver does not implement the necessary ERC1155TokenReceiver interface function(s). +**_Scenario#3 :_** The receiver does not implement the necessary ERC1155TokenReceiver interface function(s). * The transfer MUST be reverted with the one caveat below. - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. -**_Scenario:_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but returns an unknown value. +**_Scenario#4 :_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but returns an unknown value. * The transfer MUST be reverted. -**_Scenario:_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but throws an error. +**_Scenario#5 :_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but throws an error. * The transfer MUST be reverted. -**_Scenario:_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of one and only one balance change in the transaction (eg. safeTransferFrom called). -* All the balances in the transaction MUST have been updated to match the senders intent before any hook is called on a recipient. -* The appropriate choice of either onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. +**_Scenario#6 :_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of one and only one balance change (eg. safeTransferFrom called). +* All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. +* One of onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. * The onERC1155Received hook SHOULD be called on the recipient contract and its rules followed. - - If this hook is called it MUST NOT be called again on the recipient in this transaction. - - See "onERC1155Received common rules" for further rules that MUST be followed. -* The onERC1155BatchReceived hook MAY be called on the recipient contract and its rules followed - - See "onERC1155BatchReceived common rules" for further rules that MUST be followed. + - See "onERC1155Received rules" for further rules that MUST be followed. +* The onERC1155BatchReceived hook MAY be called on the recipient contract and its rules followed. + - See "onERC1155BatchReceived rules" for further rules that MUST be followed. -**_Scenario:_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of more than one balance change in the transaction (eg. safeBatchTransferFrom called). -* All the balances in the transaction MUST have been updated to match the senders intent before any hook is called on a recipient. -* The appropriate choice of either onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. -* The onERC1155BatchReceived hook SHOULD be called on the recipient contract and its rules followed. - - If called the arguments MUST contain/list information on every balance change for the recipient (and only the recipient) in this transaction. - - See "onERC1155BatchReceived common rules" for further rules that MUST be followed. -* The onERC1155Received hook MAY be called on the recipient contract and its rules followed. - - If called it MUST be repeatedly called until information has been passed and return value checked for every balance change for the recipient (and only the recipient) in this transaction. - - See "onERC1155Received common rules" for further rules that MUST be followed. +**_Scenario#7 :_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of more than one balance change (eg. safeBatchTransferFrom called). +* All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. +* onERC1155Received or onERC1155BatchReceived MUST be called on the recipient as many times as necessary such that every balance change for the recipient in the scenario is accounted for. + - The return magic value for every hook call MUST be checked and acted upon as per "onERC1155Received rules" and "onERC1155BatchReceived rules". +* The onERC1155BatchReceived hook SHOULD be called on the recipient contract and its rules followed. + - See "onERC1155BatchReceived rules" for further rules that MUST be followed. +* The onERC1155Received hook MAY be called on the recipient contract and its rules followed. + - See "onERC1155Received rules" for further rules that MUST be followed. #### Rules -**_onERC1155Received common rules:_** -* If this hook is called onERC1155BatchReceived MUST NOT also be called on the recipient in this transaction. -* The _operator argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). -* The _from argument MUST be the address of the holder whose balance is decreased. - - _from MUST be 0x0 for a mint. -* The _id argument MUST be the token type being transferred. -* The _value MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. -* The _data argument MUST contain the extra information provided by the sender (if any) for a transfer. -* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` +**_TransferSingle and TransferBatch event rules:_** +* TransferSingle SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. + - It MAY be emitted multiple times to indicate multiple balance changes in the transaction, but note that TransferBatch is designed for this to reduce gas consumption. + - The `_operator` argument MUST be msg.sender. + - The `_from` argument MUST be the address of the holder whose balance is decreased. + - The `_to` argument MUST be the address of the recipient whose balance is increased. + - The `_id` argument MUST be the token type being transferred. + - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). +* TransferBatch SHOULD be used to indicate multiple balance transfers have occurred between a `_from` and `_to` pair. + - It MAY be emitted with a single element in the list to indicate a singular balance change in the transaction, but note that TransferSingle is designed for this to reduce gas consumption. + - The `_operator` argument MUST be msg.sender. + - The `_from` argument MUST be the address of the holder whose balance is decreased. + - The `_to` argument MUST be the address of the recipient whose balance is increased. + - The `_ids` argument MUST be the list of tokens being transferred. + - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). +* The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. +* To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. + +**_onERC1155Received rules:_** +* The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +* The `_from` argument MUST be the address of the holder whose balance is decreased. + - `_from` MUST be 0x0 for a mint. +* The `_id` argument MUST be the token type being transferred. +* The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. +* The `_data` argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` - If the return value is `bytes4(keccak256("accept_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. -* The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. +* The recipient contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. * If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. +* onERC1155Received MAY be called multiple times in a single transaction and the following requirements must be met: + - All callbacks represent mutually exclusive balance changes. + - The set of all callbacks describes all balance changes that occurred during the transaction. -**_onERC1155BatchReceived common rules:_** -* If this hook is called onERC1155Received MUST NOT also be called on the recipient in this transaction. -* If this hook is called it MUST NOT be called again on the recipient in this transaction. -* The _operator argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). -* The _from argument MUST be the address of the holder whose balance is decreased. - - _from MUST be 0x0 for a mint. -* The _ids argument MUST be the list of tokens being transferred. -* The _values argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. -* The _data argument MUST contain the extra information provided by the sender (if any) for a transfer. -* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` +**_onERC1155BatchReceived rules:_** +* The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +* The `_from` argument MUST be the address of the holder whose balance is decreased. + - `_from` MUST be 0x0 for a mint. +* The `_ids` argument MUST be the list of tokens being transferred. +* The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. +* The `_data` argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` - If the return value is `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. -* The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. +* The recipient contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. * If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. +* onERC1155BatchReceived MAY be called multiple times in a single transaction and the following requirements must be met: + - All callbacks represent mutually exclusive balance changes. + - The set of all callbacks describes all balance changes that occurred during the transaction. **_Implementation specific transfer api rules:_** * If implementation specific api functions are used to transfer 1155 tokens to a contract the appropriate hook(s) MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. -* The appropriate events MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. +* The appropriate event(s) MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. ###### A solidity example of the keccak256 generated constants for the return magic is: - bytes4 constant public ERC1155_REJECTED = 0xafed434d; // keccak256("reject_erc1155_tokens()") @@ -265,8 +286,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op #### Compatibility with other standards -There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC721 at time of writing. -To cater for this there is some leeway with the rejection logic should a contract not implement the ERC1155TokenReceiver as per "Safe Transfer Rules" section above, specifically the scenario "The receiver does not implement the necessary ERC1155TokenReceiver interface function(s)". +There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC-721 at time of writing. +To cater for this there is some leeway with the rejection logic should a contract not implement the ERC1155TokenReceiver as per "Safe Transfer Rules" section above, specifically "Scenario#3 : The receiver does not implement the necessary ERC1155TokenReceiver interface function(s)". In that particular scenario if the 1155 implementation is also a hybrid implementation of another token standard, it MAY now follow the secondary standard's rules when transferring token(s) to a contract address. *__Note that a pure implementation of a single standard is recommended__* rather than a hybrid solution, but an example of a hybrid 1155+721 contract is linked in the references section under implementations. @@ -297,7 +318,7 @@ interface ERC1155Metadata_URI { /** @notice A distinct Uniform Resource Identifier (URI) for a given token. @dev URIs are defined in RFC 3986. - The URI may point to a JSON file that conforms to the "ERC-1155 Metadata JSON Schema". + The URI may point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". @return URI string */ function uri(uint256 _id) external view returns (string memory); From 98d3758f87f719458ce384a2713678c16f8344c6 Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Thu, 9 May 2019 14:21:35 -0400 Subject: [PATCH 199/431] Automatically merged updates to draft EIP(s) 1155 (#2007) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index ca70cc43..91d496c8 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -475,7 +475,7 @@ fr.json: ### Approval -The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface (DRAFT)](https://eips.ethereum.org/EIPS/eip-1761) is suggested. +The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver. To permit approval of a subset of token IDs, an interface such as [ERC-1761 Scoped Approval Interface](https://eips.ethereum.org/EIPS/eip-1761) is suggested. The counterpart `isAprrovedForAll` provides introspection into status set by `setApprovalForAll`. An owner SHOULD be assumed to always be able to operate on their own tokens regardless of approval status, so should SHOULD NOT have to call `setApprovalForAll` to approve themselves as an operator before they can operate on them. @@ -553,7 +553,7 @@ balanceOf(baseToken + index, msg.sender); // Get balance of the Non-Fungible tok **Standards** - [ERC-721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721) - [ERC-165 Standard Interface Detection](https://eips.ethereum.org/EIPS/eip-165) -- [ERC-1538 Transparent Contract Standard (DRAFT)](https://eips.ethereum.org/EIPS/eip-1538) +- [ERC-1538 Transparent Contract Standard](https://eips.ethereum.org/EIPS/eip-1538) - [JSON Schema](https://json-schema.org/) - [RFC 2119 Key words for use in RFCs to Indicate Requirement Levels](https://www.ietf.org/rfc/rfc2119.txt) From 8722db49cd8acefedc64374e6be139394d94b88c Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Thu, 9 May 2019 19:10:11 -0400 Subject: [PATCH 200/431] Automatically merged updates to draft EIP(s) 1155 (#2008) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 58 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 91d496c8..c4adf318 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -44,21 +44,25 @@ pragma solidity ^0.5.8; interface ERC1155 /* is ERC165 */ { /** @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). - `_operator` MUST be msg.sender. - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address) - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address) - The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. - To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. + The `_operator` argument MUST be msg.sender. + The `_from` argument MUST be the address of the holder whose balance is decreased. + The `_to` argument MUST be the address of the recipient whose balance is increased. + The `_id` argument MUST be the token type being transferred. + The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). */ event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value); /** @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). - `_operator` MUST be msg.sender. - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address) - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address) - The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. - To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. + The `_operator` argument MUST be msg.sender. + The `_from` argument MUST be the address of the holder whose balance is decreased. + The `_to` argument MUST be the address of the recipient whose balance is increased. + The `_ids` argument MUST be the list of tokens being transferred. + The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). */ event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values); @@ -76,10 +80,10 @@ interface ERC1155 /* is ERC165 */ { /** @notice Transfers value amount of an _id from the _from address to the _to address specified. - @dev MUST emit TransferSingle event on success. - Caller must be approved to manage the _from account's tokens (see "Approval" section of the standard). + @dev MUST emit one of TransferSingle or TransferBatch event on success (see "Safe Transfer Rules" section of the standard). + Caller must be approved to manage the `_from` account's tokens (see "Approval" section of the standard). MUST revert if `_to` is the zero address. - MUST revert if balance of sender for token `_id` is lower than the `_value` sent. + MUST revert if balance of holder for token `_id` is lower than the `_value` sent. MUST revert on any other error. After the transfer succeeds, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param _from Source address @@ -92,19 +96,19 @@ interface ERC1155 /* is ERC165 */ { /** @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call). - @dev MUST emit TransferBatch event on success. - Caller must be approved to manage the _from account's tokens (see "Approval" section of the standard). + @dev MUST emit one or more TransferSingle or TransferBatch event on success (see "Safe Transfer Rules" section of the standard). + Caller must be approved to manage the `_from` account's tokens (see "Approval" section of the standard). MUST revert if `_to` is the zero address. MUST revert if length of `_ids` is not the same as length of `_values`. - MUST revert if any of the balance of sender for token `_ids` is lower than the respective `_values` sent. + MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. MUST revert on any other error. Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc). - After all the transfer(s) in the batch succeed, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155BatchReceived` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + After all the transfer(s) in the batch succeed, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant ERC1155TokenReceiver hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param _from Source addresses @param _to Target addresses @param _ids IDs of each token type (order and length must match _values array) @param _values Transfer amounts per token type (order and length must match _ids array) - @param _data Additional data with no specified format, sent in call to `onERC1155BatchReceived` on `_to` + @param _data Additional data with no specified format, sent in call to the ERC1155TokenReceiver hook(s) on `_to` */ function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external; @@ -221,6 +225,24 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op #### Rules +**_safeTransferFrom rules:_** +* MUST emit one of TransferSingle or TransferBatch event on success (see "TransferSingle and TransferBatch event rules" section). +* Caller must be approved to manage the `_from` account's tokens (see "Approval" section). +* MUST revert if `_to` is the zero address. +* MUST revert if balance of holder for token `_id` is lower than the `_value` sent to the recipient. +* MUST revert on any other error. +* After the transfer succeeds, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "onERC1155Received rules" section). + +**_safeBatchTransferFrom rules:_** +* MUST emit one or more TransferSingle or TransferBatch event on success (see "TransferSingle and TransferBatch event rules" section). +* Caller must be approved to manage the `_from` account's tokens (see "Approval" section). +* MUST revert if `_to` is the zero address. +* MUST revert if length of `_ids` is not the same as length of `_values`. +* MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. +* MUST revert on any other error. +* Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc). +* After all the transfer(s) in the batch succeed, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant ERC1155TokenReceiver hook(s) on `_to` and act appropriately (see "onERC1155Received rules" and "onERC1155BatchReceived rules" sections). + **_TransferSingle and TransferBatch event rules:_** * TransferSingle SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. - It MAY be emitted multiple times to indicate multiple balance changes in the transaction, but note that TransferBatch is designed for this to reduce gas consumption. From ddc97b7a51f4f400f3d2afd0889455a20f84353e Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 9 May 2019 20:19:01 -0300 Subject: [PATCH 201/431] fix github pull request links (#2000) --- EIPS/eip-1820.md | 2 +- EIPS/eip-897.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1820.md b/EIPS/eip-1820.md index 055bae9c..c40a5d8a 100644 --- a/EIPS/eip-1820.md +++ b/EIPS/eip-1820.md @@ -2,7 +2,7 @@ eip: 1820 title: Pseudo-introspection Registry Contract author: Jordi Baylina , Jacques Dafflon -discussions-to: https://github.com/ethereum/EIPs/pulls/1820 +discussions-to: https://github.com/ethereum/EIPs/pull/1820 status: Final type: Standards Track category: ERC diff --git a/EIPS/eip-897.md b/EIPS/eip-897.md index 16373270..d0fdb2aa 100644 --- a/EIPS/eip-897.md +++ b/EIPS/eip-897.md @@ -6,7 +6,7 @@ type: Standards Track category: ERC status: Draft created: 2018-02-21 -discussions-to: https://github.com/ethereum/EIPs/pulls/897 +discussions-to: https://github.com/ethereum/EIPs/pull/897 --- ## Simple Summary From 508aba666bbac29509cff7406f779db049856076 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 10 May 2019 07:51:30 -0700 Subject: [PATCH 202/431] Automatically merged updates to draft EIP(s) 1679 (#1830) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 44c53751..acf51ea0 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -40,6 +40,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1380](https://eips.ethereum.org/EIPS/eip-1380): Reduced gas cost for call to self - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme - [EIP-1803](https://eips.ethereum.org/EIPS/eip-1803): Rename opcodes for clarity +- [EIP-1829](https://eips.ethereum.org/EIPS/eip-1829): Precompile for Elliptic Curve Linear Combinations - [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes ## Timeline From 774e384691ea305424fa14a5277152d1b3520d73 Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Fri, 10 May 2019 20:03:02 -0400 Subject: [PATCH 203/431] Automatically merged updates to draft EIP(s) 1155 (#2011) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 188 ++++++++++++++++++++++++++--------------------- 1 file changed, 105 insertions(+), 83 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index c4adf318..aa0e2079 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -1,7 +1,7 @@ --- eip: 1155 title: ERC-1155 Multi Token Standard -author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet +author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet type: Standards Track category: ERC status: Draft @@ -19,7 +19,7 @@ A standard interface for contracts that manage multiple token types. A single de This standard outlines a smart contract interface that can represent any number of Fungible and Non-Fungible token types. Existing standards such as ERC-20 require deployment of separate contracts per token type. The ERC-721 standard's Token ID is a single non-fungible index and the group of these non-fungibles is deployed as a single contract with settings for the entire collection. In contrast, the ERC-1155 Multi Token Standard allows for each Token ID to represent a new configurable token type, which may have its own metadata, supply and other attributes. -The `_id` parameter is contained in each function's parameters and indicates a specific token or token type in a transaction. +The `_id` argument contained in each function's argument set indicates a specific token or token type in a transaction. ## Motivation @@ -43,19 +43,19 @@ pragma solidity ^0.5.8; */ interface ERC1155 /* is ERC165 */ { /** - @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). + @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). The `_operator` argument MUST be msg.sender. The `_from` argument MUST be the address of the holder whose balance is decreased. The `_to` argument MUST be the address of the recipient whose balance is increased. The `_id` argument MUST be the token type being transferred. The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). */ event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value); - + /** - @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). + @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). The `_operator` argument MUST be msg.sender. The `_from` argument MUST be the address of the holder whose balance is decreased. The `_to` argument MUST be the address of the recipient whose balance is increased. @@ -79,36 +79,36 @@ interface ERC1155 /* is ERC165 */ { event URI(string _value, uint256 indexed _id); /** - @notice Transfers value amount of an _id from the _from address to the _to address specified. - @dev MUST emit one of TransferSingle or TransferBatch event on success (see "Safe Transfer Rules" section of the standard). - Caller must be approved to manage the `_from` account's tokens (see "Approval" section of the standard). + @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). MUST revert if `_to` is the zero address. MUST revert if balance of holder for token `_id` is lower than the `_value` sent. MUST revert on any other error. - After the transfer succeeds, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + MUST emit `TransferSingle` event on transfer success (see "Safe Transfer Rules" section of the standard). @param _from Source address @param _to Target address @param _id ID of the token type @param _value Transfer amount - @param _data Additional data with no specified format, sent in call to `onERC1155Received` on `_to` + @param _data Additional data with no specified format, MUST be sent in call to `onERC1155Received` on `_to` */ function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; /** - @notice Send multiple types of Tokens from a 3rd party in one transfer (with safety call). - @dev MUST emit one or more TransferSingle or TransferBatch event on success (see "Safe Transfer Rules" section of the standard). - Caller must be approved to manage the `_from` account's tokens (see "Approval" section of the standard). + @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). MUST revert if `_to` is the zero address. MUST revert if length of `_ids` is not the same as length of `_values`. MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. MUST revert on any other error. - Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc). - After all the transfer(s) in the batch succeed, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant ERC1155TokenReceiver hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + Transfers and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + MUST emit `TransferSingle` or `TransferBatch` event(s) on transfer success (see "Safe Transfer Rules" section of the standard). @param _from Source addresses @param _to Target addresses @param _ids IDs of each token type (order and length must match _values array) @param _values Transfer amounts per token type (order and length must match _ids array) - @param _data Additional data with no specified format, sent in call to the ERC1155TokenReceiver hook(s) on `_to` + @param _data Additional data with no specified format, MUST be sent in call to the `ERC1155TokenReceiver` hook(s) on `_to` */ function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external; @@ -119,7 +119,7 @@ interface ERC1155 /* is ERC165 */ { @return The _owner's balance of the Token type requested */ function balanceOf(address _owner, uint256 _id) external view returns (uint256); - + /** @notice Get the balance of multiple account/token pairs @param _owners The addresses of the token holders @@ -136,7 +136,7 @@ interface ERC1155 /* is ERC165 */ { */ function setApprovalForAll(address _operator, bool _approved) external; - /** + /** @notice Queries the approval status of an operator for a given owner. @param _owner The owner of the Tokens @param _operator Address of authorized operator @@ -157,113 +157,123 @@ interface ERC1155TokenReceiver { /** @notice Handle the receipt of a single ERC1155 token type. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. - This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. - Return of any other value than the prescribed keccak256 generated values MUST result in the transaction being reverted. + This function MUST return `bytes4(keccak256("accept_erc1155_tokens()"))` if it accepts the transfer. + This function MUST revert if it rejects the transfer. + Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. @param _operator The address which initiated the transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _id The id of the token being transferred @param _value The amount of tokens being transferred @param _data Additional data with no specified format - @return `bytes4(keccak256("accept_erc1155_tokens()"))`==0x4dc21a2f or `bytes4(keccak256("reject_erc1155_tokens()"))`==0xafed434d + @return `bytes4(keccak256("accept_erc1155_tokens()"))`==0x4dc21a2f */ function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4); - + /** @notice Handle the receipt of multiple ERC1155 token types. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. - This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. - Return of any other value than the prescribed keccak256 generated values MUST result in the transaction being reverted. + This function MUST return `bytes4(keccak256("accept_batch_erc1155_tokens()"))` if it accepts the transfer(s). + This function MUST revert if it rejects the transfer(s). + Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. @param _operator The address which initiated the batch transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _ids An array containing ids of each token being transferred (order and length must match _values array) @param _values An array containing amounts of each token being transferred (order and length must match _ids array) @param _data Additional data with no specified format - @return `bytes4(keccak256("accept_batch_erc1155_tokens()"))`==0xac007889 or `bytes4(keccak256("reject_erc1155_tokens()"))`==0xafed434d + @return `bytes4(keccak256("accept_batch_erc1155_tokens()"))`==0xac007889 */ function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4); + + /** + @notice Indicates whether a contract implements the `ERC1155TokenReceiver` functions and so can accept ERC1155 token types. + @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))`. + @return `bytes4(keccak256("isERC1155TokenReceiver()"))`==0x0d912442 + */ + function isERC1155TokenReceiver() external pure returns (bytes4); } ``` ### Safe Transfer Rules -To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate with respect to the ERC1155TokenReceiver, a list of scenarios and rules follows. +To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate with respect to the `ERC1155TokenReceiver`, a list of scenarios and rules follows. #### Scenarios **_Scenario#1 :_** The recipient is not a contract. -* onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA (Externally Owned Account). +* `onERC1155Received` and `onERC1155BatchReceived` MUST NOT be called on an EOA (Externally Owned Account). **_Scenario#2 :_** The transaction is not a mint/transfer of a token. -* onERC1155Received and onERC1155BatchReceived MUST NOT be called outside of a mint or transfer process. +* `onERC1155Received` and `onERC1155BatchReceived` MUST NOT be called outside of a mint or transfer process. -**_Scenario#3 :_** The receiver does not implement the necessary ERC1155TokenReceiver interface function(s). +**_Scenario#3 :_** The receiver does not implement the necessary `ERC1155TokenReceiver` interface function(s). * The transfer MUST be reverted with the one caveat below. - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. -**_Scenario#4 :_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but returns an unknown value. +**_Scenario#4 :_** The receiver implements the necessary `ERC1155TokenReceiver` interface function(s) but returns an unknown value. * The transfer MUST be reverted. -**_Scenario#5 :_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but throws an error. +**_Scenario#5 :_** The receiver implements the necessary `ERC1155TokenReceiver` interface function(s) but throws an error. * The transfer MUST be reverted. -**_Scenario#6 :_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of one and only one balance change (eg. safeTransferFrom called). +**_Scenario#6 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of one and only one balance change (eg. safeTransferFrom called). * All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. -* One of onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. -* The onERC1155Received hook SHOULD be called on the recipient contract and its rules followed. +* One of `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient. +* The `onERC1155Received` hook SHOULD be called on the recipient contract and its rules followed. - See "onERC1155Received rules" for further rules that MUST be followed. -* The onERC1155BatchReceived hook MAY be called on the recipient contract and its rules followed. +* The `onERC1155BatchReceived` hook MAY be called on the recipient contract and its rules followed. - See "onERC1155BatchReceived rules" for further rules that MUST be followed. -**_Scenario#7 :_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of more than one balance change (eg. safeBatchTransferFrom called). +**_Scenario#7 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of more than one balance change (eg. safeBatchTransferFrom called). * All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. -* onERC1155Received or onERC1155BatchReceived MUST be called on the recipient as many times as necessary such that every balance change for the recipient in the scenario is accounted for. +* `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient as many times as necessary such that every balance change for the recipient in the scenario is accounted for. - The return magic value for every hook call MUST be checked and acted upon as per "onERC1155Received rules" and "onERC1155BatchReceived rules". -* The onERC1155BatchReceived hook SHOULD be called on the recipient contract and its rules followed. +* The `onERC1155BatchReceived` hook SHOULD be called on the recipient contract and its rules followed. - See "onERC1155BatchReceived rules" for further rules that MUST be followed. -* The onERC1155Received hook MAY be called on the recipient contract and its rules followed. +* The `onERC1155Received` hook MAY be called on the recipient contract and its rules followed. - See "onERC1155Received rules" for further rules that MUST be followed. - + #### Rules **_safeTransferFrom rules:_** -* MUST emit one of TransferSingle or TransferBatch event on success (see "TransferSingle and TransferBatch event rules" section). -* Caller must be approved to manage the `_from` account's tokens (see "Approval" section). +* Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section). * MUST revert if `_to` is the zero address. * MUST revert if balance of holder for token `_id` is lower than the `_value` sent to the recipient. * MUST revert on any other error. -* After the transfer succeeds, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "onERC1155Received rules" section). +* After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "onERC1155Received rules" section). +* MUST emit `TransferSingle` event on transfer success (see "TransferSingle and TransferBatch event rules" section). **_safeBatchTransferFrom rules:_** -* MUST emit one or more TransferSingle or TransferBatch event on success (see "TransferSingle and TransferBatch event rules" section). -* Caller must be approved to manage the `_from` account's tokens (see "Approval" section). +* Caller must be approved to manage all the tokens being transferred out of the `_from` account (see "Approval" section). * MUST revert if `_to` is the zero address. * MUST revert if length of `_ids` is not the same as length of `_values`. * MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. * MUST revert on any other error. -* Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc). -* After all the transfer(s) in the batch succeed, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant ERC1155TokenReceiver hook(s) on `_to` and act appropriately (see "onERC1155Received rules" and "onERC1155BatchReceived rules" sections). +* After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` or `onERC1155BatchReceived` as on `_to` and act appropriately (see "`onERC1155Received` and onERC1155BatchReceived rules" section). +* MUST emit `TransferSingle` or `TransferBatch` event(s) on transfer success (see "TransferSingle and TransferBatch event rules" section). +* Transfers and events MUST occur in the array order they were submitted (_ids[0]/_values[0] before _ids[1]/_values[1], etc). **_TransferSingle and TransferBatch event rules:_** -* TransferSingle SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. - - It MAY be emitted multiple times to indicate multiple balance changes in the transaction, but note that TransferBatch is designed for this to reduce gas consumption. +* `TransferSingle` SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. + - It MAY be emitted multiple times to indicate multiple balance changes in the transaction, but note that `TransferBatch` is designed for this to reduce gas consumption. - The `_operator` argument MUST be msg.sender. - The `_from` argument MUST be the address of the holder whose balance is decreased. - The `_to` argument MUST be the address of the recipient whose balance is increased. - The `_id` argument MUST be the token type being transferred. - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. - - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). -* TransferBatch SHOULD be used to indicate multiple balance transfers have occurred between a `_from` and `_to` pair. - - It MAY be emitted with a single element in the list to indicate a singular balance change in the transaction, but note that TransferSingle is designed for this to reduce gas consumption. +* `TransferBatch` SHOULD be used to indicate multiple balance transfers have occurred between a `_from` and `_to` pair. + - It MAY be emitted with a single element in the list to indicate a singular balance change in the transaction, but note that `TransferSingle` is designed for this to reduce gas consumption. - The `_operator` argument MUST be msg.sender. - - The `_from` argument MUST be the address of the holder whose balance is decreased. - - The `_to` argument MUST be the address of the recipient whose balance is increased. - - The `_ids` argument MUST be the list of tokens being transferred. - - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + - The `_from` argument MUST be the address of the holder whose balance is decreased for each entry pair in `_ids` and `_values`. + - The `_to` argument MUST be the address of the recipient whose balance is increased for each entry pair in `_ids` and `_values`. + - The `_ids` array argument MUST contain the ids of the tokens being transferred. + - The `_values` array argument MUST contain the number of token to be transferred for each corresponding entry in `_ids`. + - `_ids` and `_values` MUST have the same length. - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). * The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. -* To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. +* To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the `TransferSingle` event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. **_onERC1155Received rules:_** * The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). @@ -271,47 +281,59 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - `_from` MUST be 0x0 for a mint. * The `_id` argument MUST be the token type being transferred. * The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. -* The `_data` argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The `_data` argument MUST contain the extra information provided by the sender for the transfer. * The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` - - If the return value is `bytes4(keccak256("accept_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. -* The recipient contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. -* If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. -* onERC1155Received MAY be called multiple times in a single transaction and the following requirements must be met: + - If the return value is `bytes4(keccak256("accept_erc1155_tokens()"))` the transfer MUST be completed or MUST revert if any other conditions are not met for success. +* The recipient contract MAY reject an increase of its balance by calling revert. + - If recipient contract throws/reverts the transaction MUST be reverted. +* If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` the transaction MUST be reverted. +* `onERC1155Received` (and/or `onERC1155BatchReceived`) MAY be called multiple times in a single transaction and the following requirements must be met: - All callbacks represent mutually exclusive balance changes. - - The set of all callbacks describes all balance changes that occurred during the transaction. + - The set of all calls to `onERC1155Received` and `onERC1155BatchReceived` describes all balance changes that occurred during the transaction in the order submitted. **_onERC1155BatchReceived rules:_** * The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). * The `_from` argument MUST be the address of the holder whose balance is decreased. - `_from` MUST be 0x0 for a mint. * The `_ids` argument MUST be the list of tokens being transferred. -* The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. -* The `_data` argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in `_ids`) the holder balance is decreased by and match what the recipient balance is increased by. +* The `_data` argument MUST contain the information provided by the sender for a transfer. * The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` - - If the return value is `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. -* The recipient contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. -* If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. -* onERC1155BatchReceived MAY be called multiple times in a single transaction and the following requirements must be met: + - If the return value is `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transfer MUST be completed or MUST revert if any other conditions are not met for success. +* The recipient contract MAY reject an increase of its balance by calling revert. + - If recipient contract throws/reverts the transaction MUST be reverted. +* If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transaction MUST be reverted. +* `onERC1155BatchReceived` (and/or `onERC1155Received`) MAY be called multiple times in a single transaction and the following requirements must be met: - All callbacks represent mutually exclusive balance changes. - - The set of all callbacks describes all balance changes that occurred during the transaction. + - The set of all calls to `onERC1155Received` and `onERC1155BatchReceived` describes all balance changes that occurred during the transaction in the order submitted. + +**_isERC1155TokenReceiver rules:_** +* The implementation of `isERC1155TokenReceiver` function SHOULD be as follows: + ``` + function isERC1155TokenReceiver() external pure returns (bytes4) { + return 0x0d912442; // bytes4(keccak256("isERC1155TokenReceiver()")) + } + ``` +* The implementation MAY differ from the above but it MUST return the same value. **_Implementation specific transfer api rules:_** -* If implementation specific api functions are used to transfer 1155 tokens to a contract the appropriate hook(s) MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. -* The appropriate event(s) MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. - +* If implementation specific api functions are used to transfer 1155 tokens to a contract, the safeTransferFrom, or safeBatchTransferFrom (as appropriate) rules MUST be followed. + ###### A solidity example of the keccak256 generated constants for the return magic is: - - bytes4 constant public ERC1155_REJECTED = 0xafed434d; // keccak256("reject_erc1155_tokens()") - - bytes4 constant public ERC1155_ACCEPTED = 0x4dc21a2f; // keccak256("accept_erc1155_tokens()") - - bytes4 constant public ERC1155_BATCH_ACCEPTED = 0xac007889; // keccak256("accept_batch_erc1155_tokens()") + - bytes4 constant public ERC1155_ACCEPTED = 0x4dc21a2f; // bytes4(keccak256("accept_erc1155_tokens()")) + - bytes4 constant public ERC1155_BATCH_ACCEPTED = 0xac007889; // bytes4(keccak256("accept_batch_erc1155_tokens()")) #### Compatibility with other standards -There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC-721 at time of writing. -To cater for this there is some leeway with the rejection logic should a contract not implement the ERC1155TokenReceiver as per "Safe Transfer Rules" section above, specifically "Scenario#3 : The receiver does not implement the necessary ERC1155TokenReceiver interface function(s)". -In that particular scenario if the 1155 implementation is also a hybrid implementation of another token standard, it MAY now follow the secondary standard's rules when transferring token(s) to a contract address. +There have been requirements during the design discussions to have this standard be compatible with existing standards when sending to contract addresses, specifically ERC-721 at time of writing. +To cater for this scenario, there is some leeway with the rejection logic should a contract not implement the `ERC1155TokenReceiver` as per "Safe Transfer Rules" section above, specifically "Scenario#3 : The receiver does not implement the necessary `ERC1155TokenReceiver` interface function(s)". +Hence in a hybrid 1155 contract implementation an extra call MUST be made on the recipient contract and checked before any hook calls to `onERC1155Received` or `onERC1155BatchReceived` are made. +Order of operation MUST therefore be: +1. The implementation MUST call the function `isERC1155TokenReceiver` on the recipient. +2. If the function call succeeds and the return value is `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation proceeds as a regular 1155 implementation, with the call(s) to the `onERC1155Received` or `onERC1155BatchReceived` hooks and rules associated. +3. If the function call fails or the return value is NOT `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation can assume the contract recipient is not an `ERC1155TokenReceiver` and follow its other standard's rules for transfers. + *__Note that a pure implementation of a single standard is recommended__* rather than a hybrid solution, but an example of a hybrid 1155+721 contract is linked in the references section under implementations. An important consideration is that even if the tokens are sent with another standard's rules the *__1155 transfer events MUST still be emitted.__* This is so the balances can still be determined via events alone as per 1155 standard rules. @@ -550,7 +572,7 @@ The `balanceOfBatch` function allows clients to retrieve balances of multiple ow In order to keep storage requirements light for contracts implementing ERC-1155, enumeration (discovering the IDs and values of tokens) must be done using event logs. It is RECOMMENDED that clients such as exchanges and blockchain explorers maintain a local database containing the Token ID, Supply, and URI at the minimum. This can be built from each TransferSingle, TransferBatch, and URI event, starting from the block the smart contract was deployed until the latest block. -ERC-1155 contracts must therefore carefully emit TransferSingle or TransferBatch events in any instance where tokens are created, minted, or destroyed. +ERC-1155 contracts must therefore carefully emit `TransferSingle` or `TransferBatch` events in any instance where tokens are created, minted, or destroyed. ### Non-Fungible Tokens From 75c9279e22ee77e089f2297a8c85e8567527757a Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Fri, 10 May 2019 23:38:05 -0400 Subject: [PATCH 204/431] Automatically merged updates to draft EIP(s) 1155 (#2012) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index aa0e2079..ecf6b14f 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -104,8 +104,8 @@ interface ERC1155 /* is ERC165 */ { Transfers and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). MUST emit `TransferSingle` or `TransferBatch` event(s) on transfer success (see "Safe Transfer Rules" section of the standard). - @param _from Source addresses - @param _to Target addresses + @param _from Source address + @param _to Target address @param _ids IDs of each token type (order and length must match _values array) @param _values Transfer amounts per token type (order and length must match _ids array) @param _data Additional data with no specified format, MUST be sent in call to the `ERC1155TokenReceiver` hook(s) on `_to` @@ -157,7 +157,7 @@ interface ERC1155TokenReceiver { /** @notice Handle the receipt of a single ERC1155 token type. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. - This function MUST return `bytes4(keccak256("accept_erc1155_tokens()"))` if it accepts the transfer. + This function MUST return `bytes4(keccak256("accept_erc1155_tokens()"))` (i.e. 0x4dc21a2f) if it accepts the transfer. This function MUST revert if it rejects the transfer. Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. @param _operator The address which initiated the transfer (i.e. msg.sender) @@ -165,14 +165,14 @@ interface ERC1155TokenReceiver { @param _id The id of the token being transferred @param _value The amount of tokens being transferred @param _data Additional data with no specified format - @return `bytes4(keccak256("accept_erc1155_tokens()"))`==0x4dc21a2f + @return `bytes4(keccak256("accept_erc1155_tokens()"))` */ function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4); /** @notice Handle the receipt of multiple ERC1155 token types. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. - This function MUST return `bytes4(keccak256("accept_batch_erc1155_tokens()"))` if it accepts the transfer(s). + This function MUST return `bytes4(keccak256("accept_batch_erc1155_tokens()"))` (i.e. 0xac007889) if it accepts the transfer(s). This function MUST revert if it rejects the transfer(s). Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. @param _operator The address which initiated the batch transfer (i.e. msg.sender) @@ -180,14 +180,14 @@ interface ERC1155TokenReceiver { @param _ids An array containing ids of each token being transferred (order and length must match _values array) @param _values An array containing amounts of each token being transferred (order and length must match _ids array) @param _data Additional data with no specified format - @return `bytes4(keccak256("accept_batch_erc1155_tokens()"))`==0xac007889 + @return `bytes4(keccak256("accept_batch_erc1155_tokens()"))` */ function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4); /** @notice Indicates whether a contract implements the `ERC1155TokenReceiver` functions and so can accept ERC1155 token types. - @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))`. - @return `bytes4(keccak256("isERC1155TokenReceiver()"))`==0x0d912442 + @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))` (i.e. 0x0d912442). + @return `bytes4(keccak256("isERC1155TokenReceiver()"))` */ function isERC1155TokenReceiver() external pure returns (bytes4); } From 59160e4ec42fbe0d9eb17efa3120224d70ef092f Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Sat, 11 May 2019 00:09:24 -0400 Subject: [PATCH 205/431] Automatically merged updates to draft EIP(s) 1155 (#2013) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index ecf6b14f..6e93a48d 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -153,6 +153,9 @@ Smart contracts **MUST** implement this interface to accept transfers. See "Safe ```solidity pragma solidity ^0.5.8; +/** + Note: The ERC-165 identifier for this interface is 0x43b236a2. +*/ interface ERC1155TokenReceiver { /** @notice Handle the receipt of a single ERC1155 token type. From 0911b551220748580019d7d1d629a39af2420e62 Mon Sep 17 00:00:00 2001 From: Tim Beiko Date: Sat, 11 May 2019 02:24:38 -0400 Subject: [PATCH 206/431] Re-order EIP categories (#1989) --- EIPS/eip-1.md | 2 +- _config.yml | 2 +- eip-X.md | 2 +- index.html | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 0cdc16e7..6596e699 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -28,8 +28,8 @@ There are three types of EIP: - **Networking** - includes improvements around [devp2p] ([EIP8]) and [Light Ethereum Subprotocol], as well as proposed improvements to network protocol specifications of [whisper] and [swarm]. - **Interface** - includes improvements around client [API/RPC] specifications and standards, and also certain language-level standards like method names ([EIP6]) and [contract ABIs]. The label “interface” aligns with the [interfaces repo] and discussion should primarily occur in that repository before an EIP is submitted to the EIPs repository. - **ERC** - application-level standards and conventions, including contract standards such as token standards ([ERC20]), name registries ([ERC26], [ERC137]), URI schemes ([ERC67]), library/package formats ([EIP82]), and wallet formats ([EIP75], [EIP85]). -- An **Informational EIP** describes an Ethereum design issue, or provides general guidelines or information to the Ethereum community, but does not propose a new feature. Informational EIPs do not necessarily represent Ethereum community consensus or a recommendation, so users and implementers are free to ignore Informational EIPs or follow their advice. - A **Meta EIP** describes a process surrounding Ethereum or proposes a change to (or an event in) a process. Process EIPs are like Standards Track EIPs but apply to areas other than the Ethereum protocol itself. They may propose an implementation, but not to Ethereum's codebase; they often require community consensus; unlike Informational EIPs, 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 Ethereum development. Any meta-EIP is also considered a Process EIP. +- An **Informational EIP** describes an Ethereum design issue, or provides general guidelines or information to the Ethereum community, but does not propose a new feature. Informational EIPs do not necessarily represent Ethereum community consensus or a recommendation, so users and implementers are free to ignore Informational EIPs or follow their advice. It is highly recommended that a single EIP contain a single key proposal or new idea. The more focused the EIP, the more successful it tends to be. A change to one client doesn't require an EIP; a change that affects multiple clients, or defines a standard for multiple apps to use, does. diff --git a/_config.yml b/_config.yml index d6c9410d..b0fbe061 100644 --- a/_config.yml +++ b/_config.yml @@ -27,8 +27,8 @@ header_pages: - networking.html - interface.html - erc.html - - informational.html - meta.html + - informational.html twitter: card: summary username: ethereum diff --git a/eip-X.md b/eip-X.md index e1c1c80b..66dd31b6 100644 --- a/eip-X.md +++ b/eip-X.md @@ -4,7 +4,7 @@ title: author: , FirstName (@GitHubUsername) and GitHubUsername (@GitHubUsername)> discussions-to: status: Draft -type: +type: category (*only required for Standard Track): created: requires (*optional): diff --git a/index.html b/index.html index 079dd092..c79bd888 100644 --- a/index.html +++ b/index.html @@ -41,8 +41,8 @@ title: Home

    ERC ({{site.pages|where:"type","Standards Track"|where:"category","ERC"|size}})

    Application-level standards and conventions, including contract standards such as token standards (ERC20), name registries (ERC137), URI schemes (ERC681), library/package formats (EIP190), and wallet formats (EIP85).

    -

    Informational ({{site.pages|where:"type","Informational"|size}})

    -

    Describes a Ethereum design issue, or provides general guidelines or information to the Ethereum community, but does not propose a new feature. Informational EIPs do not necessarily represent Ethereum community consensus or a recommendation, so users and implementers are free to ignore Informational EIPs or follow their advice.

    -

    Meta ({{site.pages|where:"type","Meta"|size}})

    Describes a process surrounding Ethereum or proposes a change to (or an event in) a process. Process EIPs are like Standards Track EIPs but apply to areas other than the Ethereum protocol itself. They may propose an implementation, but not to Ethereum's codebase; they often require community consensus; unlike Informational EIPs, 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 Ethereum development. Any meta-EIP is also considered a Process EIP.

    + +

    Informational ({{site.pages|where:"type","Informational"|size}})

    +

    Describes a Ethereum design issue, or provides general guidelines or information to the Ethereum community, but does not propose a new feature. Informational EIPs do not necessarily represent Ethereum community consensus or a recommendation, so users and implementers are free to ignore Informational EIPs or follow their advice.

    From 6b301b54ae2d79fdae02501efd39b3e95e75f2ce Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 13 May 2019 10:16:17 +0200 Subject: [PATCH 207/431] Automatically merged updates to draft EIP(s) 1679 (#2016) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index acf51ea0..374cf6ed 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -35,10 +35,12 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista above and beyond standard security considerations, that should be evaluated prior to inclusion. - [EIP-1108](https://eips.ethereum.org/EIPS/eip-1108): Reduce alt_bn128 precompile gas costs +- [EIP-1283](https://eips.ethereum.org/EIPS/eip-1283): Net gas metering for SSTORE without dirty maps - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts - [EIP-1380](https://eips.ethereum.org/EIPS/eip-1380): Reduced gas cost for call to self - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme +- [EIP-1706](https://eips.ethereum.org/EIPS/eip-1706): Disable SSTORE with gasleft lower than call stipend - [EIP-1803](https://eips.ethereum.org/EIPS/eip-1803): Rename opcodes for clarity - [EIP-1829](https://eips.ethereum.org/EIPS/eip-1829): Precompile for Elliptic Curve Linear Combinations - [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes From da4c47ef2e9dc9fe4c2c20629ee8d20ae98730ea Mon Sep 17 00:00:00 2001 From: Ronan Sandford Date: Mon, 13 May 2019 20:51:21 +0100 Subject: [PATCH 208/431] Automatically merged updates to draft EIP(s) 1155 (#2017) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 6e93a48d..0894c4eb 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -189,7 +189,7 @@ interface ERC1155TokenReceiver { /** @notice Indicates whether a contract implements the `ERC1155TokenReceiver` functions and so can accept ERC1155 token types. - @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))` (i.e. 0x0d912442). + @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))` (i.e. 0x0d912442). and MUST not consume more than 5,000 gas. @return `bytes4(keccak256("isERC1155TokenReceiver()"))` */ function isERC1155TokenReceiver() external pure returns (bytes4); @@ -317,7 +317,9 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op return 0x0d912442; // bytes4(keccak256("isERC1155TokenReceiver()")) } ``` -* The implementation MAY differ from the above but it MUST return the same value. +* The implementation MAY differ from the above but : + - it MUST return the same value. + - it MUST not spend more than 5,000 gas **_Implementation specific transfer api rules:_** * If implementation specific api functions are used to transfer 1155 tokens to a contract, the safeTransferFrom, or safeBatchTransferFrom (as appropriate) rules MUST be followed. @@ -333,7 +335,7 @@ To cater for this scenario, there is some leeway with the rejection logic should Hence in a hybrid 1155 contract implementation an extra call MUST be made on the recipient contract and checked before any hook calls to `onERC1155Received` or `onERC1155BatchReceived` are made. Order of operation MUST therefore be: -1. The implementation MUST call the function `isERC1155TokenReceiver` on the recipient. +1. The implementation MUST call the function `isERC1155TokenReceiver` on the recipient, providing at least 5,000 gas. 2. If the function call succeeds and the return value is `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation proceeds as a regular 1155 implementation, with the call(s) to the `onERC1155Received` or `onERC1155BatchReceived` hooks and rules associated. 3. If the function call fails or the return value is NOT `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation can assume the contract recipient is not an `ERC1155TokenReceiver` and follow its other standard's rules for transfers. From 0f469acef3719807a6855f24a91f134a1162640e Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Mon, 13 May 2019 16:05:42 -0400 Subject: [PATCH 209/431] Automatically merged updates to draft EIP(s) 1155 (#2023) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 0894c4eb..322738e3 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -189,7 +189,8 @@ interface ERC1155TokenReceiver { /** @notice Indicates whether a contract implements the `ERC1155TokenReceiver` functions and so can accept ERC1155 token types. - @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))` (i.e. 0x0d912442). and MUST not consume more than 5,000 gas. + @dev This function MUST return `bytes4(keccak256("isERC1155TokenReceiver()"))` (i.e. 0x0d912442). + This function MUST NOT consume more than 5,000 gas. @return `bytes4(keccak256("isERC1155TokenReceiver()"))` */ function isERC1155TokenReceiver() external pure returns (bytes4); @@ -251,7 +252,7 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op * MUST revert if length of `_ids` is not the same as length of `_values`. * MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. * MUST revert on any other error. -* After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` or `onERC1155BatchReceived` as on `_to` and act appropriately (see "`onERC1155Received` and onERC1155BatchReceived rules" section). +* After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` or `onERC1155BatchReceived` on `_to` and act appropriately (see "`onERC1155Received` and onERC1155BatchReceived rules" section). * MUST emit `TransferSingle` or `TransferBatch` event(s) on transfer success (see "TransferSingle and TransferBatch event rules" section). * Transfers and events MUST occur in the array order they were submitted (_ids[0]/_values[0] before _ids[1]/_values[1], etc). @@ -317,9 +318,9 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op return 0x0d912442; // bytes4(keccak256("isERC1155TokenReceiver()")) } ``` -* The implementation MAY differ from the above but : - - it MUST return the same value. - - it MUST not spend more than 5,000 gas +* The implementation MAY differ from the above but: + - It MUST return the same value. + - It MUST NOT consume more than 5,000 gas. **_Implementation specific transfer api rules:_** * If implementation specific api functions are used to transfer 1155 tokens to a contract, the safeTransferFrom, or safeBatchTransferFrom (as appropriate) rules MUST be followed. From 72657123e8b59b8bab769ea450fa81434e71bce1 Mon Sep 17 00:00:00 2001 From: Ronan Sandford Date: Mon, 13 May 2019 21:17:53 +0100 Subject: [PATCH 210/431] Call strict gas (#1950) * CALL with strict gas * fix date * 1930 * update with explicit code change * add link to discussion * update * fix link --- EIPS/eip-1930.md | 120 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 EIPS/eip-1930.md diff --git a/EIPS/eip-1930.md b/EIPS/eip-1930.md new file mode 100644 index 00000000..7452c7ff --- /dev/null +++ b/EIPS/eip-1930.md @@ -0,0 +1,120 @@ +--- +eip: 1930 +title: CALLs with strict gas semantic. Revert if not enough gas available. +author: Ronan Sandford (@wighawag) +type: Standards Track +discussions-to: https://github.com/ethereum/EIPs/issues/1930 +category: Core +status: Draft +created: 2019-04-10 +--- + +## Simple Summary + +Add the ability for smart contract to execute calls with a specific amount of gas. If this is not possible the execution should revert. + +## Abstract + +The current CALL, DELEGATE_CALL, STATIC_CALL opcode do not enforce the gas being sent, they simply consider the gas value as a maximum. This pose serious problem for applications that require the call to be executed with a precise amount of gas. + +This is for example the case for meta-transaction where the contract needs to ensure the call is executed exactly as the signing user intended. + +But this is also the case for common use cases, like checking "on-chain" if a smart contract support a specific interface (via [EIP-165](http://eips.ethereum.org/EIPS/eip-165) for example). + +The solution presented here is to add new opcodes that enforce the amount of gas specified : the call either proceed with the exact amount of gas or do not get executed and the current call revert. + + +### Specification + +- add a new variant of the CALL opcode where the gas specified is enforced so that if the gas left at the point of call is not enough to give the specified gas to the destination, the current call revert +- add a new variant of the DELEGATE_CALL opcode where the gas specified is enforced so that if the gas left at the point of call is not enough to give the specified gas to the destination, the current call revert +- add a new variant of the STATIC_CALL opcode where the gas specified is enforced so that if the gas left at the point of call is not enough to give the specified gas to the destination, the current call revert + +In other words, based on [EIP-150](http://eips.ethereum.org/EIPS/eip-150), the current call must revert unless G >= I x 64/63 where G is gas left at the point of call (after deducing the cost of the call itself) and I is the gas specified. + +So instead of +``` +availableGas = availableGas - base +gas := availableGas - availableGas/64 +... +if !callCost.IsUint64() || gas < callCost.Uint64() { + return gas, nil +} +``` +see https://github.com/ethereum/go-ethereum/blob/7504dbd6eb3f62371f86b06b03ffd665690951f2/core/vm/gas.go#L41-L48 + +we would have +``` +availableGas = availableGas - base +gas := availableGas - availableGas/64 +if !callCost.IsUint64() || gas < callCost.Uint64() { + return 0, errNotEnoughGas +} +``` + +### Rationale + +Currenlty the gas specified as part of these opcodes is simply a maximum value. And due to the behavior of [EIP-150](http://eips.ethereum.org/EIPS/eip-150) it is possible for an external call to be given less gas than intended (less than the gas specified as part of the CALL) while the rest of the current call is given enough to continue and succeed. Indeed since with EIP-150, the external call is given at max ```G - Math.floor(G/64)``` where G is the gasleft() at the point of the CALL, the rest of the current call is given ```Math.floor(G/64)``` which can be plenty enough for the transaction to succeed. For example, when G = 6,400,000 the rest of the transaction will be given 100,000 gas plenty enough in many case to succeed. + +This is an issue for contracts that require external call to only fails if they would fails with enough gas. This requirement is present in smart contract wallet and meta transaction in general, where the one executing the transaction is not the signer of the execution data. Because in such case, the contract needs to ensure the call is executed exactly as the signing user intended. + +But this is also true for simple use case, like checking if a contract implement an interface via EIP-165. Indeed as specified by such EIP, the ```supporstInterface``` method is bounded to use 30,000 gas so that it is theorically possible to ensure that the throw is not a result of a lack of gas. Unfortunately due to how the different CALL opcodes behave contracts can't simply rely on the gas value specified. They have to ensure by other means that there is enough gas for the call. + +Indeed, if the caller do not ensure that 30,000 gas or more is provided to the callee, the callee might throw because of a lack of gas (and not because it does not support the interace), and the parent call will be given up to 476 gas to continue. This would result in the caller interepreting wrongly that the callee is not implementing the interface in question. + +While such requirement can be enforced by checking the gas left according to EIP-150 and the precise gas required before the call (see solution presented in that [bug report](https://web.solidified.io/contract/5b4769b1e6c0d80014f3ea4e/bug/5c83d86ac2dd6600116381f9) or after the call (see the native meta transaction implementation [here](https://github.com/pixowl/thesandbox-contracts/blob/623f4d4ca10644dcee145bcbd9296579a1543d3d/src/Sand/erc20/ERC20MetaTxExtension.sol#L176), it would be much better if the EVM allowed us to strictly specify how much gas is to be given to the CALL so contract implementations do not need to follow [EIP-150](http://eips.ethereum.org/EIPS/eip-150) behavior and the current gas pricing so closely. + +This would also allow the behaviour of [EIP-150](http://eips.ethereum.org/EIPS/eip-150) to be changed without having to affect contract that require this strict gas behaviour. + +As mentioned, such strict gas behaviour is important for smart contract wallet and meta transaction in general. +The issue is actually already a problem in the wild as can be seen in the case of Gnosis safe which did not consider the behavior of EIP-150 and thus fails to check the gas properly, requiring the safe owners to add otherwise unecessary extra gas to their signed message to avoid the possibility of losing funds. See https://github.com/gnosis/safe-contracts/issues/100 + +As for EIP-165, the issue already exists in the example implementation presented in the EIP. Please see the details of the issue [here](https://github.com/ethereum/EIPs/pull/881#issuecomment-491677748) + +The same issue exists also on OpenZeppelin implementation, a library used by many. It does not for perform any check on gas before calling ```supportsInterface``` with 30,000 gas (see [here](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/fa004a7f5de572b3dbcde1a8a81f9a87e353e799/contracts/introspection/ERC165Checker.sol#L37) and is thus vulnerable to the issue mentioned. + + +While such issue can be prevented today by checking the gas with EIP-150 in mind, a solution at the opcode level is more elegant. + +Indeed, the two possible ways to currently enforce that the correct amount of gas is sent are as follow : + +1) check done before the call + +``` +uint256 gasAvailable = gasleft() - E; +require(gasAvailable - gasAvailable / 64 >= `txGas`, "not enough gas provided") +to.call.gas(txGas)(data); // CALL +``` +where E is the gas required for the operation beteen the call to ```gasleft()``` and the actual call PLUS the gas cost of the call itself. +While it is possible to simply over estimate ```E``` to prevent call to be executed if not enough gas is provided to the current call it would be better to have the EVM do the precise work itself. As gas pricing continue to evolve, this is important to have a mechanism to ensure a specific amount of gas is passed to the call so such mechanism can be used without having to relies on a specific gas pricing. + + +2) check done after the call: + +``` +to.call.gas(txGas)(data); // CALL +require(gasleft() > txGas / 63, "not enough gas left"); +``` +This solution does not require to compute a ```E``` value and thus do not relies on a specific gas pricing (except for the behaviour of EIP-150) since if the call is given not enough gas and fails for that reason, the condition above will always fail, ensuring the current call will revert. +But this check still pass if the gas given was less AND the external call reverted or succeeded EARLY (so that the gas left after the call > txGas / 63). +This can be an issue if the code executed as part of the CALL is reverting as a result of a check against the gas provided. Like a meta transaction in a meta transaction. + +Similarly to the the previous solution, an EVM mechanism would be much better. + +## Backwards Compatibility + +Backwards compatible as it introduce new opcodes. + +## Test Cases + +## Implementation + +None fully implemented yet. But see Specifications for an example in geth. + +## References + +1. EIP-150, http://eips.ethereum.org/EIPS/eip-150 + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 53dfa16d1282a13c4d436f1631be8b2232ab436c Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Tue, 14 May 2019 14:02:05 -0400 Subject: [PATCH 211/431] EIP-2015: Wallet Update Chain Method (#2015) * Create eip-2015.md * Include JSON RPC method in title * add requires 155 * update nativeCurrency field for wallet_updateChain * EIP-2015 format review changes * Update EIP-2015 discussions-to link --- EIPS/eip-2015.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 EIPS/eip-2015.md diff --git a/EIPS/eip-2015.md b/EIPS/eip-2015.md new file mode 100644 index 00000000..f3f0a187 --- /dev/null +++ b/EIPS/eip-2015.md @@ -0,0 +1,81 @@ +--- +eip: 2015 +title: Wallet Update Chain JSON-RPC Method (`wallet_updateChain`) +author: Pedro Gomes (@pedrouid) +discussions-to: https://ethereum-magicians.org/t/eip-2015-wallet-update-chain-json-rpc-method-wallet-updatechain/3274 +status: Draft +type: Standards Track +category: ERC +created: 2019-05-12 +requires: 155, 1474 +--- + +## Simple Summary +Wallets can update the active chain when connected to a Dapp but not vice-versa, with `wallet_updateChain` the Dapp will be able to request this change from the Wallet. + +## Abstract +Dapp can request the Wallet to switch chains by providing the minimal parameters of `chainId`, `networkId`, `rpcUrl` and `nativeCurrency`. The Wallet will display a UI element to inform the user of this change. + +## Motivation +Wallet and Dapp communication rely on the present provider that acts as middleware between the two. Using JSON-RPC methods, the Dapp is able to access not only the active accounts but also the active chain. With [EIP-1102](https://eips.ethereum.org/EIPS/eip-1102) we introduced the ability for Dapps to request access to the active accounts and the Wallet is able to provide a simple UI to inform the user of this action however the same is not currently possible for switching chains. The current pattern is to display some UI to request the user to switch chains within the Dapp, however this could be easily improved by triggering a UI from the Wallet side that can be approved or rejected by the user instead. + +## Specification +The JSON RPC method will be part of `wallet_` namespaced methods which aim to improve the UX and interoperability between Dapps and Wallets. + +### Required Parameters +- chainId (number): the id of the chain complaint with EIP-155 +- networkId (number): the id of the chain's network +- rpcUrl (string): the url endpoint for RPC requests for this chain +- nativeCurrency (Object): includes two fields for `name` (string) and `symbol` (string) + + +### Best Practices +- The Wallet should display a UI view similar to a [EIP-1102](https://eips.ethereum.org/EIPS/eip-1102) informing the user that the currently connected Dapp wants to switch to the specified chain. +- the Wallet should default the rpcUrl to any existing endpoints matching a chainId known previously to the wallet, otherwise it will use the provided rpcUrl as a fallback. +- the Wallet should call the rpcUrl with `net_version` and `eth_chainId` to verify the provided chainId and networkId match the responses from the rpcUrl +- the Wallet should change all nativeCurrency symbols to the provided parameter + +### Example 1 +A JSON-RPC request from a Dapp to switch the Ethereum Goerli chain would be as follows: +```json +{ + "id":1, + "jsonrpc": "2.0", + "method": "wallet_updateChain", + "params": [ + { + "chainId": 5, + "networkId": 5, + "rpcUrl": "https://goerli.infura.io/v3/406405f9c65348f99d0d5c27104b2213", + "nativeCurrency": { + "name": "Goerli ETH", + "symbol": "gorETH" + } + } + ] +} +``` + +### Example 2 +A JSON-RPC request from a Dapp to switch the POA Network's xDAI chain would be as follows: +```json +{ + "id":1, + "jsonrpc": "2.0", + "method": "wallet_updateChain", + "params": [ + { + "chainId": 100, + "networkId": 100, + "rpcUrl": "https://dai.poa.network", + "nativeCurrency": { + "name": "xDAI", + "symbol": "xDAI" + } + } + ] +} +``` + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 90d9ce607c872f7a87e928d37a8d12983a3e8f28 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Thu, 16 May 2019 13:04:57 -0700 Subject: [PATCH 212/431] Automatically merged updates to draft EIP(s) 1679 (#2034) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 374cf6ed..4627ae49 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -28,13 +28,14 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista ### Proposed EIPs +- [EIP-615](https://eips.ethereum.org/EIPS/eip-615): Subroutines and Static Jumps for the EVM - [EIP-1057](https://eips.ethereum.org/EIPS/eip-1057): ProgPoW, a Programmatic Proof-of-Work - There is a [pending audit](https://medium.com/ethereum-cat-herders/progpow-audit-goals-expectations-75bb902a1f01), above and beyond standard security considerations, that should be evaluated prior to inclusion. -- [EIP-1108](https://eips.ethereum.org/EIPS/eip-1108): Reduce alt_bn128 precompile gas costs +- [EIP-1108](https://eips.ethereum.org/EIPS/eip-1108): Reduce alt_bn128 precompile gas costs - [EIP-1283](https://eips.ethereum.org/EIPS/eip-1283): Net gas metering for SSTORE without dirty maps - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts From 0ec6181771607c0f2b0eec95701af84442ec9b6c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 17 May 2019 03:16:37 +0100 Subject: [PATCH 213/431] Automatically merged updates to draft EIP(s) 663 (#2038) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-663.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-663.md b/EIPS/eip-663.md index 47786a1d..fe42c2b7 100644 --- a/EIPS/eip-663.md +++ b/EIPS/eip-663.md @@ -10,7 +10,7 @@ created: 2017-07-03 ## Abstract -`SWAP` and `DUP` instructions are limited to a stack depth of 16. Introduce two new instructions, `SWAPn` and `DUPn`, which lift this limitation and allow accessing the stack up to its full depth of 1024 items. +Currently, `SWAP` and `DUP` instructions are limited to a stack depth of 16. Introduce two new instructions, `SWAPn` and `DUPn`, which lift this limitation and allow accessing the stack up to its full depth of 1024 items. ## Motivation @@ -22,9 +22,12 @@ Introducing `SWAPn` and `DUPn` will provide an option to compilers to simplify a ## Specification +### Option A + Instructions `DUPn` (`0xb0`) and `SWAPn` (`0xb1`) are introduced, which take the top item from stack (referred to as `n`). If `n` exceeds 1024 or the current stack depth is less than `n`, then a stack underflow exception is issued. If the current stack depth is at the limit, a stack overflow exception is issued. +In both of these cases the EVM stops and all gas is consumed. Otherwise - for `DUPn` the stack item at depth `n` is duplicated at the top of the stack @@ -34,6 +37,20 @@ The gas cost for both instructions is set at 3. In reality the cost for such an Since both of these instructions require the top stack item to contain the position, it is still only possible to reach more than 16 stack items if there is at least one free stack slot. +This option has no effect no static analyzers, given no immediate value is introduced. + +### Option B + +The difference to Option A is that `DUPn` and `SWAPn` do not take the value of `n` from the top stack item, but instead encode it as a 16-bit big endian immediate value following the opcode. + +This results in wasting a byte in the cases of only referring to the top 255 stack items. + +### Option C + +This option extends Option A with two new instructions, `DUPSn` and `SWAPSn`, where the value of `n` is encoded as an 8-bit immediate value following the opcode. + +The value `n` has a range of 0 to 255, but otherwise the same rules apply as in Option A. + ## Rationale TBA From b55bd38afd432cc96b803079c4f68ee83c9cd67f Mon Sep 17 00:00:00 2001 From: "A. F. Dudley" Date: Fri, 17 May 2019 11:07:47 -0400 Subject: [PATCH 214/431] Automatically merged updates to draft EIP(s) 1679 (#2043) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1679.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 4627ae49..17b0a6a3 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -40,6 +40,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344): Add ChainID opcode - [EIP-1352](https://eips.ethereum.org/EIPS/eip-1352): Specify restricted address range for precompiles/system contracts - [EIP-1380](https://eips.ethereum.org/EIPS/eip-1380): Reduced gas cost for call to self +- [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559): Fee market change for ETH 1.0 chain - [EIP-1702](https://eips.ethereum.org/EIPS/eip-1702): Generalized account versioning scheme - [EIP-1706](https://eips.ethereum.org/EIPS/eip-1706): Disable SSTORE with gasleft lower than call stipend - [EIP-1803](https://eips.ethereum.org/EIPS/eip-1803): Rename opcodes for clarity From a1ff047fab03b90da0022cdb1451c9fbbde5c99d Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Fri, 17 May 2019 09:31:59 -0700 Subject: [PATCH 215/431] Automatically merged updates to draft EIP(s) 615 (#2044) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-615.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index 3db860cf..b584498d 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -69,9 +69,9 @@ Especially important is efficient translation to and from [eWasm](https://github These forms > *`INSTRUCTION`* > -> *`INSTRUCTION x`* +> *`INSTRUCTION x`* > -> *`INSTRUCTION x, y`* +> *`INSTRUCTION x, y`* name an *`INSTRUCTION`* with no, one and two arguments, respectively. An instruction is represented in the bytecode as a single-byte opcode. Any arguments are laid out as immediate data bytes following the opcode inline, interpreted as fixed length, MSB-first, two's-complement, two-byte positive integers. (Negative values are reserved for extensions.) @@ -102,7 +102,7 @@ To support subroutines, `BEGINSUB`, `JUMPSUB`, and `RETURNSUB` are provided. Br #### Switches, Callbacks, and Virtual Functions -Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. +Dynamic jumps are also used for `O(1)` indirection: an address to jump to is selected to push on the stack and be jumped to. So we also propose two more instructions to provide for constrained indirection. We support these with vectors of `JUMPDEST` or `BEGINSUB` offsets stored inline, which can be selected with an index on the stack. That constrains validation to a specified subset of all possible destinations. The danger of quadratic blow up is avoided because it takes as much space to store the jump vectors as it does to code the worst case exploit. Dynamic jumps to a `JUMPDEST` are used to implement `O(1)` jumptables, which are useful for dense switch statements. Wasm and most CPUs provide similar instructions. @@ -193,7 +193,7 @@ frame | 21 ______|___________ 22 <- SP ``` -and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` +and after pushing two arguments and branching with `JUMPSUB` to a `BEGINSUB 2, 3` ``` PUSH 10 PUSH 11 @@ -256,7 +256,7 @@ _Execution_ is as defined in the [Yellow Paper](https://ethereum.github.io/yello >**5** Invalid instruction -We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. +We propose to expand and extend the Yellow Paper conditions to handle the new instructions we propose. To handle the return stack we expand the conditions on stack size: >**2a** The size of the data stack does not exceed 1024. @@ -290,7 +290,7 @@ All of the remaining conditions we validate statically. #### Costs & Codes -All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an O(log n) binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` and the rest should be _verylow_. Measurement will tell. +All of the instructions are `O(1)` with a small constant, requiring just a few machine operations each, whereas a `JUMP` or `JUMPI` must do an `O(log n)` binary search of an array of `JUMPDEST` offsets before every jump. With the cost of `JUMPI` being _high_ and the cost of `JUMP` being _mid_, we suggest the cost of `JUMPV` and `JUMPSUBV` should be _mid_, `JUMPSUB` and `JUMPIF` should be _low_, and`JUMPTO` and the rest should be _verylow_. Measurement will tell. We suggest the following opcodes: ``` @@ -315,7 +315,7 @@ These changes would need to be implemented in phases at decent intervals: If desired, the period of deprecation can be extended indefinitely by continuing to accept code not versioned as new—but without validation. That is, by delaying or canceling phase 2. -Regardless, we will need a versioning scheme like [EIP-1702](https://github.com/ethereum/EIPs/pull/1702) to allow current code and EIP-615 code to coexist on the same blockchain. +Regardless, we will need a versioning scheme like [EIP-1702](https://github.com/ethereum/EIPs/pull/1702) to allow current code and EIP-615 code to coexist on the same blockchain. ## Rationale @@ -325,7 +325,7 @@ As described above, the approach was simply to deprecate the problematic dynamic ## Implementation -Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. The bulk of the effort is the validator, which in most languages can almost be transcribed from the pseudocode above. +Implementation of this proposal need not be difficult. At the least, interpreters can simply be extended with the new opcodes and run unchanged otherwise. The new opcodes require only stacks for the frame pointers and return offsets and the few pushes, pops, and assignments described above. The bulk of the effort is the validator, which in most languages can almost be transcribed from the pseudocode above. A lightly tested C++ reference implementation is available in [Greg Colvin's Aleth fork.](https://github.com/gcolvin/aleth/tree/master/libaleth-interpreter) This version required circa 110 lines of new interpreter code and a well-commented, 178-line validator. @@ -346,7 +346,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_sub[code_size] // is there a BEGINSUB at PC? is_dest[code_size] // is there a JUMPDEST at PC? sub_for_pc[code_size] // which BEGINSUB is PC in? - + bool validate_jumps(PC) { current_sub = PC @@ -366,7 +366,7 @@ Validating that jumps are to valid addresses takes two sequential passes over th is_dest[PC] = true sub_for_pc[PC] = current_sub } - + // check that targets are in subroutine for (PC = 0; instruction = bytecode[PC]; PC = advance_pc(PC)) { @@ -390,7 +390,7 @@ Note that code like this is already run by EVMs to check dynamic jumps, includin #### Subroutine Validation -This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|): The sum of the number of edges and number of verticies in the graph. +This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`: The sum of the number of edges and number of verticies in the graph. The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. @@ -440,7 +440,7 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t return false if instruction is STOP, RETURN, or SUICIDE - return true + return true // violates single entry if instruction is BEGINSUB @@ -463,10 +463,10 @@ The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to t if instruction is JUMPTO { PC = jump_target(PC) - continue + continue } - // recurse to jump to code to validate + // recurse to jump to code to validate if instruction is JUMPIF { if not validate_subroutine(jump_target(PC), return_pc, SP) From 9ed4e96857e436916c0c3df6879803166ba58ad5 Mon Sep 17 00:00:00 2001 From: Tom Brand <45038918+TomStarkWare@users.noreply.github.com> Date: Sat, 18 May 2019 03:26:00 +0300 Subject: [PATCH 216/431] Calldata gas cost reduction (#2028) * Calldata gas cost reduction Added a draft of EIP to reduce the gas cost of Calldata * changed name to 2028 * Added EIP-2028 to meta eip-1679 * Added discussion url * edited 'motivation' & 'specification' Edited motivation to increase readability. Edited specification to clarify terms. --- EIPS/eip-1679.md | 1 + EIPS/eip-2028.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 EIPS/eip-2028.md diff --git a/EIPS/eip-1679.md b/EIPS/eip-1679.md index 17b0a6a3..866cf780 100644 --- a/EIPS/eip-1679.md +++ b/EIPS/eip-1679.md @@ -46,6 +46,7 @@ This meta-EIP specifies the changes included in the Ethereum hardfork named Ista - [EIP-1803](https://eips.ethereum.org/EIPS/eip-1803): Rename opcodes for clarity - [EIP-1829](https://eips.ethereum.org/EIPS/eip-1829): Precompile for Elliptic Curve Linear Combinations - [EIP-1884](https://eips.ethereum.org/EIPS/eip-1884): Repricing for trie-size-dependent opcodes +- [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028): Calldata gas cost reduction ## Timeline diff --git a/EIPS/eip-2028.md b/EIPS/eip-2028.md new file mode 100644 index 00000000..e5fbb8a2 --- /dev/null +++ b/EIPS/eip-2028.md @@ -0,0 +1,75 @@ +--- +eip: 2028 +title: Calldata gas cost reduction +author: Alexey Akhunov(@AlexeyAkhunov), Eli Ben Sasson (eli@starkware.co), Tom Brand (tom@starkware.co), Avihu Levy (avihu@starkware.co) +discussions-to: https://ethereum-magicians.org/t/eip-2028-calldata-gas-cost-reduction/3280 +status: Draft +type: Standards Track +category: Core +created: 2019-05-03 +--- + +## Simple Summary +We propose to reduce the gas cost of Calldata (`GTXDATANONZERO`) from its current value of 68 gas per byte to a lower cost, to be backed by mathematical modeling and empirical estimates. The mathematical model is the one used in the works of Sompolinsky and Zohar [1] and Pass, Seeman and Shelat [2], which relates network security to network delay. We shall (1) evaluate the theoretical impact of lower Calldata gas cost on network delay using this model, (2) validate the model empirically, and (3) base the proposed gas cost on our findings. + +## Motivation +There are a couple of main benefits to accepting this proposal and lowering gas cost of Calldata +On-Chain Scalability: Generally speaking, higher bandwidth of Calldata improves scalability, as more data can fit within a single block. +* Layer two scalability: Layer two scaling solutions can improve scalability by moving storage and computation off-chain, but often introduce data transmission instead. + - Proof systems such as STARKs and SNARKs use a single proof that attests to the computational integrity of a large computation, say, one that processes a large batch of transactions. + - Some solutions use fraud proofs which requires a transmission of merkle proofs. + - Moreover, one optional data availability solution to layer two is to place data on the main chain, via Calldata. +* Stateless clients: The same model will be used to determine the price of the state access for the stateless client regime, which will be proposed in the State Rent (from version 4). There, it is expected that the gas cost of state accessing operation will increase roughly proportional to the extra bandwidth required to transmit the “block proofs” as well as extra processing required to verify those block proofs. + +## Specification +The gas per non-zero byte is reduced from 68 to TBD. Gas cost of zero bytes is unchanged. + +## Rationale +Roughly speaking, reducing the gas cost of Calldata leads to potentially larger blocks, which increases the network delay associated with data transmission over the network. This is only part of the full network delay, other factors are block processing time (and storage access, as part of it). Increasing network delay affects security by lowering the cost of attacking the network, because at any given point in time fewer nodes are updated on the latest state of the blockchain. + +Yonatan Sompolinsky and Aviv Zohar suggested in [1] an elegant model to relate network delay to network security, and this model is also used in the work of Rafael Pass, Lior Seeman and Abhi Shelat [2]. We briefly explain this model below, because we shall study it theoretically and validate it by empirical measurements to reach the suggested lower gas cost for Calldata. + +The model uses the following natural parameters: +* _lambda_ denotes the block creation rate [1/s]: We treat the process of finding a PoW +solution as a poisson process with rate _lambda_. +* _beta_ - chain growth rate [1/s]: the rate at which new blocks are added to +the heaviest chain. +* _D_ - block delay [s]: The time that elapses between the mining of a new block and its acceptance by all the miners (all miners switched to mining on top of that block). + +### _Beta_ Lower Bound +Notice that _lambda_ => _beta_, because not all blocks that are found will enter the main chain (as is the case with uncles). In [1] it was shown that for a blockchain using the longest chain rule, one may bound _beta_ from below by _lambda_/ (1+ D * _lambda_). This lower bound holds in the extremal case where the topology of the network is a clique in which the delay between each pair of nodes is D, the maximal possible delay. Recording both the lower and upper bounds on _beta_ we get + + _lambda_ >= _beta_ >= _lambda_ / (1 + D * _lambda_) (*) + +Notice, as a sanity check, that when there is no delay (D=0) then _beta_ equals _lambda_, as expected. + +### Security of the network +An attacker attempting to reorganize the main chain needs to generate blocks at a rate that is greater than _beta_. +Fixing the difficulty level of the PoW puzzle, the total hash rate in the system is correlated to _lambda_. Thus, _beta_ / _lambda_ is defined as the the *efficiency* of the system, as it measures the fraction of total hash power that is used to generate the main chain of the network. + +Rearranging (*) gives the following lower bound on efficiency in terms of delay: + + _beta_ / _lambda_ >= 1 / (1 + D * _lambda_) (**) + +### The _delay_ parameter D +The network delay depends on the location of the mining node within the network and on the current network topology (which changes dynamically), and consequently is somewhat difficult to measure directly. +Previously, Christian Decker and Roger Wattenhofer [3] showed that propagation time scales with blocksize, and Vitalik Buterin showed that uncle rate, which is tightly related to efficiency (**) measure, also scales with block size [4]. + +However, the delay function can be decomposed into two parts D = *D_t* + *D_p*, where _D_t_ is the delay caused by the transmission of the block and _D_p_ is the delay caused by the processing of the block by the node. Our model and tests will examine the effect of Calldata on each of _D_t_ and _D_p_, postulating that their effect is different. This may be particularly relevant for Layer 2 Scalability and for Stateless Clients (Rationales 2, 3 above) because most of the Calldata associated with these goals are Merkle authentication paths that have a large _D_t_ component but relatively small _D_p_ values. + +## Test Cases +To suggest the gas cost of calldata we shall conduct two types of tests: +1. Network tests, conducted on the Ethereum mainnet, used to estimate the effect on increasing block size on _D_p_ and _D_t_, on the overall network delay D and the efficiency ratio (**), as well as delays between different mining pools. Those tests will include regression tests on existing data, and stress tests to introduce extreme scenarios. +2. Local tests, conducted on a single node and measuring the processing time as a function of Calldata amount and general computation limits. + +## References +[1] Yonatan Sompolinsky, Aviv Zohar: [Secure High-Rate Transaction Processing in Bitcoin](https://eprint.iacr.org/2013/881.pdf). Financial Cryptography 2015: 507-527 + +[2] Rafael Pass, Lior Seeman, Abhi Shelat: [Analysis of the Blockchain Protocol in Asynchronous Networks](https://eprint.iacr.org/2016/454.pdf), ePrint report 2016/454 + +[3] Christian Decker, Roger Wattenhofer: [Information propagation in the Bitcoin network](http://www.gsd.inesc-id.pt/~ler/docencia/rcs1314/papers/P2P2013_041.pdf). P2P 2013: 1-10 + +[4] Vitalik Buterin: [Uncle Rate and Transaction Fee Analysis](https://blog.ethereum.org/2016/10/31/uncle-rate-transaction-fee-analysis/) + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 5e6d4885f965dd7a54c9e665832d9ba2e25088c5 Mon Sep 17 00:00:00 2001 From: Andrew Cooke Date: Sat, 18 May 2019 11:16:55 -0400 Subject: [PATCH 217/431] Automatically merged updates to draft EIP(s) 1155 (#2049) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1155.md | 56 +++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 322738e3..f7c1de48 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -1,7 +1,7 @@ --- eip: 1155 title: ERC-1155 Multi Token Standard -author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet +author: Witek Radomski , Andrew Cooke , Philippe Castonguay , James Therien , Eric Binet , Ronan Sandford type: Standards Track category: ERC status: Draft @@ -13,7 +13,7 @@ requires: 165 ## Simple Summary -A standard interface for contracts that manage multiple token types. A single deployed contract may include any combination of fungible tokens, non-fungible tokens, or other configurations (for example, semi-fungible tokens). +A standard interface for contracts that manage multiple token types. A single deployed contract may include any combination of fungible tokens, non-fungible tokens, or other configurations (e.g. semi-fungible tokens). ## Abstract @@ -84,13 +84,13 @@ interface ERC1155 /* is ERC165 */ { MUST revert if `_to` is the zero address. MUST revert if balance of holder for token `_id` is lower than the `_value` sent. MUST revert on any other error. - After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). - MUST emit `TransferSingle` event on transfer success (see "Safe Transfer Rules" section of the standard). + MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param _from Source address @param _to Target address @param _id ID of the token type @param _value Transfer amount - @param _data Additional data with no specified format, MUST be sent in call to `onERC1155Received` on `_to` + @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` */ function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; @@ -100,15 +100,15 @@ interface ERC1155 /* is ERC165 */ { MUST revert if `_to` is the zero address. MUST revert if length of `_ids` is not the same as length of `_values`. MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. - MUST revert on any other error. - Transfers and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). - MUST emit `TransferSingle` or `TransferBatch` event(s) on transfer success (see "Safe Transfer Rules" section of the standard). + MUST revert on any other error. + MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). @param _from Source address @param _to Target address @param _ids IDs of each token type (order and length must match _values array) @param _values Transfer amounts per token type (order and length must match _ids array) - @param _data Additional data with no specified format, MUST be sent in call to the `ERC1155TokenReceiver` hook(s) on `_to` + @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` */ function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external; @@ -193,13 +193,13 @@ interface ERC1155TokenReceiver { This function MUST NOT consume more than 5,000 gas. @return `bytes4(keccak256("isERC1155TokenReceiver()"))` */ - function isERC1155TokenReceiver() external pure returns (bytes4); + function isERC1155TokenReceiver() external view returns (bytes4); } ``` ### Safe Transfer Rules -To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate with respect to the `ERC1155TokenReceiver`, a list of scenarios and rules follows. +To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate with respect to the `ERC1155TokenReceiver` hook functions, a list of scenarios and rules follows. #### Scenarios @@ -219,22 +219,30 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op **_Scenario#5 :_** The receiver implements the necessary `ERC1155TokenReceiver` interface function(s) but throws an error. * The transfer MUST be reverted. -**_Scenario#6 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of one and only one balance change (eg. safeTransferFrom called). +**_Scenario#6 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of one and only one balance change (e.g. safeTransferFrom called). * All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. +* All the transfer events for the transfer MUST have been emitted to reflect the balance changes before any hook is called on a recipient. * One of `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient. * The `onERC1155Received` hook SHOULD be called on the recipient contract and its rules followed. - See "onERC1155Received rules" for further rules that MUST be followed. * The `onERC1155BatchReceived` hook MAY be called on the recipient contract and its rules followed. - See "onERC1155BatchReceived rules" for further rules that MUST be followed. -**_Scenario#7 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of more than one balance change (eg. safeBatchTransferFrom called). +**_Scenario#7 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of more than one balance change (e.g. safeBatchTransferFrom called). * All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. +* All the transfer events for the transfer MUST have been emitted to reflect the balance changes before any hook is called on a recipient. * `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient as many times as necessary such that every balance change for the recipient in the scenario is accounted for. - The return magic value for every hook call MUST be checked and acted upon as per "onERC1155Received rules" and "onERC1155BatchReceived rules". * The `onERC1155BatchReceived` hook SHOULD be called on the recipient contract and its rules followed. - See "onERC1155BatchReceived rules" for further rules that MUST be followed. * The `onERC1155Received` hook MAY be called on the recipient contract and its rules followed. - See "onERC1155Received rules" for further rules that MUST be followed. + +**_Scenario#8 :_** You are the creator of a contract that implements the `ERC1155TokenReceiver` interface and you forward the token(s) onto another address in one or both of `onERC1155Received` and `onERC1155BatchReceived`. +* Forwarding should be considered acceptance and then initiating a new `safeTransferFrom` or `safeBatchTransferFrom` in a new context. + - The prescribed keccak256 acceptance value magic for the receiver hook being called MUST be returned after forwarding is successful. +* The `_data` argument MAY be re-purposed for the new context. +* If forwarding unexpectedly fails the transaction MUST be reverted. #### Rules @@ -243,8 +251,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op * MUST revert if `_to` is the zero address. * MUST revert if balance of holder for token `_id` is lower than the `_value` sent to the recipient. * MUST revert on any other error. -* After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "onERC1155Received rules" section). -* MUST emit `TransferSingle` event on transfer success (see "TransferSingle and TransferBatch event rules" section). +* MUST emit the `TransferSingle` event to reflect the balance change (see "TransferSingle and TransferBatch event rules" section). +* After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "onERC1155Received rules" section). **_safeBatchTransferFrom rules:_** * Caller must be approved to manage all the tokens being transferred out of the `_from` account (see "Approval" section). @@ -252,9 +260,9 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op * MUST revert if length of `_ids` is not the same as length of `_values`. * MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. * MUST revert on any other error. -* After the above conditions are met, this function MUST check if `_to` is a smart contract (eg. code size > 0). If so, it MUST call `onERC1155Received` or `onERC1155BatchReceived` on `_to` and act appropriately (see "`onERC1155Received` and onERC1155BatchReceived rules" section). -* MUST emit `TransferSingle` or `TransferBatch` event(s) on transfer success (see "TransferSingle and TransferBatch event rules" section). -* Transfers and events MUST occur in the array order they were submitted (_ids[0]/_values[0] before _ids[1]/_values[1], etc). +* MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "TransferSingle and TransferBatch event rules" section). +* The balance changes and events MUST occur in the array order they were submitted (_ids[0]/_values[0] before _ids[1]/_values[1], etc). +* After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` or `onERC1155BatchReceived` on `_to` and act appropriately (see "`onERC1155Received` and onERC1155BatchReceived rules" section). **_TransferSingle and TransferBatch event rules:_** * `TransferSingle` SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. @@ -278,6 +286,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). * The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. * To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the `TransferSingle` event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. +* All `TransferSingle` and `TransferBatch` events MUST be emitted to reflect all the balance changes that have occurred before any call(s) to `onERC1155Received` or `onERC1155BatchReceived`. + - To make sure event order is correct in the case of valid re-entry (e.g. if a receiver contract forwards tokens on receipt) state balance and events balance MUST match before calling an external contract. **_onERC1155Received rules:_** * The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). @@ -285,7 +295,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - `_from` MUST be 0x0 for a mint. * The `_id` argument MUST be the token type being transferred. * The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. -* The `_data` argument MUST contain the extra information provided by the sender for the transfer. +* The `_data` argument MUST contain the unaltered information provided by the sender for the transfer. + - i.e. it MUST pass on the unaltered `_data` argument sent via the `safeTransferFrom` or `safeBatchTransferFrom` call for this transfer. * The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` - If the return value is `bytes4(keccak256("accept_erc1155_tokens()"))` the transfer MUST be completed or MUST revert if any other conditions are not met for success. * The recipient contract MAY reject an increase of its balance by calling revert. @@ -301,7 +312,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op - `_from` MUST be 0x0 for a mint. * The `_ids` argument MUST be the list of tokens being transferred. * The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in `_ids`) the holder balance is decreased by and match what the recipient balance is increased by. -* The `_data` argument MUST contain the information provided by the sender for a transfer. +* The `_data` argument MUST contain the unaltered information provided by the sender for the transfer. + - i.e. it MUST pass on the unaltered `_data` argument sent via the `safeTransferFrom` or `safeBatchTransferFrom` call for this transfer. * The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` - If the return value is `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transfer MUST be completed or MUST revert if any other conditions are not met for success. * The recipient contract MAY reject an increase of its balance by calling revert. @@ -314,7 +326,7 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op **_isERC1155TokenReceiver rules:_** * The implementation of `isERC1155TokenReceiver` function SHOULD be as follows: ``` - function isERC1155TokenReceiver() external pure returns (bytes4) { + function isERC1155TokenReceiver() external view returns (bytes4) { return 0x0d912442; // bytes4(keccak256("isERC1155TokenReceiver()")) } ``` From 433a6ce99825b134e3c5dbf6792667f7331ad941 Mon Sep 17 00:00:00 2001 From: Ronan Sandford Date: Sun, 19 May 2019 07:51:33 +0100 Subject: [PATCH 218/431] EIP-1965 Method to check if a chainID is valid at a specific block Number (#1965) --- EIPS/eip-1965.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 EIPS/eip-1965.md diff --git a/EIPS/eip-1965.md b/EIPS/eip-1965.md new file mode 100644 index 00000000..ff432fa0 --- /dev/null +++ b/EIPS/eip-1965.md @@ -0,0 +1,63 @@ +--- +eip: 1965 +title: Method to check if a chainID is valid at a specific block Number +author: Ronan Sandford (@wighawag) +category: Core +type: Standards Track +discussions-to: https://ethereum-magicians.org/t/eip-1965-valid-chainid-for-specific-blocknumber-protect-all-forks/3181 +status: Draft +created: 2019-04-20 +requires: 155 +--- + +## Abstract +This EIP adds a precompile that returns whether a specific chainID (EIP-155 unique identifier) is valid at a specific blockNumber. ChainID are assumed to be valid up to the blockNumber at which they get replaced by a new chainID. + +## Motivation +[EIP-155](https://eips.ethereum.org/EIPS/eip-155) proposes to use the chain ID to prevent the replay of transactions between different chains. It would be a great benefit to have the same possibility inside smart contracts when handling off-chain message signatures, especially for Layer 2 signature schemes using [EIP-712](https://eips.ethereum.org/EIPS/eip-712). + +[EIP-1344](http://eips.ethereum.org/EIPS/eip-1344) is attempting to solve this by giving smart contract access to the tip of the chainID history. This is insuficient as such value is changing. Hence why EIP-1344 describes a contract based solution to work arround the problem. It would be better to solve it in a simpler, cheaper and safer manner, removing the potential risk of misuse present in EIP-1344. Furthermore EIP-1344 can't protect replay properly for minority-led hardfork as the caching system cannot guarantee accuracy of the blockNumber at which the new chainID has been introduced. + +[EIP-1959](https://github.com/ethereum/EIPs/pull/1959) solves the issue of EIP-1344 but do not attempt to protect from minority-led hardfork as mentioned in the rationale. We consider this a mistake, since it remove some freedom to fork. We consider that all fork should be given equal oportunities. And while there will always be issues we can't solve for the majority that ignore a particular fork, **users that decide to use both the minority-fork and the majority-chain should be protected from replay without having to wait for the majority chain to update its chainID.** + +## Specification +Adds a new precompile which uses 2 argument : a 32 bytes value that represent the chainID to test and a 32 bytes value representing the blockNumber at which the chainID is tested. It return 0x1 if the chainID is valid at the specific blockNumber, 0x0 otherwise. Note that chainID are considered valid up to the blockNumber at which they are replaced. So they are valid for every blockNumber past their replacement. + +The operation will costs no more than `G_blockhash` + `G_verylow` to execute. This could be lower as chainID are only introduced during hardfork. + +The cost of the operation might need to be adjusted later as the number of chainID in the history of the chain grows. + +Note though that the alternative to keep track of old chainID is to implement a smart contract based caching solution as EIP-1344 proposes comes with an overall higher gas cost and exhibit issues for minority-led hardfork (see Rationale section below). As such the gas cost is simply a necessary cost for the feature. + +## Rationale + +The rationale at EIP-1959 applies here as well too : + +- An opcode is better than a caching system for past chainID, It is cheaper, safer and do not include gaps. +- Direct access to the latest chainID is dangerous since it make it easy for contract to use it as a replay protection mechanism while preventing otherwise valid old messages to be valid after a fork that change the chainID. This can have disastrous consequences on users. +- all off-chain messaged signed before a fork should be valid across all side of the fork. + +The only difference is that this current proposal propose a solution to protect hardfork led by a minority. + +To summarize there is 2 possible fork scenario : + +1) The majority decide to make an hardfork but a minority disagree with it (ETC is such example). The fork is planned for block X. If the majority is not taking any action to automate the process of assigning a different chainID for both, the minority has plenty of time to plan for a chainID upgrade to happen at that same block X. Now if they do not do it, their users will face the problem that their messages will be replayable on the majority chain (Note that this is not true the other way around as we assume the majority decided to change the chainID). As such there is no reason that they’ll leave it that way. + +2) A minority decide to create an hardfork that the majority disagree with (or simply ignore). Now, the same as above can happen but since we are talking about a minority there is a chance that the majority do not care about the minority. In that case, there would be no incentive for the majority to upgrade the chainID. This means that user of both side of the fork will have the messages meant for the majority chain replayable on the minority-chain (even if this one changed its chainID) unless extra precaution is taken. + +The solution is to add the blockNumber representing the time at which the message was signed and use it as an argument to the opcode proposed here. This way, when the minority forks with a new chainID, the previous chainID become invalid from that time onward. So new messages destinated to the majority chain can't be replayed on the minority fork. + + +## Backwards Compatibility + +EIP-712 is still in draft but would need to be updated to include the blockNumber as part of the values that wallets need to verify for the protection of their users. + +Since chainID and blockNumber will vary, they should not be part of the domain separator (meant to be generated once) but another part of the message. + +While the pair could be optional for contract that do not care about replays or have other ways to prevent them, if chainID is present, the blockNumber must be present too. And if any of them is present, wallet need to ensure that the chainID is indeed the latest one of the chain being used, while the blockNumber is the latest one at the point of signing. During fork transition, the wallet can use the blockNumber to know which chainID to use. + +## References +This was previously suggested as part of [EIP1959 discussion](https://ethereum-magicians.org/t/eip-1959-valid-chainid-opcode/3170). + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). \ No newline at end of file From af982f1470624791da334b09d3e4f2e4de5e1265 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Sun, 19 May 2019 07:54:10 +0100 Subject: [PATCH 219/431] Run spelling checks on CI (#2040) --- .codespell-whitelist | 7 +++++++ .travis-ci.sh | 2 ++ .travis.yml | 5 ++++- EIPS/eip-1011.md | 4 ++-- EIPS/eip-1015.md | 8 ++++---- EIPS/eip-1057.md | 6 +++--- EIPS/eip-1066.md | 12 ++++++------ EIPS/eip-107.md | 8 ++++---- EIPS/eip-1077.md | 4 ++-- EIPS/eip-1078.md | 2 +- EIPS/eip-1080.md | 2 +- EIPS/eip-1081.md | 2 +- EIPS/eip-1108.md | 2 +- EIPS/eip-1109.md | 4 ++-- EIPS/eip-1123.md | 2 +- EIPS/eip-1154.md | 2 +- EIPS/eip-1155.md | 2 +- EIPS/eip-1167.md | 2 +- EIPS/eip-1186.md | 2 +- EIPS/eip-1193.md | 2 +- EIPS/eip-1202.md | 2 +- EIPS/eip-1261.md | 4 ++-- EIPS/eip-1271.md | 2 +- EIPS/eip-1283.md | 2 +- EIPS/eip-1380.md | 2 +- EIPS/eip-1388.md | 2 +- EIPS/eip-1417.md | 12 ++++++------ EIPS/eip-145.md | 2 +- EIPS/eip-1450.md | 2 +- EIPS/eip-1462.md | 2 +- EIPS/eip-1470.md | 2 +- EIPS/eip-1484.md | 10 +++++----- EIPS/eip-1485.md | 6 +++--- EIPS/eip-1491.md | 34 ++++++++++++++++----------------- EIPS/eip-1571.md | 14 +++++++------- EIPS/eip-1613.md | 2 +- EIPS/eip-1616.md | 4 ++-- EIPS/eip-162.md | 2 +- EIPS/eip-165.md | 2 +- EIPS/eip-1681.md | 2 +- EIPS/eip-1702.md | 2 +- EIPS/eip-1775.md | 30 ++++++++++++++--------------- EIPS/eip-1895.md | 2 +- EIPS/eip-1922.md | 2 +- EIPS/eip-1930.md | 8 ++++---- EIPS/eip-1973.md | 8 ++++---- EIPS/eip-210.md | 2 +- EIPS/eip-3.md | 4 ++-- EIPS/eip-5.md | 2 +- EIPS/eip-615.md | 2 +- EIPS/eip-627.md | 4 ++-- EIPS/eip-706.md | 4 ++-- EIPS/eip-712.md | 4 ++-- EIPS/eip-725.md | 2 +- EIPS/eip-758.md | 4 ++-- EIPS/eip-823.md | 2 +- EIPS/eip-918.md | 8 ++++---- EIPS/eip-998.md | 4 ++-- README.md | 2 +- assets/eip-1057/test-vectors.md | 4 ++-- index.html | 2 +- 61 files changed, 152 insertions(+), 140 deletions(-) create mode 100644 .codespell-whitelist diff --git a/.codespell-whitelist b/.codespell-whitelist new file mode 100644 index 00000000..21c9c7e4 --- /dev/null +++ b/.codespell-whitelist @@ -0,0 +1,7 @@ +uint +ith +mitre +readded +crate +developper +ist diff --git a/.travis-ci.sh b/.travis-ci.sh index f907ac4d..98b6f814 100755 --- a/.travis-ci.sh +++ b/.travis-ci.sh @@ -24,4 +24,6 @@ elif [[ $TASK = 'eip-validator' ]]; then FILES="$(ls EIPS/*.md | egrep "eip-[0-9]+.md")" bundle exec eip_validator $FILES +elif [[ $TASK = 'codespell' ]]; then + codespell -q4 -I .codespell-whitelist eip-X.md EIPS/ fi diff --git a/.travis.yml b/.travis.yml index a4e1fb88..70b2fd19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ cache: - bundler - directories: - $TRAVIS_BUILD_DIR/tmp/.htmlproofer #https://github.com/gjtorikian/html-proofer/issues/381 - + - /usr/local/lib/python3.3/dist-packages/pip/ # Assume bundler is being used, therefore # the `install` step will run `bundle install` by default. @@ -29,6 +29,9 @@ matrix: env: TASK='htmlproofer-external' - rvm: 2.2.5 env: TASK='eip-validator' + - python: 3.3 + env: TASK='codespell' + before_script: "sudo pip install urllib3[secure] && sudo pip install codespell" allow_failures: - rvm: 2.2.5 env: TASK='htmlproofer-external' diff --git a/EIPS/eip-1011.md b/EIPS/eip-1011.md index 58b9264b..a35c0a7b 100644 --- a/EIPS/eip-1011.md +++ b/EIPS/eip-1011.md @@ -183,7 +183,7 @@ def check_and_finalize_new_checkpoint(new_block): db.last_finalized_block = finalized_hash ``` -The new chain scoring rule queries the casper contract to find the highest justified epoch that meets the client's minimum deposit requirement (`NON_REVERT_MIN_DEPOSITS`). The `10**40` multiplier ensures that the justified epoch takes precendence over block mining difficulty. `total_difficulty` only serves as a tie breaker if the two blocks in question have an equivalent `highest_justified_epoch`. +The new chain scoring rule queries the casper contract to find the highest justified epoch that meets the client's minimum deposit requirement (`NON_REVERT_MIN_DEPOSITS`). The `10**40` multiplier ensures that the justified epoch takes precedence over block mining difficulty. `total_difficulty` only serves as a tie breaker if the two blocks in question have an equivalent `highest_justified_epoch`. _Note_: If the client has no justified checkpoints, the contract returns `highest_justified_epoch` as `0` essentially reverting the fork choice rule to pure PoW. @@ -379,7 +379,7 @@ Any call to this method fails prior to the end of the `WARM_UP_PERIOD`. Thus the #### Issuance A fixed amount of 1.25M ETH was chosen as `CASPER_BALANCE` to fund the casper contract. This gives the contract enough runway to operate for approximately 2 years (assuming ~10M ETH in validator deposits). Acting similarly to the "difficulty bomb", this "funding crunch" forces the network to hardfork in the relative near future to further fund the contract. This future hardfork is an opportunity to upgrade the contract and transition to full PoS. -The PoW block reward is reduced from 3.0 to 0.6 ETH/block over the course of approximately one year because the security of the chain is greatly shifted from PoW difficulty to PoS finality and because rewards are now issued to both validators and miners. Rewards are stepped down by 0.6 ETH/block every 3 months (`REWARD_STEPDOWN_BLOCK_COUNT`) to provide for a conservative transition period from full PoW to hybrid PoS/PoW. This gives validators time to become familiar with the new technology and begin logging on and also provides the network with more leeway in case of any unforseen issues. If any major issues do arise, the Ethereum network will still have substantial PoW security to rely upon while decisions are made and/or patches are deployed. See [here](https://gist.github.com/djrtwo/bc864c0d0a275170183803814b207b9a) for further analysis of the current PoW security and of the effect of PoW block reward reduction in the context of Hybrid Casper FFG. +The PoW block reward is reduced from 3.0 to 0.6 ETH/block over the course of approximately one year because the security of the chain is greatly shifted from PoW difficulty to PoS finality and because rewards are now issued to both validators and miners. Rewards are stepped down by 0.6 ETH/block every 3 months (`REWARD_STEPDOWN_BLOCK_COUNT`) to provide for a conservative transition period from full PoW to hybrid PoS/PoW. This gives validators time to become familiar with the new technology and begin logging on and also provides the network with more leeway in case of any unforeseen issues. If any major issues do arise, the Ethereum network will still have substantial PoW security to rely upon while decisions are made and/or patches are deployed. See [here](https://gist.github.com/djrtwo/bc864c0d0a275170183803814b207b9a) for further analysis of the current PoW security and of the effect of PoW block reward reduction in the context of Hybrid Casper FFG. In addition to block rewards, miners now receive an issuance reward for including successful `vote` transactions into the block on time. This reward is equal to 1/8th that of the reward the validator receives for a successful `vote` transaction. Under optimal FFG conditions after group validator reward adjustments are made, miners receive approximately 1/5th of the total ETH issued by the Casper contract. diff --git a/EIPS/eip-1015.md b/EIPS/eip-1015.md index 4aecc15a..0d690fa6 100644 --- a/EIPS/eip-1015.md +++ b/EIPS/eip-1015.md @@ -12,7 +12,7 @@ created: 2018-04-20 ## Simple Summary -This EIP changes the block reward step by instead of setting it to be hard coded on the clients and to be given to the miner/validator etherbase, it should instead go to an address decided by an on-chain contract, with hard limits on how it would be issued (six month lock-in; issuance can only decrease or be mantained, but not increase;). A decision method is suggested but not essential to the notion of this EIP. This would **not be a generic governance solution**, which is a much broader and harder topic, would **not** affect technical upgrade decisions or other hard forks, but seen as *a forum to attempt to prevent contentious hard forks* that can be solved with the issuance. +This EIP changes the block reward step by instead of setting it to be hard coded on the clients and to be given to the miner/validator etherbase, it should instead go to an address decided by an on-chain contract, with hard limits on how it would be issued (six month lock-in; issuance can only decrease or be maintained, but not increase;). A decision method is suggested but not essential to the notion of this EIP. This would **not be a generic governance solution**, which is a much broader and harder topic, would **not** affect technical upgrade decisions or other hard forks, but seen as *a forum to attempt to prevent contentious hard forks* that can be solved with the issuance. ## Summary ### Thesis: many controversial issues boil down to resources @@ -24,7 +24,7 @@ Moving to PoS has been on the roadmap since day 0 for ethereum, along with a red #### Issuance Cap at 120 Million -[EIP 960](https://github.com/ethereum/EIPs/issues/960), Vitalik's not so jokey april's fool has been taken seriously. It proposes the issuance to be slowly reduced until it reaches 120 million ether. One of the main counterpoints by Vlad can be simplified by [we don't know enough to know what that ether can be used for](https://medium.com/@Vlad_Zamfir/against-vitaliks-fixed-supply-eip-eip-960-18e182a7e5bd) and Vitalik's counterpoint is that [reducing emissions can be a way to reduce future abuse of these funds by finding a schelling point at 0](https://medium.com/@VitalikButerin/to-be-clear-im-not-necessarily-wedded-to-a-finite-supply-cap-a7aa48ab880c). Issuance has already been reduced once, from 5 ether to the current 3 ether per block. The main point of a hard cap is that a lot of people consider *not issuing* as having a positive contribution, that can outweight other actions. Burning ether is also a valid issuance decision. +[EIP 960](https://github.com/ethereum/EIPs/issues/960), Vitalik's not so jokey april's fool has been taken seriously. It proposes the issuance to be slowly reduced until it reaches 120 million ether. One of the main counterpoints by Vlad can be simplified by [we don't know enough to know what that ether can be used for](https://medium.com/@Vlad_Zamfir/against-vitaliks-fixed-supply-eip-eip-960-18e182a7e5bd) and Vitalik's counterpoint is that [reducing emissions can be a way to reduce future abuse of these funds by finding a schelling point at 0](https://medium.com/@VitalikButerin/to-be-clear-im-not-necessarily-wedded-to-a-finite-supply-cap-a7aa48ab880c). Issuance has already been reduced once, from 5 ether to the current 3 ether per block. The main point of a hard cap is that a lot of people consider *not issuing* as having a positive contribution, that can outweigh other actions. Burning ether is also a valid issuance decision. #### Asics and advantadges of PoW @@ -52,7 +52,7 @@ It's not meant to be a general governance contract. The contract **should NOT be ##### It cannot only decrease issuance, and once decreased it cannot be increased again -In order to reduce future abuse and uncertainity, **once issuance is reduced, it cannot be increased**. To prevent a single action reducing it to 0, the reduction is limited up to a percentage per time, so if the **decision assembly** is agressively to reduce issuance to zero, it would take a known number of years. +In order to reduce future abuse and uncertainty, **once issuance is reduced, it cannot be increased**. To prevent a single action reducing it to 0, the reduction is limited up to a percentage per time, so if the **decision assembly** is aggressively to reduce issuance to zero, it would take a known number of years. ##### Results are locked for six months @@ -109,7 +109,7 @@ A lot of things are suggested in this EIP, so I would like to propose these ques 1. Do we want to have dynamically changing block rewards, instead of having them be hard coded in the protocol? 2. If the answer above is yes, then what would be the best governance process to decide it, and what sorts of limits would we want that governance contract to have? -3. If the answer is a multi-signalling contract, then what sorts of signals would we want, what sort of relative weight should they have and what would be the proccess to add and remove them? +3. If the answer is a multi-signalling contract, then what sorts of signals would we want, what sort of relative weight should they have and what would be the process to add and remove them? diff --git a/EIPS/eip-1057.md b/EIPS/eip-1057.md index b3b897b9..5ffc0b9f 100644 --- a/EIPS/eip-1057.md +++ b/EIPS/eip-1057.md @@ -15,7 +15,7 @@ A new Proof-of-Work algorithm to replace Ethash that utilizes almost all parts o ## Abstract -ProgPoW is a proof-of-work algorithm designed to close the efficency gap available to specialized ASICs. It utilizes almost all parts of commodity hardware (GPUs), and comes pre-tuned for the most common hardware utilized in the Ethereum network. +ProgPoW is a proof-of-work algorithm designed to close the efficiency gap available to specialized ASICs. It utilizes almost all parts of commodity hardware (GPUs), and comes pre-tuned for the most common hardware utilized in the Ethereum network. ## Motivation @@ -53,7 +53,7 @@ With the growth of large mining pools, the control of hashing power has been del While the goal of “ASIC resistance” is valuable, the entire concept of “ASIC resistance” is a bit of a fallacy. CPUs and GPUs are themselves ASICs. Any algorithm that can run on a commodity ASIC (a CPU or GPU) by definition can have a customized ASIC created for it with slightly less functionality. Some algorithms are intentionally made to be “ASIC friendly” - where an ASIC implementation is drastically more efficient than the same algorithm running on general purpose hardware. The protection that this offers when the coin is unknown also makes it an attractive target for a dedicate mining ASIC company as soon as it becomes useful. -Therefore, ASIC resistance is: the efficiency difference of specilized hardware versus hardware that has a wider adoption and applicability. A smaller efficiency difference between custom vs general hardware mean higher resistance and a better algorithm. This efficiency difference is the proper metric to use when comparing the quality of PoW algorithms. Efficiency could mean absolute performance, performance per watt, or performance per dollar - they are all highly correlated. If a single entity creates and controls an ASIC that is drastically more efficient, they can gain 51% of the network hashrate and possibly stage an attack. +Therefore, ASIC resistance is: the efficiency difference of specialized hardware versus hardware that has a wider adoption and applicability. A smaller efficiency difference between custom vs general hardware mean higher resistance and a better algorithm. This efficiency difference is the proper metric to use when comparing the quality of PoW algorithms. Efficiency could mean absolute performance, performance per watt, or performance per dollar - they are all highly correlated. If a single entity creates and controls an ASIC that is drastically more efficient, they can gain 51% of the network hashrate and possibly stage an attack. ### Review of Existing PoW Algorithms @@ -134,7 +134,7 @@ The random program changes every `PROGPOW_PERIOD` blocks to ensure the hardware Sample code is written in C++, this should be kept in mind when evaluating the code in the specification. -All numerics are computed using unsinged 32 bit integers. Any overflows are trimmed off before proceeding to the next computation. Languages that use numerics not fixed to bit lenghts (such as Python and JavaScript) or that only use signed integers (such as Java) will need to keep their languages' quirks in mind. The extensive use of 32 bit data values aligns with modern GPUs internal data architectures. +All numerics are computed using unsigned 32 bit integers. Any overflows are trimmed off before proceeding to the next computation. Languages that use numerics not fixed to bit lengths (such as Python and JavaScript) or that only use signed integers (such as Java) will need to keep their languages' quirks in mind. The extensive use of 32 bit data values aligns with modern GPUs internal data architectures. ProgPoW uses a 32-bit variant of **FNV1a** for merging data. The existing Ethash uses a similar vaiant of FNV1 for merging, but FNV1a provides better distribution properties. diff --git a/EIPS/eip-1066.md b/EIPS/eip-1066.md index bfb15d1d..c8755a5b 100644 --- a/EIPS/eip-1066.md +++ b/EIPS/eip-1066.md @@ -104,10 +104,10 @@ General codes. These double as bare "reasons", since `0x01 == 1`. | `0x02` | Awaiting Others | | `0x03` | Accepted | | `0x04` | Lower Limit or Insufficient | -| `0x05` | Reciever Action Requested | +| `0x05` | Receiver Action Requested | | `0x06` | Upper Limit | | `0x07` | [reserved] | -| `0x08` | Duplicate, Unnessesary, or Inapplicable | +| `0x08` | Duplicate, Unnecessary, or Inapplicable | | `0x09` | [reserved] | | `0x0A` | [reserved] | | `0x0B` | [reserved] | @@ -130,7 +130,7 @@ Also used for common state machine actions (ex. "stoplight" actions). | `0x15` | Needs Your Permission or Request for Continuation | | `0x16` | Revoked or Banned | | `0x17` | [reserved] | -| `0x18` | Not Applicatable to Current State | +| `0x18` | Not Applicable to Current State | | `0x19` | [reserved] | | `0x1A` | [reserved] | | `0x1B` | [reserved] | @@ -286,7 +286,7 @@ Currently unspecified. (Full range reserved) Actions around signatures, cryptography, signing, and application-level authentication. -The meta code `0xEF` is often used to signal a payload descibing the algorithm or process used. +The meta code `0xEF` is often used to signal a payload describing the algorithm or process used. | Code | Description | |--------|-------------------------------------| @@ -344,7 +344,7 @@ Among other things, the meta code `0xFF` may be used to describe what the off-ch | `0x*5` | `0x05` Receiver Action Required | `0x15` Needs Your Permission or Request for Continuation | `0x25` Request for Match | `0x35` Receiver's Ratification Requested | `0x45` Awaiting Your Availability | `0x55` Funds Requested | `0x65` [reserved] | `0x75` [reserved] | `0x85` [reserved] | `0x95` [reserved] | `0xA5` App-Specific Receiver Action Requested | `0xB5` [reserved] | `0xC5` [reserved] | `0xD5` [reserved] | `0xE5` Signature Required | `0xF5` Off-Chain Action Required | | `0x*6` | `0x06` Upper Limit | `0x16` Revoked or Banned | `0x26` Above Range or Overflow | `0x36` Offer or Vote Limit Reached | `0x46` Expired | `0x56` Transfer Volume Exceeded | `0x66` [reserved] | `0x76` [reserved] | `0x86` [reserved] | `0x96` [reserved] | `0xA6` App-Specific Expiry or Limit | `0xB6` [reserved] | `0xC6` [reserved] | `0xD6` [reserved] | `0xE6` Known to be Compromised | `0xF6` Off-Chain Expiry or Limit Reached | | `0x*7` | `0x07` [reserved] | `0x17` [reserved] | `0x27` [reserved] | `0x37` [reserved] | `0x47` [reserved] | `0x57` [reserved] | `0x67` [reserved] | `0x77` [reserved] | `0x87` [reserved] | `0x97` [reserved] | `0xA7` [reserved] | `0xB7` [reserved] | `0xC7` [reserved] | `0xD7` [reserved] | `0xE7` [reserved] | `0xF7` [reserved] | -| `0x*8` | `0x08` Duplicate, Unnessesary, or Inapplicable | `0x18` Not Applicatable to Current State | `0x28` Duplicate, Conflict, or Collision | `0x38` Already Voted | `0x48` Already Done | `0x58` Funds Not Required | `0x68` [reserved] | `0x78` [reserved] | `0x88` [reserved] | `0x98` [reserved] | `0xA8` App-Specific Inapplicable Condition | `0xB8` [reserved] | `0xC8` [reserved] | `0xD8` [reserved] | `0xE8` Already Signed or Not Encrypted | `0xF8` Duplicate Off-Chain Request | +| `0x*8` | `0x08` Duplicate, Unnecessary, or Inapplicable | `0x18` Not Applicable to Current State | `0x28` Duplicate, Conflict, or Collision | `0x38` Already Voted | `0x48` Already Done | `0x58` Funds Not Required | `0x68` [reserved] | `0x78` [reserved] | `0x88` [reserved] | `0x98` [reserved] | `0xA8` App-Specific Inapplicable Condition | `0xB8` [reserved] | `0xC8` [reserved] | `0xD8` [reserved] | `0xE8` Already Signed or Not Encrypted | `0xF8` Duplicate Off-Chain Request | | `0x*9` | `0x09` [reserved] | `0x19` [reserved] | `0x29` [reserved] | `0x39` [reserved] | `0x49` [reserved] | `0x59` [reserved] | `0x69` [reserved] | `0x79` [reserved] | `0x89` [reserved] | `0x99` [reserved] | `0xA9` [reserved] | `0xB9` [reserved] | `0xC9` [reserved] | `0xD9` [reserved] | `0xE9` [reserved] | `0xF9` [reserved] | | `0x*A` | `0x0A` [reserved] | `0x1A` [reserved] | `0x2A` [reserved] | `0x3A` [reserved] | `0x4A` [reserved] | `0x5A` [reserved] | `0x6A` [reserved] | `0x7A` [reserved] | `0x8A` [reserved] | `0x9A` [reserved] | `0xAA` [reserved] | `0xBA` [reserved] | `0xCA` [reserved] | `0xDA` [reserved] | `0xEA` [reserved] | `0xFA` [reserved] | | `0x*B` | `0x0B` [reserved] | `0x1B` [reserved] | `0x2B` [reserved] | `0x3B` [reserved] | `0x4B` [reserved] | `0x5B` [reserved] | `0x6B` [reserved] | `0x7B` [reserved] | `0x8B` [reserved] | `0x9B` [reserved] | `0xAB` [reserved] | `0xBB` [reserved] | `0xCB` [reserved] | `0xDB` [reserved] | `0xEB` [reserved] | `0xFB` [reserved] | @@ -491,7 +491,7 @@ Alternate schemes include `bytes32` and `uint8`. While these work reasonably wel `uint8` feels even more similar to HTTP status codes, and enums don't require as much casting. However does not break as evenly as a square table (256 doesn't look as nice in base 10). -Packing multiple codes into a single `bytes32` is nice in theory, but poses additional challenges. Unused space may be interpeted as `0x00 Failure`, you can only efficiently pack four codes at once, and there is a challenge in ensuring that code combinations are sensible. Forcing four codes into a packed representation encourages multiple status codes to be returned, which is often more information than strictly necessarily. This can lead to paradoxical results (ex `0x00` and `0x01` together), or greater resorces allocated to interpreting 2564 (4.3 billion) permutations. +Packing multiple codes into a single `bytes32` is nice in theory, but poses additional challenges. Unused space may be interpreted as `0x00 Failure`, you can only efficiently pack four codes at once, and there is a challenge in ensuring that code combinations are sensible. Forcing four codes into a packed representation encourages multiple status codes to be returned, which is often more information than strictly necessarily. This can lead to paradoxical results (ex `0x00` and `0x01` together), or greater resources allocated to interpreting 2564 (4.3 billion) permutations. ### Multiple Returns diff --git a/EIPS/eip-107.md b/EIPS/eip-107.md index 48b13a03..897feb80 100644 --- a/EIPS/eip-107.md +++ b/EIPS/eip-107.md @@ -16,7 +16,7 @@ Every read only rpc call the dapp wants to perform is redirected to an invisible Motivation ========== -Currently, if a user navigates to a dapp running on a website using her/his everyday browser, the dapp will by default have no access to the rpc api for security reasons. The user will have to enable CORS for the website's domain in order for the dapp to work. Unfortunately if the user does so, the dapp will be able to send transactions from any unlocked account without the need for any user consent. In other words, not only does the user need to change the node's default setting, but the user is also forced to trust the dapp in order to use it. This is of course not acceptable and forces existing dapps to rely on the use of workarrounds like: +Currently, if a user navigates to a dapp running on a website using her/his everyday browser, the dapp will by default have no access to the rpc api for security reasons. The user will have to enable CORS for the website's domain in order for the dapp to work. Unfortunately if the user does so, the dapp will be able to send transactions from any unlocked account without the need for any user consent. In other words, not only does the user need to change the node's default setting, but the user is also forced to trust the dapp in order to use it. This is of course not acceptable and forces existing dapps to rely on the use of workarounds like: - if the transaction is a plain ether transfer, the user is asked to enter it in a dedicated trusted wallet like "Mist" - For more complex case, the user is asked to enter the transaction manually via the node command line interface. @@ -50,12 +50,12 @@ In order for the mechanism to work, the node needs to serve an html file via htt This file will then be used by the dapp in 2 different modes (invisible iframe and popup window). -The invisible iframe will be embeded in the dapp to allow the dapp to send its read-only rpc call without having to enable CORS for the dapp's website domain. This is done by sending message to the iframe (via javascript ```window.postMessage```) which in turn execute the rpc call. This works since the iframe and the node share the same domain/port. +The invisible iframe will be embedded in the dapp to allow the dapp to send its read-only rpc call without having to enable CORS for the dapp's website domain. This is done by sending message to the iframe (via javascript ```window.postMessage```) which in turn execute the rpc call. This works since the iframe and the node share the same domain/port. In the iframe mode, the html file's javascript code will ensure that no call requiring an unlocked key can be made. This is to prevent dapps from embedding the invisible iframe and tricking the user into clicking the confirm button. If the dapp requires an ```eth_sendTransaction``` call, the dapp will instead open a new window using the same url. -In this popup window mode, the html file's javascript code will alow ```eth_sendTransaction``` (but not ```eth_sign```, as there is no way to display to the user the meaningful content of the transaction to sign in a safe way) to be called. But instead of sending the call to the node directly, a confirmation dialog will be presented showing the sender and recipient addresses, as well as the amount being transfered along with the potential gas cost. Upon the user approving, the request will be sent and the result returned to the dapp. An error will be returned in case the user cancel the request. +In this popup window mode, the html file's javascript code will allow ```eth_sendTransaction``` (but not ```eth_sign```, as there is no way to display to the user the meaningful content of the transaction to sign in a safe way) to be called. But instead of sending the call to the node directly, a confirmation dialog will be presented showing the sender and recipient addresses, as well as the amount being transferred along with the potential gas cost. Upon the user approving, the request will be sent and the result returned to the dapp. An error will be returned in case the user cancel the request. The html page also checks for the availability of the "personal" api and if so, will ask the user to unlock the account if necessary. The unlocking is temporary (3s) so the password will be asked again if a transaction is attempted before the end of this short time. @@ -75,7 +75,7 @@ Upon receiving such message, the iframe will perform the actual rpc call to the In all the cases, the iframe/window will send a message back to the dapp using the following object: ``` { - id:, + id:, result:, error: } diff --git a/EIPS/eip-1077.md b/EIPS/eip-1077.md index 81ff8f8b..4e7e08fd 100644 --- a/EIPS/eip-1077.md +++ b/EIPS/eip-1077.md @@ -84,7 +84,7 @@ Regardless of which fields you use, in your contract you **must** accept an extr #### Multiple signatures -If multiple signatures are required, then all signed messageHashes should then be *ordered by account* and sent to the receiveing contract which then will execute the following actions: +If multiple signatures are required, then all signed messageHashes should then be *ordered by account* and sent to the receiving contract which then will execute the following actions: #### keep track of nonces: @@ -166,7 +166,7 @@ A function which returns the amount of signatures that are required for a given `event ExecutedSigned(bytes32 signHash, uint nonce, bool success);` -Whenever a new transaction is executed it **must** emit an event with the signHash, nonce and either the transaction was sucessfully executed or not. Apps that are waiting for a transaction to be executed should subscribe to the identity and watch this event to see if their transaction was sucessful. If a different signHash is executed with an equal or higher nonce, it means that your transaction has been replaced. +Whenever a new transaction is executed it **must** emit an event with the signHash, nonce and either the transaction was successfully executed or not. Apps that are waiting for a transaction to be executed should subscribe to the identity and watch this event to see if their transaction was successful. If a different signHash is executed with an equal or higher nonce, it means that your transaction has been replaced. ## Implementation One initial implementation of such a contract can be found at [the Identity Gas Relay at the Status repository](https://github.com/status-im/contracts/blob/73-economic-abstraction/contracts/identity/IdentityGasRelay.sol) diff --git a/EIPS/eip-1078.md b/EIPS/eip-1078.md index f0045666..990d446f 100644 --- a/EIPS/eip-1078.md +++ b/EIPS/eip-1078.md @@ -71,7 +71,7 @@ Here's an example of a EIP681 compatible address to add a public key generated l `ethereum:bob.example.eth?function=addKey(address='0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',uint=1)` -If adding the new key requires multiple signatures, or if the app receiving that request exclusiveky deals with executeable signed messages and has no ether on itself, then it should follow the steps in the next section on how to request transactions. +If adding the new key requires multiple signatures, or if the app receiving that request exclusiveky deals with executable signed messages and has no ether on itself, then it should follow the steps in the next section on how to request transactions. As before, the user shouldn’t be forced to wait for transaction confirmation times. Instead, have an indicator somewhere on the app the shows the progress and then allow the user to interact with your app normally. diff --git a/EIPS/eip-1080.md b/EIPS/eip-1080.md index e5f7a467..18277e8f 100644 --- a/EIPS/eip-1080.md +++ b/EIPS/eip-1080.md @@ -172,7 +172,7 @@ event AccountFrozen(address indexed reported) ## Rationale -* A recoverable token standard can provide configurable saftey for users or contracts who desire this saftey. +* A recoverable token standard can provide configurable safety for users or contracts who desire this safety. * Implementations of this standard will give users the ability to select a dispute resolution process on an opt-in basis and benefit the community by decreasing the necessity of consideration of token recovery actions. diff --git a/EIPS/eip-1081.md b/EIPS/eip-1081.md index d5a7556c..835ecac7 100644 --- a/EIPS/eip-1081.md +++ b/EIPS/eip-1081.md @@ -42,7 +42,7 @@ Optional Functions: - `acceptAndFulfill(address[] _fulfillers, uint[] _numerators, uint _denomenator, string _data, StandardToken[] _payoutTokens, uint[] _tokenAmounts)`: During the course of the development of this standard, we discovered the desire for fulfillers to avoid paying gas fees on their own, entrusting the bounty's `issuer` to make the submission for them, and at the same time accept it. This is useful since it still immutably stores the exchange of tokens for completed work, but avoids the need for new bounty fulfillers to have any ETH to pay for gas costs in advance of their earnings. - `changeMasterCopy(StandardBounty _masterCopy)`: For `issuer`s to be able to change the masterCopy which their proxy contract relies on, if the proxy design pattern is being employed. - `refundableContribute(uint[] _amounts, StandardToken[] _tokens)`: While non-refundable contributions may be sent to a bounty simply by transferring those tokens to the address where it resides, one may also desire to contribute to a bounty with the option to refund their contribution, should the bounty never receive a correct submission which is paid out. -`refundContribution(uint _contributionId)`: If a bounty hasn't yet paid out to any correct submissions and is past it's deadline, those individuals who employed the `refundableContribute` function may retreive their funds from the contract. +`refundContribution(uint _contributionId)`: If a bounty hasn't yet paid out to any correct submissions and is past it's deadline, those individuals who employed the `refundableContribute` function may retrieve their funds from the contract. **Schemas** Persona Schema: diff --git a/EIPS/eip-1108.md b/EIPS/eip-1108.md index b77e50df..792cc908 100644 --- a/EIPS/eip-1108.md +++ b/EIPS/eip-1108.md @@ -75,7 +75,7 @@ Fast elliptic curve cryptography is a keystone of a growing number of protocols * [The AZTEC protocol](https://github.com/AztecProtocol/AZTEC) utilizes the elliptic curve precompiles to construct private tokens, with zero-knowledge transaction logic, via the [ERC1723](https://github.com/ethereum/EIPs/issues/1723) and [ERC1724](https://github.com/ethereum/EIPs/issues/1724) standard. * [Matter Labs](https://github.com/matter-labs/matter-network) utilizes the precompiles to implement Ignis, a scaling solution with a throughput of 500txns per second -* [Rollup](https://github.com/rollup/rollup) utilizes the precompiles to create L2 scaling solutions, where the correctness of transactions is gauranteed by main-net, without an additional consensus layer +* [Rollup](https://github.com/rollup/rollup) utilizes the precompiles to create L2 scaling solutions, where the correctness of transactions is guaranteed by main-net, without an additional consensus layer * [ZEther](https://crypto.stanford.edu/~buenz/papers/zether.pdf) uses precompiles `ECADD` and `ECMUL` to construct confidential transactions These are all technologies that have been, or are in the process of being, deployed to main-net. There protocols would all benefit from reducing the gas cost of the precompiles. diff --git a/EIPS/eip-1109.md b/EIPS/eip-1109.md index 1d80f910..647796a7 100644 --- a/EIPS/eip-1109.md +++ b/EIPS/eip-1109.md @@ -37,7 +37,7 @@ The input stack values are: mu_s[0] = The address of the precompiled smart contract that is called. mu_s[1] = Pointer to memory for the input parameters. -mu_s[2] = Length of the input parametes in bytes. +mu_s[2] = Length of the input parameters in bytes. mu_s[3] = Pointer to memory where the output is stored mu_s[4] = Length of the output buffer. @@ -75,7 +75,7 @@ Old contracts that call precompiled smart contracts with the CALL method, will c - Call to a regular contract - Call to a regular account - Call to 0x0 smart contract (Does not exists). -- Call with large values for the offste pointers and lenghts +- Call with large values for the offste pointers and lengths - Call with the exact gas remaining needed to call smart contract. - Call with the exact gas remaining minus one needed to call smart contract. diff --git a/EIPS/eip-1123.md b/EIPS/eip-1123.md index 11605fcf..aa0cf317 100644 --- a/EIPS/eip-1123.md +++ b/EIPS/eip-1123.md @@ -89,7 +89,7 @@ Guiding Principles This specification makes the following assumptions about the document lifecycle. -1. Package manifests are intended to be generated programatically by +1. Package manifests are intended to be generated programmatically by package management software as part of the release process. 2. Package manifests will be consumed by package managers during tasks diff --git a/EIPS/eip-1154.md b/EIPS/eip-1154.md index a9fedf4d..4e8dc483 100644 --- a/EIPS/eip-1154.md +++ b/EIPS/eip-1154.md @@ -100,7 +100,7 @@ Transaction-wise, both systems are roughly equivalent in efficiency in this scen #### Result Immutability In both the proposed specification and the alternate specification, results are immutable once they are determined. This is due to the expectation that typical consumers will require results to be immutable in order to determine a resulting state consistently. With the proposed push-based system, the consumer enforces the result immutability requirement, whereas in the alternate pull-based system, either the oracle would have to be trusted to implement the spec correctly and enforce the immutability requirement, or the consumer would also have to handle result immutability. -For data which mutates over time, the `id` field may be structured to specify "what" and "when" for the data (using 128 bits to specify "when" is still safe for many millenia). +For data which mutates over time, the `id` field may be structured to specify "what" and "when" for the data (using 128 bits to specify "when" is still safe for many millennia). ## Implementation diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index f7c1de48..bfd1539c 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -67,7 +67,7 @@ interface ERC1155 /* is ERC165 */ { event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values); /** - @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absense of an event assumes disabled). + @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). */ event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); diff --git a/EIPS/eip-1167.md b/EIPS/eip-1167.md index 4b35d046..30154b6a 100644 --- a/EIPS/eip-1167.md +++ b/EIPS/eip-1167.md @@ -22,7 +22,7 @@ By standardizing on a known minimal bytecode redirect implementation, this stand ## Motivation -This standard supports use-cases wherein it is desireable to clone exact contract functionality with a minimum of side effects (e.g. memory slot stomping) and with low gas cost deployment of duplicate proxies. +This standard supports use-cases wherein it is desirable to clone exact contract functionality with a minimum of side effects (e.g. memory slot stomping) and with low gas cost deployment of duplicate proxies. ## Specification diff --git a/EIPS/eip-1186.md b/EIPS/eip-1186.md index 3398e5b5..84f7442d 100644 --- a/EIPS/eip-1186.md +++ b/EIPS/eip-1186.md @@ -124,7 +124,7 @@ This one Method actually returns 3 different important data points: Combining these in one Method allows the client to work very efficient since the required data are already fetched from the db. -### Proofs for non existant values +### Proofs for non existent values In case an address or storage-value does not exist, the proof needs to provide enough data to verify this fact. This means the client needs to follow the path from the root node and deliver until the last matching node. If the last matching node is a branch, the proof value in the node must be an empty one. In case of leaf-type, it must be pointing to a different relative-path in order to proof that the requested path does not exist. diff --git a/EIPS/eip-1193.md b/EIPS/eip-1193.md index 26fd23fb..7398f75d 100644 --- a/EIPS/eip-1193.md +++ b/EIPS/eip-1193.md @@ -47,7 +47,7 @@ All subscriptions from the node emit on "subscription type" (e.g. `eth_subscript ethereum.on('eth_subscription', listener: (result: any) => void): this; ``` -To create a subscription, call `ethereum.send('eth_subscribe')` or `ethereum.send('shh_subscribe')`. The subscription object will emit through the specifc subscription type. +To create a subscription, call `ethereum.send('eth_subscribe')` or `ethereum.send('shh_subscribe')`. The subscription object will emit through the specific subscription type. The result object will look as follows: diff --git a/EIPS/eip-1202.md b/EIPS/eip-1202.md index a114f2e2..a6de062f 100644 --- a/EIPS/eip-1202.md +++ b/EIPS/eip-1202.md @@ -23,7 +23,7 @@ following category: - [Telegram Channel t.me/erc1202](https://t.me/erc1202) for real-time and related random chat. 3. We are actively working on updating this draft as many feedbacks have come in since it merged into official EIP repo. -If you are viewing a snapshot of this draft, please be adviced the latest dev version of ERC 1202 can be found [here](https://github.com/xinbenlv/eip-1202-draft/blob/master/EIP-1202.md) +If you are viewing a snapshot of this draft, please be advised the latest dev version of ERC 1202 can be found [here](https://github.com/xinbenlv/eip-1202-draft/blob/master/EIP-1202.md) ## Simple Summary Propose a standard interface for voting. diff --git a/EIPS/eip-1261.md b/EIPS/eip-1261.md index 5645d025..75dd50da 100644 --- a/EIPS/eip-1261.md +++ b/EIPS/eip-1261.md @@ -106,9 +106,9 @@ interface IERC1261 {/* is ERC173, ERC165 */ /// @notice Requests membership from any address. /// @dev Throws if the `msg.sender` already has the token. - /// The individual `msg.sender` can request for a membership if some exisiting criteria are satisfied. + /// The individual `msg.sender` can request for a membership if some existing criteria are satisfied. /// When a membership is requested, this function emits the RequestedMembership event. - /// dev can store the membership request and use `approveRequest` to assign memebership later + /// dev can store the membership request and use `approveRequest` to assign membership later /// dev can also oraclize the request to assign membership later /// @param _attributeIndexes the attribute data associated with the member. /// This is an array which contains indexes of attributes. diff --git a/EIPS/eip-1271.md b/EIPS/eip-1271.md index 94b8551e..a76c905d 100644 --- a/EIPS/eip-1271.md +++ b/EIPS/eip-1271.md @@ -61,7 +61,7 @@ contract ERC1271 { } ``` -`isValidSignature` can call arbitrary methods to validate a given signature, which could be context dependent (e.g. time based or state based), EOA dependant (e.g. signers authorization level within smart wallet), signature scheme Dependant (e.g. ECDSA, multisig, BLS), etc. +`isValidSignature` can call arbitrary methods to validate a given signature, which could be context dependent (e.g. time based or state based), EOA dependent (e.g. signers authorization level within smart wallet), signature scheme Dependent (e.g. ECDSA, multisig, BLS), etc. diff --git a/EIPS/eip-1283.md b/EIPS/eip-1283.md index 7361bdd8..38df50bc 100644 --- a/EIPS/eip-1283.md +++ b/EIPS/eip-1283.md @@ -286,7 +286,7 @@ When *original value* is not 0, we want to prove that: charge `200 * N` gases, because no disk write is needed. * **Case II**: If the *final value* ends up being zero, we want to charge `5000 - 15000 + 200 * (N-1)` gas. Note that `15000` is the - refund in actual defintion. + refund in actual definition. * **Case III**: If the *final value* ends up being a changed non-zero value, we want to charge `5000 + 200 * (N-1)` gas. diff --git a/EIPS/eip-1380.md b/EIPS/eip-1380.md index 87a29aad..f8476e1f 100644 --- a/EIPS/eip-1380.md +++ b/EIPS/eip-1380.md @@ -25,7 +25,7 @@ Using `JUMP` comes at a considerable cost in complexity to the implementation of must be swapped in and out of the calling functions context. A desired feature is having *pure* functions, which do not modify the state of memory, and realising them through `JUMP` requires a bigger effort from the compiler as opposed to being able to use `CALL`s. -Using call-to-self provides the guarentee that when making an internal call the function can rely on a clear reset state of memory or context, benefiting both +Using call-to-self provides the guarantee that when making an internal call the function can rely on a clear reset state of memory or context, benefiting both contract writers and contract consumers against potentially undetetected edge cases were memory could poison the context of the internal function. Because of the `JUMP` usage for internal functions a smart contract languages are also at risk of reaching the stack depth limit considerbly faster, if nested diff --git a/EIPS/eip-1388.md b/EIPS/eip-1388.md index 84c2f296..6bf1ca4e 100644 --- a/EIPS/eip-1388.md +++ b/EIPS/eip-1388.md @@ -23,7 +23,7 @@ This ERC provides a smart contract interface for anyone to manage a list of atte ### Draft implementation ``` /* The purpose of this contract is to manage the list of attestation - * issuer contracts and their capacity to fulfil requirements + * issuer contracts and their capacity to fulfill requirements */ contract ManagedListERC { diff --git a/EIPS/eip-1417.md b/EIPS/eip-1417.md index 81f11a79..f30735ef 100644 --- a/EIPS/eip-1417.md +++ b/EIPS/eip-1417.md @@ -26,7 +26,7 @@ The following standard allows for the implementation of a standard API for polls We considered the usage of polls with MVTs because MVTs serve as a permissioning mechanism. The manual permissioning of polls allows for vote weightage functions to take up several shapes and forms. Hence the voterbase function applies several logical checks on the vote sender to confirm that they are member(see EIP 1261) of a certain entity or combination of entities. For the specification of the nature of voting, we define the vote weight function. The vote weight function decides how much of vote share each voter will receive and this can be based on several criteria, some of which are listed below in this article. There are certain kinds of polls that enforce certain consequences on the voter, for example a poll may require a voter to lock in a certain amount of tokens, or require the voter to pay a small fee. These on-chain consequences can be coded into the consequence module of the poll standard. Finally, the last module is where the votes are added. A ballot for each candidate is updated whenever relevant, depending on the vote value, and the corresponding NoV count(number of voters). This module is common for most polls, and is the most straightforward. Polls may be time bound, ie. having a finish time, after which no votes are recorded, or be unbound, such that there is no finish time. The following are some examples of specific polls which leverage the flexibility of the poll standard, and it is possible to come up with several others: - Plurality Voting: The simplest form of voting is when you want all eligible voters to have one vote per person. This is the simplest to code, as the vote weight is 1, and there is no vote consequence. The only relevant module here is the voterbase, which can be categorized by one or more MVT contracts. -- Token proportional voting: This kind of a poll is actually possible without the use of a voterbase function, because the vote weight function having token proportionality automatically rules out addresses which dont hold the appropriate ERC - 20/ ERC - 777 token. However the voterbase function may be leveraged to further permission the system and give voting rights only to a fixed subset of token holders. +- Token proportional voting: This kind of a poll is actually possible without the use of a voterbase function, because the vote weight function having token proportionality automatically rules out addresses which don't hold the appropriate ERC - 20/ ERC - 777 token. However the voterbase function may be leveraged to further permission the system and give voting rights only to a fixed subset of token holders. - Capped Token Proportional Voting: This is a modified version of the previous example, where each voter is given proportional vote share only until a certain limit of token ownership. After exceeding that limit, holding more coins does not add more vote share. This format leverages the voterbase module effectively, disallowing people from spreading their coins across multiple addresses by allowing the admin to control which addresses can vote. - Delegated Voting: Certain polls may allow voters to delegate their votes to other voters. This is known as delegated voting or liquid democracy. For such a poll, a complicated vote weight function is needed, and a data structure concerning the voterbase is also required. A consequence of voting here would be that a user cannot delegate, and a consequence of delegating is that a user cannot vote. Sample implementation of polls contains an example of this vote scheme. - Karma Based Voting: A certain form of poll may be based on weightage from digital respect. This digital respect would be like a simple upvote from one member of voterbase to another. A mapping of mappings along with an appropriate vote weight function can serve this purpose. Sample implementation has an example. @@ -46,7 +46,7 @@ This realization happened while conducting market research on DAICOs. The first 2. Permissioning: Permissioning is an important aspect of polls, and is missing in most poll proposals so far, on the blockchain. For some reason, most blockchain based polls seem to consider token holding as the only way to permission a poll. However this hampers flexibility, and hence our poll standard is leveraging EIP 1261 in order to clear the permissioning hurdle. Not only does it allow for more creative poll structures in terms of vote weightage, but even improves the flexibility in permissioning by allowing developers to combine several entities and read attributes from entities. -3. Flexibilty: The vote weight module of the poll standard can be used effectively to design various kinds of poll contracts which function differently and are suited to different environments. Some examples are quadratic voting, karma voting, delegated voting, token based voting, and one person one vote systems. These schemes are possible due to the separation of voterbase creation and vote weight calculation. +3. Flexibility: The vote weight module of the poll standard can be used effectively to design various kinds of poll contracts which function differently and are suited to different environments. Some examples are quadratic voting, karma voting, delegated voting, token based voting, and one person one vote systems. These schemes are possible due to the separation of voterbase creation and vote weight calculation. 4. NoV Counts: Several weighted polls have struggled to provide proper transparency because they only show the final result without enough granularity. This is because they do not store the number of voters that have voted for each proposal, and only store the total accrued vote for each option. EIP 1417 solves this by additionally recording number of voters(NoV) in each proposal. This NoV count is redundant in the case of one person one vote, but elsewhere, it is helpful in figuring out concentration of power. This ensures that malicious parties can be traced to a larger extent. @@ -59,13 +59,13 @@ All that being said, we are very excited to share our proposal with the communit ### Benefits 1. Building applications (pollscan.io) on top of a standardized voting interface enables transparency and encourage more DAO/DAICO's to act responsibly in terms of governance -2. Create Action contracts which take actions programatically based on the result of a poll +2. Create Action contracts which take actions programmatically based on the result of a poll 3. Allow the compatibility with token standard such as [ERC-20](https://eips.ethereum.org/EIPS/eip-20) or (https://eips.ethereum.org/EIPS/eip-777)) and membership standard such as [EIP-1261](https://eips.ethereum.org/EIPS/eip-1261) 4. Flexibility allows for various voting schemes including but not limited to modern schemes such as PLCR Voting ### Use-cases: -Polls are useful in any context of collective decision making, which include but arent limited to: +Polls are useful in any context of collective decision making, which include but aren't limited to: 1. Governing public resources, like ponds, playgrounds, streets etc 2. Maintaining fiscal policy in a transparent consensus driven manner @@ -177,7 +177,7 @@ interface IPoll { /// @return end time as Unix Standard Time function getEndTime() external view returns (uint); - /// @notice retuns the list of entity addresses (eip-1261) used for perimissioning purposes. + /// @notice returns the list of entity addresses (eip-1261) used for perimissioning purposes. /// @dev addresses list can be used along with IERC1261 interface to define the logic inside `canVote()` function /// @return the list of addresses of entities function getProtocolAddresses() external view returns (address[]); @@ -231,7 +231,7 @@ Having explained our rationale, we are looking forward to hearing from the commu **Gas and Complexity** (regarding the enumeration for proposal count) -This specification contemplates implementations that contain a sample of 32 proposals (max upto blockgaslimit). If your application is able to grow and needs more than 32 proposals, then avoid using for/while loops in your code. These indicate your contract may be unable to scale and gas costs will rise over time without bound +This specification contemplates implementations that contain a sample of 32 proposals (max up to blockgaslimit). If your application is able to grow and needs more than 32 proposals, then avoid using for/while loops in your code. These indicate your contract may be unable to scale and gas costs will rise over time without bound **Privacy** diff --git a/EIPS/eip-145.md b/EIPS/eip-145.md index e3cc6591..d0b38cf7 100644 --- a/EIPS/eip-145.md +++ b/EIPS/eip-145.md @@ -18,7 +18,7 @@ Native bitwise shifting instructions are introduced, which are more efficient pr ## Motivation -EVM is lacking bitwise shifting operators, but supports other logical and arithmetic operators. Shift operations can be implemented via arithmetic operators, but that has a higher cost and requires more processing time from the host. Implementing `SHL` and `SHR` using arithmetics cost each 35 gas, while the proposed instructions take 3 gas. +EVM is lacking bitwise shifting operators, but supports other logical and arithmetic operators. Shift operations can be implemented via arithmetic operators, but that has a higher cost and requires more processing time from the host. Implementing `SHL` and `SHR` using arithmetic cost each 35 gas, while the proposed instructions take 3 gas. ## Specification diff --git a/EIPS/eip-1450.md b/EIPS/eip-1450.md index 1eeb1990..ddbb8ba1 100644 --- a/EIPS/eip-1450.md +++ b/EIPS/eip-1450.md @@ -301,7 +301,7 @@ Investors may “lose” their credentials for a number of reasons: they simply If an Investor (or, say, the Investor’s heir) loses their credentials, the Investor must go through a notarized process to notify the RTA of the situation and supply a new Investor address. From there, the RTA can `mint` the “lost” securities to the new Investor address and `burnFrom` the old Investor address (because the RTA knows all Investors’ addresses). ## Rationale -The are currently no token standards that faciliate compliance with SEC regulations. The closest token is [ERC-884 (Delaware General Corporations Law (DGCL) compatible share token)](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-884.md) which states that SEC requirements are out of scope. [EIP-1404 (Simple Restricted Token Standard)](https://github.com/ethereum/EIPs/issues/1404) does not go far enough to address SEC requirements around re-issuing securities to Investors. +The are currently no token standards that facilitate compliance with SEC regulations. The closest token is [ERC-884 (Delaware General Corporations Law (DGCL) compatible share token)](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-884.md) which states that SEC requirements are out of scope. [EIP-1404 (Simple Restricted Token Standard)](https://github.com/ethereum/EIPs/issues/1404) does not go far enough to address SEC requirements around re-issuing securities to Investors. ## Backwards Compatibility `ERC-1450` maintains compatibility with ERC-20 tokens with the following stipulations: diff --git a/EIPS/eip-1462.md b/EIPS/eip-1462.md index f2004d0a..59713317 100644 --- a/EIPS/eip-1462.md +++ b/EIPS/eip-1462.md @@ -83,7 +83,7 @@ Each function must return a status code from the common set of Ethereum status c For both cases, * It is required for guaranteed compatibility with ERC-20 and ERC-777 wallets that each checking function returns `0x11` (Allowed) if not overridden with the issuer's custom logic. -* It is required that all overriden checking functions must revert if the action is not allowed or an error occured, according to the returned status code. +* It is required that all overridden checking functions must revert if the action is not allowed or an error occurred, according to the returned status code. Inside checker functions the logic is allowed to use any feature available on-chain: perform calls to registry contracts with whitelists/blacklists, use built-in checking logic that is defined on the same contract, or even run off-chain queries through an oracle. diff --git a/EIPS/eip-1470.md b/EIPS/eip-1470.md index bda13e61..d6f9dffc 100644 --- a/EIPS/eip-1470.md +++ b/EIPS/eip-1470.md @@ -54,7 +54,7 @@ The SWC in its most basic form links a numeric identifier to a weakness variant. **SWC definition** -A SWC definition is formated in markdown to allow good readability and tools to process them easily. It consists of the following attributes. +A SWC definition is formatted in markdown to allow good readability and tools to process them easily. It consists of the following attributes. - Title: A name for the weakness that points to the technical root cause. - Relationships: Links a CWE _Base_ or _Class_ type to its CWE variant. The _Integer Overflow and Underflow_ variant for example is linked to [CWE-682 - Incorrect Calculation](https://cwe.mitre.org/data/definitions/682.html). diff --git a/EIPS/eip-1484.md b/EIPS/eip-1484.md index 87d43400..ebe60637 100644 --- a/EIPS/eip-1484.md +++ b/EIPS/eip-1484.md @@ -179,7 +179,7 @@ Triggers event: [IdentityCreated](#identitycreated) #### createIdentityDelegated -Preforms the same logic as `createIdentity`, but can be called by any address. This function requires a signature from the `associatedAddress` to ensure their consent. +Performs the same logic as `createIdentity`, but can be called by any address. This function requires a signature from the `associatedAddress` to ensure their consent. ```solidity function createIdentityDelegated( @@ -252,7 +252,7 @@ Triggers event: [ProviderAdded](#provideradded) #### addProvidersFor -Preforms the same logic as `addProviders`, but must be called by a `Provider`. +Performs the same logic as `addProviders`, but must be called by a `Provider`. ```solidity function addProvidersFor(uint ein, address[] memory providers) public; @@ -273,7 +273,7 @@ Triggers event: [ProviderRemoved](#providerremoved) #### removeProvidersFor -Preforms the same logic as `removeProviders`, but is called by a `Provider`. +Performs the same logic as `removeProviders`, but is called by a `Provider`. ```solidity function removeProvidersFor(uint ein, address[] memory providers) public; @@ -294,7 +294,7 @@ Triggers event: [ResolverAdded](#resolveradded) #### addResolversFor -Preforms the same logic as `addResolvers`, but must be called by a `Provider`. +Performs the same logic as `addResolvers`, but must be called by a `Provider`. ```solidity function addResolversFor(uint ein, address[] memory resolvers) public; @@ -314,7 +314,7 @@ Triggers event: [ResolverRemoved](#resolverremoved) #### removeResolversFor -Preforms the same logic as `removeResolvers`, but must be called by a `Provider`. +Performs the same logic as `removeResolvers`, but must be called by a `Provider`. ```solidity function removeResolversFor(uint ein, address[] memory resolvers) public; diff --git a/EIPS/eip-1485.md b/EIPS/eip-1485.md index 716455ca..12040c4a 100644 --- a/EIPS/eip-1485.md +++ b/EIPS/eip-1485.md @@ -97,7 +97,7 @@ In TETHashV1, Adapts fully follow the FNV1A implementation. - TETHASHV1 FNV1A implementation -Followings are reference implementation of FNV1A adapted in TETHashV1. +Following are reference implementation of FNV1A adapted in TETHashV1. ```cpp // Reference Pseudo c/cpp implementation @@ -177,7 +177,7 @@ F(00,10)::VEC(0, 10, ffffffff, 0):: FNV :00000010, DF=0000001f(05) DS(00000 In case of ethash algorithm, it can't prevent ASIC forever. -And, current ethash algorithm's FNV function is depricated. +And, current ethash algorithm's FNV function is deprecated. So, It needs to be upgraded and it will make current ethash based ASICs obsolete. @@ -187,7 +187,7 @@ Another propose of big differencing the Ethash algorithm need to crypto analysis **Verification and Optimization timeline Examples** -orignal ethminer (2015) -> claymore optimized miner (2016) [1year] +original ethminer (2015) -> claymore optimized miner (2016) [1year] genoil ethminer (2015) -> ethereum-mining/ethminer (2017) [2year] diff --git a/EIPS/eip-1491.md b/EIPS/eip-1491.md index 3b9c9a64..66502ef0 100644 --- a/EIPS/eip-1491.md +++ b/EIPS/eip-1491.md @@ -18,7 +18,7 @@ A standard interface for Human Capital Accounting tokens. ## Abstract -The following standard allows for the implementation of a standard API for HUCAP tokens within smart contracts. This standard provides basic functionality to discover, track and transfer the motivational hierarchy of human resources. While blockchain architecture has suceeded in the financialisation of integrity by way of transparency; correspondingly real world outcomes will be proportional to the degree of individualisation of capital by way of knowledge. +The following standard allows for the implementation of a standard API for HUCAP tokens within smart contracts. This standard provides basic functionality to discover, track and transfer the motivational hierarchy of human resources. While blockchain architecture has succeeded in the financialisation of integrity by way of transparency; correspondingly real world outcomes will be proportional to the degree of individualisation of capital by way of knowledge. ## Motivation @@ -425,21 +425,21 @@ interface IERC_HUCAP_KEYSIGNING_EXTENSION { /** /// @notice Cycle through state transition of an Agent in the ecosystem. /// @param _address toggle on/off a doer agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract */ function flipTo(address _address) external onlyOwner returns (IS); /** /// @notice Turn Agent in the ecosystem to on/off. /// @param _address toggle on/off a doer agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract */ function toggle(address _address) external onlyOwner returns (bool); /** /// @notice Set the trust level of an Agent in the ecosystem. /// @param _level toggle on/off a doer agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract */ function trust(Trust _level) returns (bytes32 Trust); @@ -457,66 +457,66 @@ pragma experimental ABIEncoderV2; interface IERC_HUCAP_TRACKUSERS_EXTENSION { - /// @notice Instatiate an Agent in the ecosystem with default data. + /// @notice Instantiate an Agent in the ecosystem with default data. /// @param _address initialise a doer agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function initAgent(Doers _address) external onlyControlled returns (bool); /// @notice Get the data by uuid of an Agent in the ecosystem. /// @param _uuid Get the address of a unique uid - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function getAgent(bytes32 _uuid) view external returns (address); /// @notice Get the data of all Talents in the ecosystem. /// @param _address Query if address belongs to an agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function iam(address _address) view public returns (bool); /// @notice Get the data of all Talents in the ecosystem. /// @param _address Query if address belongs to a doer - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function isDoer(address _address) view public returns (IS); /// @notice Get the number of doers that can be spawned by a Creators. /// The query condition of the contract - // @dev `anybody` can retrive the count data in the contract + // @dev `anybody` can retrieve the count data in the contract function getAgent(address _address) view public returns (bytes32 keyid_, IS state_, bool active_, uint myDoers_); /// @notice Get the data of all Talents in the ecosystem. /// @param _talent The talent whose frequency is being queried - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function getTalents(bytes32 _talent) view external returns (uint talentK_, uint talentI_, uint talentR_, uint talentF_); /// @notice Increment a kind of talent in the ecosystem. /// @param The talent whose frequency is being queried - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function incTalent() payable public onlyDoer returns (bool); /// @notice Decrement a kind of talent in the ecosystem.. /// @param The talent whose frequency is being queried - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function decTalent() payable public onlyDoer returns (bool); /// @notice Set the Public-Key Id of an Agent in the ecosystem. /// @param _address Set the Public-key Id of an agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function setAgent(address _address, bytes32 _keyId) external onlyControlled returns (bytes32); /// @notice Transition the states of an Agent in the ecosystem. /// @param _address Set the stance of an agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function setAgent(address _address, IS _state) external onlyControlled returns (IS); /// @notice Set the active status of an Agent in the ecosystem. /// @param _address Toggle the true/false status of an agent - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function setAgent(address _address, bool _active) external onlyControlled returns (bool); /// @notice Set the data of all Intentions of Agents in the ecosystem. /// @param _serviceId Track number of offers available - // @dev `anybody` can retrive the talent data in the contract + // @dev `anybody` can retrieve the talent data in the contract function setAllPromises(bytes32 _serviceId) external onlyControlled; /* End of interface IERC_HUCAP_TRACKUSERS_EXTENSION */ diff --git a/EIPS/eip-1571.md b/EIPS/eip-1571.md index fedc29b9..942d0e35 100644 --- a/EIPS/eip-1571.md +++ b/EIPS/eip-1571.md @@ -80,7 +80,7 @@ The JSON representation of `request` object is made of these parts: The JSON representation of `response` object is made of these parts: - mandatory `id` member of type Integer : the identifier of the request this response corresponds to - optional `error` member : whether an error occurred during the parsing of the method or during it's execution this member **MUST** be present and valued. If no errors occurred this member **MUST NOT** be present. For a detailed structure of the `error` member see below. -- optional `result` member : This has to be set, if the corresponding request requires a result from the user. If no errors occurred by invoking the corresponding function, this member **MUST** be present even if one or more informations are null. The type can be of Object or single type Array or Primitive string/number. If no data is meant back for the issuer (the method is void on the receiver) or an error occurred this member **MUST NOT** be present. +- optional `result` member : This has to be set, if the corresponding request requires a result from the user. If no errors occurred by invoking the corresponding function, this member **MUST** be present even if one or more information are null. The type can be of Object or single type Array or Primitive string/number. If no data is meant back for the issuer (the method is void on the receiver) or an error occurred this member **MUST NOT** be present. You'll notice here some differences with standard JSON-RPC-2.0. Namely the result member is not always required. Basically a response like this : ```json @@ -141,13 +141,13 @@ Using proper error codes pools may properly inform miners of the condition of th - Error codes 5xx : server could not process the request due to internal errors ### Notifications -A notification message has the very same representation of a `request` with the only difference the `id` member **MUST NOT** be present. This means the issuer is not interested nor expects any reponse to this message. It's up to the receiver to take actions accordingly. For instance the receiver **MAY** decide to execute the method, or, in case of errors or methods not allowed, drop the connection thus closing the session. +A notification message has the very same representation of a `request` with the only difference the `id` member **MUST NOT** be present. This means the issuer is not interested nor expects any response to this message. It's up to the receiver to take actions accordingly. For instance the receiver **MAY** decide to execute the method, or, in case of errors or methods not allowed, drop the connection thus closing the session. #### Error member As seen above a `response` **MAY** contain an `error` member. When present this member **MUST** be an Object with: - mandatory member `code` : a Number which identifies the error occurred - mandatory member `message` : a short human readable sentence describing the error occurred -- optional member `data` : a Structured or Primitive value that contains additional informations about the error. The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.). +- optional member `data` : a Structured or Primitive value that contains additional information about the error. The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.). ## Protocol Flow - Client starts session by opening a TCP socket to the server @@ -373,7 +373,7 @@ At the beginning of each `session` the server **MUST** send this notification be Whenever the server detects that one, or two, or three or four values change within the session, the server will issue a notification with one, or two or three or four members in the `param` object. For this reason on each **new** session the server **MUST** pass all four members. As a consequence the miner is instructed to adapt those values on **next** job which gets notified. The new `algo` member is defined to be prepared for possible presence of algorithm variants to ethash, namely ethash1a or ProgPow. Pools providing multicoin switching will take care to send a new `mining.set` to miners before pushing any job after a switch. -The client wich can't support the data provided in the `mining.set` notification **MAY** close connection or stay idle till new values satisfy it's configuration (see `mining.noop`). +The client which can't support the data provided in the `mining.set` notification **MAY** close connection or stay idle till new values satisfy it's configuration (see `mining.noop`). All client's implementations **MUST** be prepared to accept new extranonces during the session: unlike in EthereumStratum/1.0.0 the optional client advertisement `mining.extranonce.subscribe` is now implicit and mandatory. The miner receiving the `extranonce` **MUST** initialize the search segment for next job resizing the extranonce to a hex of 16 bytes thus appending as many zeroes as needed. @@ -462,7 +462,7 @@ When a miner finds a solution for a job he is mining on it sends a `mining.submi ] } ``` -First element of `params` array is the jobId this solution refers to (as sent in the `mining.notify` message from the server). Second element is the `miner nonce` as hex. Third element is the token given to the worker previous `mining.authorize` request. Any `mining.submit` request bound to a worker which was not succesfully authorized - i.e. the token does not exist in the session - **MUST** be rejected. +First element of `params` array is the jobId this solution refers to (as sent in the `mining.notify` message from the server). Second element is the `miner nonce` as hex. Third element is the token given to the worker previous `mining.authorize` request. Any `mining.submit` request bound to a worker which was not successfully authorized - i.e. the token does not exist in the session - **MUST** be rejected. You'll notice in the sample above the `miner nonce` is only 12 bytes wide (should be 16). Why ? That's because in the previous `mining.set` the server has set an `extranonce` of `af4c`. This means the full nonce is `af4c68765fccd712` @@ -488,7 +488,7 @@ or, in case of any error or condition with a detailed error object Client **should** treat errors as "soft" errors (stales) or "hard" (bad nonce computation, job not found etc.). Errors in 5xx range are server errors and suggest the miner to abandon the connection and switch to a failover. ### Hashrate -Most pools offer statistic informations, in form of graphs or by API calls, about the calculated hashrate expressed by the miner while miners like to compare this data with the hashrate they read on their devices. Communication about parties of these informations have never been coded in Stratum and most pools adopt the method from getWork named `eth_submitHashrate`. +Most pools offer statistic information, in form of graphs or by API calls, about the calculated hashrate expressed by the miner while miners like to compare this data with the hashrate they read on their devices. Communication about parties of these information have never been coded in Stratum and most pools adopt the method from getWork named `eth_submitHashrate`. In this document we propose an official implementation of the `mining.hashrate` request. This method behaves differently when issued from client or from server. #### Client communicates it's hashrate to server. @@ -540,7 +540,7 @@ Optionally the server can **notify** client about it's overall performance (acco } } ``` -Where `params` is an object which holds theese members for values of the **whole session**: +Where `params` is an object which holds these members for values of the **whole session**: - `interval` (number) the width, in minutes, of the observation window. "_in the last x minutes we calculated ..._" - `hr` (hex) representation of the hashrate the pool has calculated for the miner - `accepted` is an array of two number elements : the first is the overall count of accepted shares and the second is the number of stale shares. The array must be interpreted as "total accepted of which x are stale" diff --git a/EIPS/eip-1613.md b/EIPS/eip-1613.md index 7ed7b64c..973e040f 100644 --- a/EIPS/eip-1613.md +++ b/EIPS/eip-1613.md @@ -225,7 +225,7 @@ Scaling such attack would be prohibitively expensive, and actually quite profita ##### Attack: Relay attempts to censor a transaction by signing it, but using a nonce higher than it's current nonce. In this attack, the Relay did create and return a perfectly valid transaction, but it will not be mined until this Relay fills the gap in the nonce with 'missing' transactions. -This may delay the relaying of some transactions indefinately. In order to mitigate that, the sender includes a `max_nonce` parameter with it's signing request. +This may delay the relaying of some transactions indefinitely. In order to mitigate that, the sender includes a `max_nonce` parameter with it's signing request. It is suggested to be higher by 2-3 from current nonce, to allow the relay process several transactions. When the sender receives a transaction signed by a Relay he validates that the nonce used is valid, and if it is not, the client will ignore the given relay and use other relays to relay given transaction. Therefore, there will be no actual delay introduced by such attack. diff --git a/EIPS/eip-1616.md b/EIPS/eip-1616.md index c709dd10..c22cdec2 100644 --- a/EIPS/eip-1616.md +++ b/EIPS/eip-1616.md @@ -25,7 +25,7 @@ This EIP contains the following core ideas: Potential advanced uses of attribute registries include: * Encoding complex boolean expressions which combine multiple attributes into a single uint256 key, which is then parsed and evaluated by the registry logic. * Using values associated with an attribute to query additional on-chain or off-chain metadata. -* Resolving attribute values by calling into seperate attribute registries or other contracts, delegating authority without changing the interface of the registry. +* Resolving attribute values by calling into separate attribute registries or other contracts, delegating authority without changing the interface of the registry. ## Motivation @@ -213,7 +213,7 @@ contract AttributeRegistry is AttributeRegistryInterface { mapping(address => mapping(uint256 => uint256)) private _issuedAttributeValues; /** - * @notice The constructor function, defines the two attribute types avaiable + * @notice The constructor function, defines the two attribute types available * on this particular registry. */ constructor() public { diff --git a/EIPS/eip-162.md b/EIPS/eip-162.md index 60cec465..d1936bd6 100644 --- a/EIPS/eip-162.md +++ b/EIPS/eip-162.md @@ -135,7 +135,7 @@ The following table outlines what portion of the balance held in a deed contract ### Deployment and Upgrade process -The Initial Registrar requires the ENS's address as a contructor, and should be deployed after the ENS. The multisig account owning the root node in the ENS should then set the Initial Registrar's address as owner of the `eth` node. +The Initial Registrar requires the ENS's address as a constructor, and should be deployed after the ENS. The multisig account owning the root node in the ENS should then set the Initial Registrar's address as owner of the `eth` node. The Initial Registrar is expected to be replaced by a Permanent Registrar approximately 2 years after deployment. The following process should be used for the upgrade: 1. The Permanent Registrar contract will be deployed. diff --git a/EIPS/eip-165.md b/EIPS/eip-165.md index 5d333aab..e71e96e0 100644 --- a/EIPS/eip-165.md +++ b/EIPS/eip-165.md @@ -144,7 +144,7 @@ contract ERC165Query { assembly { let x := mload(0x40) // Find empty storage location using "free memory pointer" - mstore(x, erc165ID) // Place signature at begining of empty storage + mstore(x, erc165ID) // Place signature at beginning of empty storage mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature success := staticcall( diff --git a/EIPS/eip-1681.md b/EIPS/eip-1681.md index 2e557f28..28c6b2fc 100644 --- a/EIPS/eip-1681.md +++ b/EIPS/eip-1681.md @@ -51,7 +51,7 @@ For the dust-account clearing usecase, - Other schemas which uses the `nonce` can have unintended side-effects, - such as inability to create contracts at certain addresses. - more difficult to integrate with offline signers, since more elaborate nonce-schemes requires state access to determine. - - More intricate schemes like `highest-nonce` are a lot more difficult, since highest-known-nonce will be a consensus-struct that is incremented and possibly reverted during transaction execution, requireing one more journalled field. + - More intricate schemes like `highest-nonce` are a lot more difficult, since highest-known-nonce will be a consensus-struct that is incremented and possibly reverted during transaction execution, requiring one more journalled field. ### Rationale for walltime diff --git a/EIPS/eip-1702.md b/EIPS/eip-1702.md index 1dc088d2..e6096ee5 100644 --- a/EIPS/eip-1702.md +++ b/EIPS/eip-1702.md @@ -171,7 +171,7 @@ change how current contracts are executed. ### Performance Currently nearly all full node implementations uses config parameters -to decide which virtual machine version to use. Switching vitual +to decide which virtual machine version to use. Switching virtual machine version is simply an operation that changes a pointer using a different set of config parameters. As a result, this scheme has nearly zero impact to performance. diff --git a/EIPS/eip-1775.md b/EIPS/eip-1775.md index 1c623887..8aa74721 100644 --- a/EIPS/eip-1775.md +++ b/EIPS/eip-1775.md @@ -16,7 +16,7 @@ requires: 137 Among others cryptographic applications, scalability and privacy solutions for ethereum blockchain require that an user performs a significant amount of signing operations. It may also require her to watch some state and be ready to sign data automatically (e.g. sign a state or contest a withdraw). The way wallets currently implement accounts poses several obstacles to the development of a complete web3.0 experience both in terms of UX, security and privacy. -This proposal describes a standard and api for a new type of wallet accounts that are derived specifically for a each given application. We propose to call them `app keys`. They allow to isolate the accounts used for each application, thus potentially increasing privacy. They also allow to give more control to the applications developpers over account management and signing delegation. For these app keys, wallets can have a more permissive level of security (e.g. not requesting user's confirmation) while keeping main accounts secure. Finally wallets can also implement a different behavior such as allowing to sign transactions without broadcasting them. +This proposal describes a standard and api for a new type of wallet accounts that are derived specifically for a each given application. We propose to call them `app keys`. They allow to isolate the accounts used for each application, thus potentially increasing privacy. They also allow to give more control to the applications developers over account management and signing delegation. For these app keys, wallets can have a more permissive level of security (e.g. not requesting user's confirmation) while keeping main accounts secure. Finally wallets can also implement a different behavior such as allowing to sign transactions without broadcasting them. This new accounts type can allow to significantly improve UX and permit new designs for applications of the crypto permissionned web. @@ -26,7 +26,7 @@ In a wallet, an user often holds most of her funds in her main accounts. These a We introduce here a new account type, app keys, which permits signing delegation and accounts isolation across applications for privacy and security. -In this EIP, we provide a proposal on how to uniquely identify and authenticate each application, how to derive the accounts along an Hierachical Deterministic (HD) path restricted for the domain and we finally define an API for applications to derive and use these app keys. This ERC aims at finding a standard that will fit the needs of wallets and application developers while also allowing app keys to be used across wallets and yield the same accounts for the user for each application. +In this EIP, we provide a proposal on how to uniquely identify and authenticate each application, how to derive the accounts along an Hierarchical Deterministic (HD) path restricted for the domain and we finally define an API for applications to derive and use these app keys. This ERC aims at finding a standard that will fit the needs of wallets and application developers while also allowing app keys to be used across wallets and yield the same accounts for the user for each application. ## Motivation @@ -86,7 +86,7 @@ However, there may be benefits to use only one depth instead of 3. We could use ### Personas -We allow the user to use different personas in combination to her mnemonic to potentially fully isolate her interaction with a given app accross personas. One can use this for instance to create a personal and business profile for a given's domain both backup up from the same mnemonic, using 2 different personnas indexes. The app or domain, will not be aware that it is the same person and mnemonic behind both. +We allow the user to use different personas in combination to her mnemonic to potentially fully isolate her interaction with a given app across personas. One can use this for instance to create a personal and business profile for a given's domain both backup up from the same mnemonic, using 2 different personnas indexes. The app or domain, will not be aware that it is the same person and mnemonic behind both. We use a string following BIP32 format (can be hardened) to define personas. The indexes should be hex under 0x80000000, 31 bits. @@ -105,7 +105,7 @@ There are a few restrictions however on the characters used and normalisation, e In addition there must be a maximum size to the domain string that we need to determine such that the mapping from strings to nodes remains injective, to avoid collision. -We recommend this standard to be following the [ENS Specs](http://docs.ens.domains/en/latest/implementers.html#namehash), reproduced below for convinience and reference. +We recommend this standard to be following the [ENS Specs](http://docs.ens.domains/en/latest/implementers.html#namehash), reproduced below for convenience and reference. ``` Normalising and validating names @@ -239,9 +239,9 @@ and converted to uints ``` -* Second approach favors an homogenous decomposition: +* Second approach favors an homogeneous decomposition: -Equal lenght indexes would be 16 * 16 bits or in other words 16 * 2 bytes, cleanest and favored spec: +Equal length indexes would be 16 * 16 bits or in other words 16 * 2 bytes, cleanest and favored spec: ``` x = x0 || x1 || x2 || x3 || x4 || x5 || x6 || x7 || x8 || x9 || x10 || x11 || x12 || x13 || x14 || x15 @@ -270,7 +270,7 @@ Finally, the last part of the hd path is under the application's control. This w We consider that a given child on the HD tree should be called an `account` and not an `address` since it is composed of a private key, a public key and an address. Similarly to the persona path, this sub path must follow bip32, with hex under 0x80000000, 31 bits. -It can be hardened depending on each application's needs and can be writen as hex or unsigned integers. +It can be hardened depending on each application's needs and can be written as hex or unsigned integers. It can include a large number of indexes. Q [Should we set a limit on the persona and application customsable hd path number of indexes?] @@ -299,7 +299,7 @@ We propose to introduce new RPC methods but they should be restricted and wrappe * `wallet.appkey.enable(options)` This method allows to enable app keys (getting user permission to use and allow him to select the persona she would like to use). -[TBD] Could return the account public key from the HD path before `the app's custom subPath`. Hence from this app's root account, one could derive all non hardened childs public keys of the app's keys. +[TBD] Could return the account public key from the HD path before `the app's custom subPath`. Hence from this app's root account, one could derive all non hardened children public keys of the app's keys. [TBD] where `options` is a javascript object containing the permissions requested for these app keys. Options could also include a challenge to be signed by the app's root account (would serve as authentication of the users from the app's perspective). The signature should then be also returned. @@ -390,7 +390,7 @@ If there is a strong demand, we could add a method that exposes the private keys We indeed think that writing applications that don't need to manipulate the user private keys is a better pattern. For instance, if one needs the user to sign data while being offline, one should for instance rather implement a delegation method to an external application's controlled account rather than storing the user private key on a server that stays online. -### Persona isolation accross applications for privacy +### Persona isolation across applications for privacy The persona path is set by the user-wallet interaction and known only by them. There is thus a strict isolation between 2 different persona subpaths as if they were generated by different mnemonics. @@ -417,13 +417,13 @@ For the persona specification this may not be possible, unless we impose some st ### Hardened and non-hardened indexes: privacy and functionality -Hardening allows to increase privacy. If the extended public key of a parent level in the HD tree is known, public keys of its childs can not be computed if they are hardened. On the contrary if the child indexes are not hardened one can enumerate the child public keys and use that for the application design or to easily restore a wallet and it increases functionality. +Hardening allows to increase privacy. If the extended public key of a parent level in the HD tree is known, public keys of its children can not be computed if they are hardened. On the contrary if the child indexes are not hardened one can enumerate the child public keys and use that for the application design or to easily restore a wallet and it increases functionality. For the first parts of the HD tree, we need isolation and privacy. Thus we use hardened indexes for the persona and application paths in case some extended public key leaks at some previous level of the tree, it would protect the sub trees (of course this has no impact if private keys leak). For instance if we don't harden the application path, in case a persona public key is known and the application subpath does not use hardening either, one could get all `app keys` public keys for every application for this persona. -However the app can use non hardened indexes in their custom path part to be able to benefit from guessing child public keys from parent one (for instance for counterfactual state channel interaction accross 2 peers that would like to use new keys every time they counterfactually instantiate a new sub app). +However the app can use non hardened indexes in their custom path part to be able to benefit from guessing child public keys from parent one (for instance for counterfactual state channel interaction across 2 peers that would like to use new keys every time they counterfactually instantiate a new sub app). ### Alternatives for the HD derivation path @@ -478,7 +478,7 @@ We think our approach while also being more englobing benefits from not requirin #### Shortening the Hash node -Our current approach uses identification through an ENS name converted to a hash node and sliced fully but one could potentially keep only the first 16 bytes of the node for instance and slice them similarly. This may increase the chance of app collision but we probably can reduce the lenght while retaining an injective mapping from strings to hashes. +Our current approach uses identification through an ENS name converted to a hash node and sliced fully but one could potentially keep only the first 16 bytes of the node for instance and slice them similarly. This may increase the chance of app collision but we probably can reduce the length while retaining an injective mapping from strings to hashes. #### Alternative application identification specification @@ -509,18 +509,18 @@ Another alternative could be to use the plain website url and get rid of ens alt For authentication we use DNS and ENS resolution, and browsing to a given url resolved. A few comments on this: A few comments in case of ENS resolution: -* First connection requires the wallet to connect to ethereum mainnet, but once first resolution is done we could use some metadata paramater such as `author address` for a blockchain less authentication of the application (e.g. application server signs a challenge message with the author address resolved in the ENS metadata). +* First connection requires the wallet to connect to ethereum mainnet, but once first resolution is done we could use some metadata parameter such as `author address` for a blockchain less authentication of the application (e.g. application server signs a challenge message with the author address resolved in the ENS metadata). * The url the name resolves to through ENS can change without the user knowing and then a different application/website may be granted access to his app keys. But this means the ENS name owner address was copromised. This would be similar to using a signing challenge authentified by a known public key. If this known public key is compromised we have a similar problem. * Homoglyph attacks are not a bigger problem for `app keys` than it is for ENS since it will not grant access to `app keys` from the real domain (they would be derived along a different path). However homoglyph applications may lure the user to send funds from her main account to an `app key` of a malicious homoglyphic domain. Other metadata resolution through ENS that can be used alongside: -* `author address`: already mentionned above +* `author address`: already mentioned above * `contract address`: For app keys that would be designed to interact with a given ethereum contract (for instance app keys for a given token, if one desires to do so), other metadata fields could be used such as contract addresses. * [TBD] -In relation to the SLIP13 proposal mentionned above, one could think of alternative specifications that would use some certificate for authentication similar to https. +In relation to the SLIP13 proposal mentioned above, one could think of alternative specifications that would use some certificate for authentication similar to https. ### An Account gap limit standard for application controlled hd sub-path? diff --git a/EIPS/eip-1895.md b/EIPS/eip-1895.md index 4067b3a5..5c097b75 100644 --- a/EIPS/eip-1895.md +++ b/EIPS/eip-1895.md @@ -132,7 +132,7 @@ In the EVM the compressed form allows us to represents curve points with 2 uint2 ## Rationale -The curve has 80 bits of security (whereas MNT6 has 120 bits) which might not be considered enough for critical security level, (for instance transfering several billions), but enough for others. If it turns out this is not enough security for adoption, there is another option : another cycle is being used by Coda but is defined over a 753 bits sized field which might also be prohibitively low (no reference to this curve from Coda's publications found). +The curve has 80 bits of security (whereas MNT6 has 120 bits) which might not be considered enough for critical security level, (for instance transferring several billions), but enough for others. If it turns out this is not enough security for adoption, there is another option : another cycle is being used by Coda but is defined over a 753 bits sized field which might also be prohibitively low (no reference to this curve from Coda's publications found). Independently of the cycle chosen, the groups and field elements are represented with integers larger than 256 bits (even for the 80 bits of security), therefore it might be necessary to also add support for larger field size operations. diff --git a/EIPS/eip-1922.md b/EIPS/eip-1922.md index 9742dd36..e0f9d76a 100644 --- a/EIPS/eip-1922.md +++ b/EIPS/eip-1922.md @@ -89,7 +89,7 @@ interface ERC165 { ⚠️ TODO: Add a specific reference to libsnark here, explaining the choice of variable names. -:warning: TODO: Explain how _C_ may not necessarilly be a satisfiable arithmetic circuit of logical statements. As current, this is a limitation to certain kinds of SNARKS. Whereas the source references also mention polynomials, and other applications. +:warning: TODO: Explain how _C_ may not necessarily be a satisfiable arithmetic circuit of logical statements. As current, this is a limitation to certain kinds of SNARKS. Whereas the source references also mention polynomials, and other applications. _C_ — A satisfiable arithmetic circuit abstraction of logical statements. diff --git a/EIPS/eip-1930.md b/EIPS/eip-1930.md index 7452c7ff..abf1456c 100644 --- a/EIPS/eip-1930.md +++ b/EIPS/eip-1930.md @@ -54,20 +54,20 @@ if !callCost.IsUint64() || gas < callCost.Uint64() { ### Rationale -Currenlty the gas specified as part of these opcodes is simply a maximum value. And due to the behavior of [EIP-150](http://eips.ethereum.org/EIPS/eip-150) it is possible for an external call to be given less gas than intended (less than the gas specified as part of the CALL) while the rest of the current call is given enough to continue and succeed. Indeed since with EIP-150, the external call is given at max ```G - Math.floor(G/64)``` where G is the gasleft() at the point of the CALL, the rest of the current call is given ```Math.floor(G/64)``` which can be plenty enough for the transaction to succeed. For example, when G = 6,400,000 the rest of the transaction will be given 100,000 gas plenty enough in many case to succeed. +Currently the gas specified as part of these opcodes is simply a maximum value. And due to the behavior of [EIP-150](http://eips.ethereum.org/EIPS/eip-150) it is possible for an external call to be given less gas than intended (less than the gas specified as part of the CALL) while the rest of the current call is given enough to continue and succeed. Indeed since with EIP-150, the external call is given at max ```G - Math.floor(G/64)``` where G is the gasleft() at the point of the CALL, the rest of the current call is given ```Math.floor(G/64)``` which can be plenty enough for the transaction to succeed. For example, when G = 6,400,000 the rest of the transaction will be given 100,000 gas plenty enough in many case to succeed. This is an issue for contracts that require external call to only fails if they would fails with enough gas. This requirement is present in smart contract wallet and meta transaction in general, where the one executing the transaction is not the signer of the execution data. Because in such case, the contract needs to ensure the call is executed exactly as the signing user intended. But this is also true for simple use case, like checking if a contract implement an interface via EIP-165. Indeed as specified by such EIP, the ```supporstInterface``` method is bounded to use 30,000 gas so that it is theorically possible to ensure that the throw is not a result of a lack of gas. Unfortunately due to how the different CALL opcodes behave contracts can't simply rely on the gas value specified. They have to ensure by other means that there is enough gas for the call. -Indeed, if the caller do not ensure that 30,000 gas or more is provided to the callee, the callee might throw because of a lack of gas (and not because it does not support the interace), and the parent call will be given up to 476 gas to continue. This would result in the caller interepreting wrongly that the callee is not implementing the interface in question. +Indeed, if the caller do not ensure that 30,000 gas or more is provided to the callee, the callee might throw because of a lack of gas (and not because it does not support the interface), and the parent call will be given up to 476 gas to continue. This would result in the caller interepreting wrongly that the callee is not implementing the interface in question. While such requirement can be enforced by checking the gas left according to EIP-150 and the precise gas required before the call (see solution presented in that [bug report](https://web.solidified.io/contract/5b4769b1e6c0d80014f3ea4e/bug/5c83d86ac2dd6600116381f9) or after the call (see the native meta transaction implementation [here](https://github.com/pixowl/thesandbox-contracts/blob/623f4d4ca10644dcee145bcbd9296579a1543d3d/src/Sand/erc20/ERC20MetaTxExtension.sol#L176), it would be much better if the EVM allowed us to strictly specify how much gas is to be given to the CALL so contract implementations do not need to follow [EIP-150](http://eips.ethereum.org/EIPS/eip-150) behavior and the current gas pricing so closely. This would also allow the behaviour of [EIP-150](http://eips.ethereum.org/EIPS/eip-150) to be changed without having to affect contract that require this strict gas behaviour. As mentioned, such strict gas behaviour is important for smart contract wallet and meta transaction in general. -The issue is actually already a problem in the wild as can be seen in the case of Gnosis safe which did not consider the behavior of EIP-150 and thus fails to check the gas properly, requiring the safe owners to add otherwise unecessary extra gas to their signed message to avoid the possibility of losing funds. See https://github.com/gnosis/safe-contracts/issues/100 +The issue is actually already a problem in the wild as can be seen in the case of Gnosis safe which did not consider the behavior of EIP-150 and thus fails to check the gas properly, requiring the safe owners to add otherwise unnecessary extra gas to their signed message to avoid the possibility of losing funds. See https://github.com/gnosis/safe-contracts/issues/100 As for EIP-165, the issue already exists in the example implementation presented in the EIP. Please see the details of the issue [here](https://github.com/ethereum/EIPs/pull/881#issuecomment-491677748) @@ -85,7 +85,7 @@ uint256 gasAvailable = gasleft() - E; require(gasAvailable - gasAvailable / 64 >= `txGas`, "not enough gas provided") to.call.gas(txGas)(data); // CALL ``` -where E is the gas required for the operation beteen the call to ```gasleft()``` and the actual call PLUS the gas cost of the call itself. +where E is the gas required for the operation between the call to ```gasleft()``` and the actual call PLUS the gas cost of the call itself. While it is possible to simply over estimate ```E``` to prevent call to be executed if not enough gas is provided to the current call it would be better to have the EVM do the precise work itself. As gas pricing continue to evolve, this is important to have a mechanism to ensure a specific amount of gas is passed to the call so such mechanism can be used without having to relies on a specific gas pricing. diff --git a/EIPS/eip-1973.md b/EIPS/eip-1973.md index ed108da1..64c7a9cf 100644 --- a/EIPS/eip-1973.md +++ b/EIPS/eip-1973.md @@ -29,7 +29,7 @@ A pull system is required to keep the application completely decentralized and t `token amount per participant in the ecosytem or TPP (token per participant)`: TPP = (token amount to mint / total active participants) - `roundMask`: the cummulative snapshot of TPP over time for the token contract. E.g. transactionOne = 10 tokens are minted with 100 available participants (TPP = 10 / 100) , transactionTwo = 12 tokens are minted with 95 participants (TPP = 12 / 95 ) + `roundMask`: the cumulative snapshot of TPP over time for the token contract. E.g. transactionOne = 10 tokens are minted with 100 available participants (TPP = 10 / 100) , transactionTwo = 12 tokens are minted with 95 participants (TPP = 12 / 95 ) roundMask = (10/100) + (12/95) @@ -39,7 +39,7 @@ A pull system is required to keep the application completely decentralized and t `rewards for msg.sender`: roundMask - participantMask - E.g. Let's assume a total of 6 transactions (smart contract triggers or functions calls) are in place with 10 exising participants (denominator) and 20 tokens (numerator) are minted per transaction. At 2nd transaction, the 11th participant joins the network and exits before 5th transaction, the 11th participant's balance is as follows: + E.g. Let's assume a total of 6 transactions (smart contract triggers or functions calls) are in place with 10 existing participants (denominator) and 20 tokens (numerator) are minted per transaction. At 2nd transaction, the 11th participant joins the network and exits before 5th transaction, the 11th participant's balance is as follows: ``` t1 roundMask = (20/10) @@ -52,7 +52,7 @@ A pull system is required to keep the application completely decentralized and t Total tokens released in 6 transactions = 60 tokens - As the participant joins at t2 and leaves before t5, the participant deserves the rewards between t2 and t4. When the participant joins at t2, the 'participantMask = (20/10)', when the participant leaves before t5, the cummulative deserved reward tokens are : + As the participant joins at t2 and leaves before t5, the participant deserves the rewards between t2 and t4. When the participant joins at t2, the 'participantMask = (20/10)', when the participant leaves before t5, the cumulative deserved reward tokens are : rewards for msg.sender: `[t4 roundMask = (20/10) + (20/11)+ (20/11) + (20/11)] - [participantMask = (20/10)] = [rewards = (20/11)+ (20/11) + (20/11)]` @@ -89,7 +89,7 @@ address public tokencontractAddress = address(this); mapping(address => uint256) public participantMask; /** - * @dev constructor, initilizes variables. + * @dev constructor, initializes variables. * @param _tokensPerBlock The amount of token that will be released per block, entered in wei format (E.g. 1000000000000000000) * @param _blockFreezeInterval The amount of blocks that need to pass (E.g. 1, 10, 100) before more tokens are brought into the ecosystem. */ diff --git a/EIPS/eip-210.md b/EIPS/eip-210.md index 859991c1..abba50af 100644 --- a/EIPS/eip-210.md +++ b/EIPS/eip-210.md @@ -83,4 +83,4 @@ The EVM bytecode that the contract code should be set to is: ### Rationale -This removes the need for implementaitons to have an explicit way to look into historical block hashes, simplifying the protocol definition and removing a large component of the "implied state" (information that is technically state but is not part of the state tree) and thereby making the protocol more "pure". Additionally, it allows blocks to directly point to blocks far behind them, which enables extremely efficient and secure light client protocols. +This removes the need for implementations to have an explicit way to look into historical block hashes, simplifying the protocol definition and removing a large component of the "implied state" (information that is technically state but is not part of the state tree) and thereby making the protocol more "pure". Additionally, it allows blocks to directly point to blocks far behind them, which enables extremely efficient and secure light client protocols. diff --git a/EIPS/eip-3.md b/EIPS/eip-3.md index 63378516..621b1435 100644 --- a/EIPS/eip-3.md +++ b/EIPS/eip-3.md @@ -16,11 +16,11 @@ This is a proposal to add a new opcode, `CALLDEPTH`. The `CALLDEPTH` opcode woul There is a limit specifying how deep contracts can call other contracts; the call stack. The limit is currently `256`. If a contract invokes another contract (either via `CALL` or `CALLCODE`), the operation will fail if the call stack depth limit has been reached. -This behaviour makes it possible to subject a contract to a "call stack attack" [1]. In such an attack, an attacker first creates a suitable depth of the stack, e.g. by recursive calls. After this step, the attacker invokes the targeted contract. If the targeted calls another contract, that call will fail. If the return value is not properly checked to see if the call was successfull, the consequences could be damaging. +This behaviour makes it possible to subject a contract to a "call stack attack" [1]. In such an attack, an attacker first creates a suitable depth of the stack, e.g. by recursive calls. After this step, the attacker invokes the targeted contract. If the targeted calls another contract, that call will fail. If the return value is not properly checked to see if the call was successful, the consequences could be damaging. Example: -1. Contract `A` want's to be invoked regularly, and pays Ether to the invoker in every block. +1. Contract `A` wants to be invoked regularly, and pays Ether to the invoker in every block. 2. When contract `A` is invoked, it calls contracts `B` and `C`, which consumes a lot of gas. After invocation, contract `A` pays Ether to the caller. 3. Malicious user `X` ensures that the stack depth is shallow before invoking A. Both calls to `B` and `C` fail, but `X` can still collect the reward. diff --git a/EIPS/eip-5.md b/EIPS/eip-5.md index dfde87b3..bb47fbe6 100644 --- a/EIPS/eip-5.md +++ b/EIPS/eip-5.md @@ -108,7 +108,7 @@ The change in semantics affects existing contracts in two ways: all be written in a way, though, such that objects in memory are _relocatable_, i.e. their absolute position in memory and their relative position to other objects does not matter. This is of course not the case for arrays, but they - are allocated in a single allocation and not with an intermidiate `CALL`. + are allocated in a single allocation and not with an intermediate `CALL`. ### Implementation diff --git a/EIPS/eip-615.md b/EIPS/eip-615.md index b584498d..d9d2b203 100644 --- a/EIPS/eip-615.md +++ b/EIPS/eip-615.md @@ -390,7 +390,7 @@ Note that code like this is already run by EVMs to check dynamic jumps, includin #### Subroutine Validation -This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertexes and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`: The sum of the number of edges and number of verticies in the graph. +This function can be seen as a symbolic execution of a subroutine in the EVM code, where only the effect of the instructions on the state being validated is computed. Thus the structure of this function is very similar to an EVM interpreter. This function can also be seen as an acyclic traversal of the directed graph formed by taking instructions as vertices and sequential and branching connections as edges, checking conditions along the way. The traversal is accomplished via recursion, and cycles are broken by returning when a vertex which has already been visited is reached. The time complexity of this traversal is `O(|E|+|V|)`: The sum of the number of edges and number of vertices in the graph. The basic approach is to call `validate_subroutine(i, 0, 0)`, for `i` equal to the first instruction in the EVM code through each `BEGINDATA` offset. `validate_subroutine()` traverses instructions sequentially, recursing when `JUMP` and `JUMPI` instructions are encountered. When a destination is reached that has been visited before it returns, thus breaking cycles. It returns true if the subroutine is valid, false otherwise. diff --git a/EIPS/eip-627.md b/EIPS/eip-627.md index 0fe174ea..00f0133b 100644 --- a/EIPS/eip-627.md +++ b/EIPS/eip-627.md @@ -66,7 +66,7 @@ This packet is used for sending the standard Whisper envelopes. This packet contains two objects: integer message code (0x02) followed by a single floating point value of PoW. This value is the IEEE 754 binary representation of 64-bit floating point number. Values of qNAN, sNAN, INF and -INF are not allowed. Negative values are also not allowed. -This packet is used by Whisper nodes for dynamic adjustment of their individual PoW requirements. Receipient of this message should no longer deliver the sender messages with PoW lower than specified in this message. +This packet is used by Whisper nodes for dynamic adjustment of their individual PoW requirements. Recipient of this message should no longer deliver the sender messages with PoW lower than specified in this message. PoW is defined as average number of iterations, required to find the current BestBit (the number of leading zero bits in the hash), divided by message size and TTL: @@ -165,7 +165,7 @@ Symmetric encryption uses AES GCM algorithm with random 96-bit nonce. Packet codes 0x00 and 0x01 are already used in all Whisper versions. -Packet code 0x02 will be necessary for the future developement of Whisper. It will provide possiblitity to adjust the PoW requirement in real time. It is better to allow the network to govern itself, rather than hardcode any specific value for minimal PoW requirement. +Packet code 0x02 will be necessary for the future development of Whisper. It will provide possiblitity to adjust the PoW requirement in real time. It is better to allow the network to govern itself, rather than hardcode any specific value for minimal PoW requirement. Packet code 0x03 will be necessary for scalability of the network. In case of too much traffic, the nodes will be able to request and receive only the messages they are interested in. diff --git a/EIPS/eip-706.md b/EIPS/eip-706.md index e1f60125..4211c23b 100644 --- a/EIPS/eip-706.md +++ b/EIPS/eip-706.md @@ -16,7 +16,7 @@ This EIP proposes a tiny extension to the DEVp2p protocol to enable [Snappy comp ## Motivation Synchronizing the Ethereum main network (block 4,248,000) in Geth using fast sync currently consumes 1.01GB upload and 33.59GB download bandwidth. On the Rinkeby test network (block 852,000) it's 55.89MB upload and 2.51GB download. -However, most of this data (blocks, transactions) are heavily compressable. By enabling compression at the message payload level, we can reduce the previous numbers to 1.01GB upload / 13.46GB download on the main network, and 46.21MB upload / 463.65MB download on the test network. +However, most of this data (blocks, transactions) are heavily compressible. By enabling compression at the message payload level, we can reduce the previous numbers to 1.01GB upload / 13.46GB download on the main network, and 46.21MB upload / 463.65MB download on the test network. The motivation behind doing this at the DEVp2p level (opposed to eth for example) is that it would enable compression for all sub-protocols (eth, les, bzz) seamlessly, reducing any complexity those protocols might incur in trying to individually optimize for data traffic. @@ -46,7 +46,7 @@ Important caveats: ### Avoiding DOS attacks -Currently a DEVp2p message length is limited to 24 bits, amounting to a maximum size of 16MB. With the introduction of Snappy compression, care must be taken not to blindy decompress messages, since they may get significantly larger than 16MB. +Currently a DEVp2p message length is limited to 24 bits, amounting to a maximum size of 16MB. With the introduction of Snappy compression, care must be taken not to blindly decompress messages, since they may get significantly larger than 16MB. However, Snappy is capable of calculating the decompressed size of an input message without inflating it in memory (*[the stream starts with the uncompressed length up to a maximum of `2^32 - 1` stored as a little-endian varint](https://github.com/google/snappy/blob/master/format_description.txt#L20)*). This can be used to discard any messages which decompress above some threshold. **The proposal is to use the same limit (16MB) as the threshold for decompressed messages.** This retains the same guarantees that the current DEVp2p protocol does, so there won't be surprises in application level protocols. diff --git a/EIPS/eip-712.md b/EIPS/eip-712.md index f7e8f893..14fa4c37 100644 --- a/EIPS/eip-712.md +++ b/EIPS/eip-712.md @@ -157,7 +157,7 @@ If the struct type references other struct types (and these in turn reference ev ### Definition of `encodeData` -The encoding of a struct instance is `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)`, i.e. the concatenation of the encoded member values in the order that they apear in the type. Each encoded member value is exactly 32-byte long. +The encoding of a struct instance is `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)`, i.e. the concatenation of the encoded member values in the order that they appear in the type. Each encoded member value is exactly 32-byte long. The atomic values are encoded as follows: Boolean `false` and `true` are encoded as `uint256` values `0` and `1` respectively. Addresses are encoded as `uint160`. Integer values are sign-extended to 256-bit and encoded in big endian order. `bytes1` to `bytes31` are arrays with a beginning (index `0`) and an end (index `length - 1`), they are zero-padded at the end to `bytes32` and encoded in beginning to end order. This corresponds to their encoding in ABI v1 and v2. @@ -205,7 +205,7 @@ By adding a prefix to the message makes the calculated signature recognisable as 1. `Address` - 20 Bytes - Address of the account that will sign the messages. 2. `TypedData` - Typed structured data to be signed. -Typed data is a JSON object containing type information, domain seprator parameters and the message object. Below is the [json-schema][jsons] definition for `TypedData` param. +Typed data is a JSON object containing type information, domain separator parameters and the message object. Below is the [json-schema][jsons] definition for `TypedData` param. [jsons]: https://json-schema.org/ diff --git a/EIPS/eip-725.md b/EIPS/eip-725.md index c69731a5..8688e9cc 100644 --- a/EIPS/eip-725.md +++ b/EIPS/eip-725.md @@ -19,7 +19,7 @@ The following describes standard functions for a unique identifiable proxy accou ## Motivation Standardizing a minimal interface for an proxy account allows third parties to interact with various proxy accounts contracts in a consistent manner. -the benefit is a persistent account that is independed from single keys and can attach an arbitrary amount of information to verifiy, or enhance the accounts purpose. +the benefit is a persistent account that is independent from single keys and can attach an arbitrary amount of information to verifiy, or enhance the accounts purpose. ## Specification diff --git a/EIPS/eip-758.md b/EIPS/eip-758.md index 8d7df949..89a5bffa 100644 --- a/EIPS/eip-758.md +++ b/EIPS/eip-758.md @@ -46,7 +46,7 @@ Or to be notified of any transactions submitted by this rpc client when they com filter = {} ``` -After the request is recieved, the Ethereum node responds with a subscription ID: +After the request is received, the Ethereum node responds with a subscription ID: ```json {"jsonrpc": "2.0", "id": 1, "result": "0x00000000000000000000000000000b0b"} @@ -106,7 +106,7 @@ The node responds with an array of transaction hashes and their corresponding re } ``` -All transactions that were sealed _after_ the initial `eth_newCompletedTransactionFilter` request are included in this array. Again, if the `filter` param is a non-empty dictinary (contains either `from`, `to`, or `hasReturnData`) then only transactions matching the filter criteria generate notifications. Note that in the polling case, there is no way for the Ethereum node to be sure that an RPC client which submits a transaction was the same as the one who created the filter, so there is no restriction based on where the transaction was submitted. +All transactions that were sealed _after_ the initial `eth_newCompletedTransactionFilter` request are included in this array. Again, if the `filter` param is a non-empty dictionary (contains either `from`, `to`, or `hasReturnData`) then only transactions matching the filter criteria generate notifications. Note that in the polling case, there is no way for the Ethereum node to be sure that an RPC client which submits a transaction was the same as the one who created the filter, so there is no restriction based on where the transaction was submitted. ## Rationale diff --git a/EIPS/eip-823.md b/EIPS/eip-823.md index 727af0cf..f9eb4149 100644 --- a/EIPS/eip-823.md +++ b/EIPS/eip-823.md @@ -184,7 +184,7 @@ This event logs any new exchange that have taken place and have been spent immed event ExchangeAndSpent ( address _from, address _by, uint _value ,address _target ,address _to) ``` -### Diagramatic Explaination +### Diagramatic Explanation #### Exchanging Tokens ![token-exchange-standard-visual-representation-1](https://raw.githubusercontent.com/kashishkhullar/EIPs/master/assets/eip-823/eip-823-token-exchange-standard-visual-representation-1.PNG) diff --git a/EIPS/eip-918.md b/EIPS/eip-918.md index 1dc296e5..10047046 100644 --- a/EIPS/eip-918.md +++ b/EIPS/eip-918.md @@ -66,7 +66,7 @@ bytes32 public adjustmentInterval; ``` #### challengeNumber -The current challenge number. It is expected tha a new challenge number is generated after a new reward is minted. +The current challenge number. It is expected that a new challenge number is generated after a new reward is minted. ``` solidity bytes32 public challengeNumber; @@ -145,7 +145,7 @@ contract AbstractERC918 is EIP918Interface { epochCount = _epoch(); - //every so often, readjust difficulty. Dont readjust when deploying + //every so often, readjust difficulty. Don't readjust when deploying if(epochCount % blocksPerReadjustment == 0){ _adjustDifficulty(); } @@ -273,7 +273,7 @@ contract ERC918Merged is AbstractERC918 { } /* - * @notice Externally facing merge function kept for backwards compatability with previous definition + * @notice Externally facing merge function kept for backwards compatibility with previous definition * * @param _nonce the solution nonce * @param _challenge_digest the keccak256 encoded challenge number + message sender + solution nonce @@ -442,7 +442,7 @@ Earlier versions of this standard incorporated a redundant 'challenge_digest' pa contract ERC918BackwardsCompatible is AbstractERC918 { /* - * @notice Externally facing mint function kept for backwards compatability with previous mint() definition + * @notice Externally facing mint function kept for backwards compatibility with previous mint() definition * @param _nonce the solution nonce * @param _challenge_digest the keccak256 encoded challenge number + message sender + solution nonce **/ diff --git a/EIPS/eip-998.md b/EIPS/eip-998.md index 88f0b920..bc87b8b1 100644 --- a/EIPS/eip-998.md +++ b/EIPS/eip-998.md @@ -856,7 +856,7 @@ interface ERC998ERC721BottomUp { /// @return rootOwner The root owner at the top of tree of tokens and ERC998 magic value. function rootOwnerOf(uint256 _tokenId) external view returns (bytes32 rootOwner); - /// @notice Get the owner addess and parent token (if there is one) of a token + /// @notice Get the owner address and parent token (if there is one) of a token /// @param _tokenId The tokenId to query. /// @return tokenOwner The owner address of the token /// @return parentTokenId The parent owner of the token and ERC998 magic value @@ -947,7 +947,7 @@ Here is an example of a value returned by `rootOwnerOf`. #### tokenOwnerOf ```solidity -/// @notice Get the owner addess and parent token (if there is one) of a token +/// @notice Get the owner address and parent token (if there is one) of a token /// @param _tokenId The tokenId to query. /// @return tokenOwner The owner address of the token and ERC998 magic value. /// @return parentTokenId The parent owner of the token diff --git a/README.md b/README.md index 03278d56..3d0d6306 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ When you believe your EIP is mature and ready to progress past the draft phase, * **Draft** - an EIP that is undergoing rapid iteration and changes. * **Last Call** - an EIP that is done with its initial iteration and ready for review by a wide audience. -* **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP wil move to final. +* **Accepted** - a core EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. The process for Core Devs to decide whether to encode an EIP into their clients as part of a hard fork is not part of the EIP process. If such a decision is made, the EIP will move to final. * **Final (non-Core)** - an EIP that has been in Last Call for at least 2 weeks and any technical changes that were requested have been addressed by the author. * **Final (Core)** - an EIP that the Core Devs have decided to implement and release in a future hard fork or has already been released in a hard fork. * **Deferred** - an EIP that is not being considered for immediate adoption. May be reconsidered in the future for a subsequent hard fork. diff --git a/assets/eip-1057/test-vectors.md b/assets/eip-1057/test-vectors.md index 991e2509..5fcec000 100644 --- a/assets/eip-1057/test-vectors.md +++ b/assets/eip-1057/test-vectors.md @@ -1,6 +1,6 @@ # Test Vectors for EIP-1057 - ProgPow -Many of these vectors are dervived from [chfast/ethash](https://github.com/chfast/ethash) +Many of these vectors are derived from [chfast/ethash](https://github.com/chfast/ethash) ## fnv1a @@ -121,7 +121,7 @@ Kiss 99 state: For the first loop iteration of block 30,000 the seed to use for `fill_mix` would be `0xEE304846DDD0A47B`. A two dimensional `mix` array should be created -passing the rows into `fill_mix` witht he column number as the loop argument. +passing the rows into `fill_mix` with the column number as the loop argument. The state of the mix array after the call to `progPowLoop` for block 30,000, loop 1 are as follows. diff --git a/index.html b/index.html index c79bd888..507775cb 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,7 @@ title: Home

    EIP Types

    From bd877f84f92cb002f93ca4bfd1ef3ba04a006b7a Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 17 Jul 2019 18:40:46 -0400 Subject: [PATCH 333/431] Fix typo in (#2194) --- EIPS/eip-6.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-6.md b/EIPS/eip-6.md index 3e097521..2302a4c7 100644 --- a/EIPS/eip-6.md +++ b/EIPS/eip-6.md @@ -12,7 +12,7 @@ created: 2015-11-22 The solution proposed in this EIP is to change the name of the `SUICIDE` opcode in Ethereum programming languages with `SELFDESTRUCT`. ### Motivation -Mental health is a very real issue for many people and small notions can make a difference. Those dealing with loss or depression would benefit from not seeing the word suicide in our a programming languages. By some estimates, 350 million people worldwide suffer from depression. The semantics of Ethereum's programming languages need to be reviewed often if we wish to grow our ecosystem to all types of developers. +Mental health is a very real issue for many people and small notions can make a difference. Those dealing with loss or depression would benefit from not seeing the word suicide in our programming languages. By some estimates, 350 million people worldwide suffer from depression. The semantics of Ethereum's programming languages need to be reviewed often if we wish to grow our ecosystem to all types of developers. An Ethereum security audit commissioned by DEVolution, GmbH and [performed by Least Authority](https://github.com/LeastAuthority/ethereum-analyses/blob/master/README.md) recommended the following: > Replace the instruction name "suicide" with a less connotative word like "self-destruct", "destroy", "terminate", or "close", especially since that is a term describing the natural conclusion of a contract. From 4e33f4ca90bf49990ae9ee64334460e042b56df9 Mon Sep 17 00:00:00 2001 From: Witek Date: Wed, 17 Jul 2019 19:53:42 -0700 Subject: [PATCH 334/431] Automatically merged updates to draft EIP(s) 1761 (#2198) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-1761.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EIPS/eip-1761.md b/EIPS/eip-1761.md index 7b4057e1..7d7a5116 100644 --- a/EIPS/eip-1761.md +++ b/EIPS/eip-1761.md @@ -1,7 +1,7 @@ --- eip: 1761 title: ERC-1761 Scoped Approval Interface -author: Witek Radomski , Andrew Cooke , James Therien , Eric Binet +author: Witek Radomski , Andrew Cooke , James Therien , Eric Binet type: Standards Track category: ERC status: Draft @@ -48,14 +48,14 @@ interface ScopedApproval { The range is inclusive: _idStart, _idEnd, and all IDs in between have been added to the scope. _idStart must be lower than or equal to _idEnd. */ - event AddIdsToScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); + event IdsAddedToScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); /** @dev MUST emit when the token IDs are removed from the scope. The range is inclusive: _idStart, _idEnd, and all IDs in between have been removed from the scope. _idStart must be lower than or equal to _idEnd. */ - event RemoveIdsFromScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); + event IdsRemovedFromScope(uint256 indexed _idStart, uint256 indexed _idEnd, bytes32 indexed _scope); /** @dev MUST emit when a scope URI is set or changes. URIs are defined in RFC 3986. From fc9dad1f82e992b92a7c4ab25a9e4986ab664c8a Mon Sep 17 00:00:00 2001 From: Tom Brand Date: Thu, 18 Jul 2019 14:03:21 +0300 Subject: [PATCH 335/431] Automatically merged updates to draft EIP(s) 2028 (#2199) Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing --- EIPS/eip-2028.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/EIPS/eip-2028.md b/EIPS/eip-2028.md index e8b8230f..9dfbab78 100644 --- a/EIPS/eip-2028.md +++ b/EIPS/eip-2028.md @@ -62,6 +62,10 @@ To suggest the gas cost of calldata we shall conduct two types of tests: 1. Network tests, conducted on the Ethereum mainnet, used to estimate the effect on increasing block size on _D_p_ and _D_t_, on the overall network delay D and the efficiency ratio (**), as well as delays between different mining pools. Those tests will include regression tests on existing data, and stress tests to introduce extreme scenarios. 2. Local tests, conducted on a single node and measuring the processing time as a function of Calldata amount and general computation limits. +## Reference Implementation +[Parity](https://github.com/liorgold2/parity-ethereum/pull/1) +[Geth](https://github.com/liorgold2/go-ethereum/pull/1) + ## References [1] Yonatan Sompolinsky, Aviv Zohar: [Secure High-Rate Transaction Processing in Bitcoin](https://eprint.iacr.org/2013/881.pdf). Financial Cryptography 2015: 507-527 From 1529796d3a141a2e1b23911d291407d6eeb39c2d Mon Sep 17 00:00:00 2001 From: Loredana Cirstea Date: Thu, 18 Jul 2019 22:14:06 +0300 Subject: [PATCH 336/431] Add ERC: dType Alias Extension - Decentralized Type System (#2193) * Add ERC: dType Alias Extension - Decentralized Type System * Add EIP number 2193, fix links As suggested in https://github.com/ethereum/EIPs/pull/2193#discussion_r304121479, https://github.com/ethereum/EIPs/pull/2193#discussion_r304121615 * EIP-2193 - add separator semantics, address PR review - add separator semantic explanations - add EIP-155 as requirement, as per https://github.com/ethereum/EIPs/pull/2193#discussion_r304139427 - address https://github.com/ethereum/EIPs/pull/2193#discussion_r304139590 -- use `external` instead of public -- clarify who can set aliases -- chainId explanation -- use `bytes1 separator` instead of `string separator` --- EIPS/eip-2193.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 EIPS/eip-2193.md diff --git a/EIPS/eip-2193.md b/EIPS/eip-2193.md new file mode 100644 index 00000000..fdab1455 --- /dev/null +++ b/EIPS/eip-2193.md @@ -0,0 +1,92 @@ +--- +eip: 2193 +title: dType Alias Extension - Decentralized Type System +author: Loredana Cirstea (@loredanacirstea), Christian Tzurcanu (@ctzurcanu) +discussions-to: https://github.com/ethereum/EIPs/issues/2192 +status: Draft +type: Standards Track +category: ERC +created: 2019-07-16 +requires: 1900, 2157, 155 +--- + +## Simple Summary + +We are proposing Alias - a semantic standard for identifying on-chain resources by human-readable qualifiers, supporting any type of data. + +## Abstract + +The dType Alias is a system for providing human-readable resource identifiers to on-chain content. A resource identifier is based on the type of data (identifier provided by dType, [EIP-1900](http://eips.ethereum.org/EIPS/eip-1900)) and the data content (identifier provided by a dType Storage Contract, [EIP-2157](http://eips.ethereum.org/EIPS/eip-2157)). It is a universal way of addressing content, supporting any type of data. + +## Motivation + +There are standards that currently address the need for attaching human-readable identifiers to Ethereum accounts, such as [EIP-137](http://eips.ethereum.org/EIPS/eip-137). These standards are an attempt to bring domain names to Ethereum, following the same format as DNS: `subdomain.domain.tld`. This leaf -> root format is unintuitive and contradicts the semantic meaning that `.` has in programming languages, which is a root -> leaf connection (e.g. in OOP, when accessing an object's property). A more intuitive and widely used approach is a root->leaf format, used in file browsers, hierarchical menus, and even in other decentralized systems, which give unique identifiers to resources (e.g. `0x56.Currency.TCoin` in [Libra](https://medium.com/r/?url=https%3A%2F%2Fdevelopers.libra.org). + +Moreover, [EIP-137](http://eips.ethereum.org/EIPS/eip-137) is not flexible enough to address smart contract content, which can contain heterogeneous data that belongs to various accounts. For example, a `PaymentChannel` smart contract can have an domain name. However, the `Alice-Bob` channel data from inside the smart contract, cannot have a subdomain name. Having uniquely identified, granular resources opens the way to creating both human and machine-readable protocols on top of Ethereum. It also provides a basis for protocols based on functional programming. + +This ERC proposes a set of separators which maintain their semantic meaning and provides a way to address any type of resource - from Ethereum addresses, to individual `struct` instances inside smart contracts. + +Imagine the following dType types: `SocialNetwork` and `Profile`, with related storage data about user profiles. One could access such a profile using an alias for the data content: `alice@socialnetwork.profile`. For a `PaymentChannel` type, Alice can refer to her channel with Bob with `alice-bob.paymentchannel`. +This alias system can be used off-chain, to replace the old DNS system with a deterministic and machine-readable way of displaying content, based on the dType type's metadata. + +## Specification + +The dType registry will provide domain and subdomain names for the resource type. Subdomains can be attributed recursively, to dType types which contain other complex types in their composition. + +We define an `Alias` registry contract, that keeps track of the human-readable identifiers for data resources, which exist in dType storage contracts. +Anyone can set an alias in the `Alias` registry, as long as the Ethereum address that signs the alias data has ownership on the resource, in the dType storage contract. Storage contract data ownership will be detailed in [EIP-2157](http://eips.ethereum.org/EIPS/eip-2157). An owner can update or delete an alias at any time. + +```solidity +interface Alias { + + event AliasSet(bytes32 dtypeIdentifier, bytes1 separator, string name, bytes32 indexed identifier); + + function setAlias(bytes32 dtypeIdentifier, bytes1 separator, string memory name, bytes32 identifier, bytes memory signature) external; + + function getAliased(bytes1 separator, string memory name) view external returns (bytes32 identifier); +} +``` + +- `dtypeIdentifier`: Type identifier from the dType registry, needed to ensure uniqueness of `name` for a dType type. `dtypeIdentifier` is checked to see if it exists in the dType registry. The dType registry also links the type's data storage contract, where the existence and ownership of the `identifier` is checked. +- `name`: user-defined human-readable name for the resource referenced by `identifier` +- `separator`: Character acting as a separator between the name and the rest of the alias. Allowed values: + - `.`: general domain separation, using root->leaf semantics. E.g. `domain.subdomain.leafsubdomain.resource` + - `@`: identifying actor-related data, such as user profiles, using leaf->root semantics. E.g. `alice@socialnetwork.profile` or `alice@dao@eth` + - `#`: identifying concepts, using root->leaf semantics. E.g. `topicX#postY` + - `/`: general resource path definition, using root->leaf semantics. E.g. `resourceRoot/resource` +- `identifier`: Resource identifier from a smart contract linked with dType +- `signature`: Alias owner signature on `dtypeIdentifier`, `identifier`, `name`, `separator`, `nonce`, `aliasAddress`, `chainId`. + - `nonce`: monotonically increasing counter, used to prevent replay attacks + - `aliasAddress`: Ethereum address of `Alias` contract + - `chainId`: chain on which the `Alias` contract is deployed, as detailed in [EIP-155](http://eips.ethereum.org/EIPS/eip-155), used to prevent replay attacks when updating the `identifier` for an alias. + +Content addressability can be done: +- using the `bytes32` identifiers directly, e.g. `0x0b5e76559822448f6243a6f76ac7864eba89c810084471bdee2a63429c92d2e7@0x9dbb9abe0c47484c5707699b3ceea23b1c2cca2ac72681256ab42ae01bd347da` +- using the human identifiers, e.g. `alice@socialnetwork` + +Both of the above examples will resolve to the same content. + + +## Rationale + +Current attempts to solve content addressability, such as [EIP-137](http://eips.ethereum.org/EIPS/eip-137), only target Ethereum accounts. These are based on inherited concepts from HTTP and DNS, which are not machine friendly. + +With [EIP-1900](http://eips.ethereum.org/EIPS/eip-1900) and [EIP-2157](http://eips.ethereum.org/EIPS/eip-2157), general content addressability can be achieved. dType provides type information and a reference to the smart contract where the type instances are stored. Additionally, Alias uses the semantic meaning of subdomain separators to have a [intuitive order rule](https://github.com/loredanacirstea/articles/blob/master/articles/Flexible_Alias_or_Why_ENS_is_Obsolete.md). + +Multiple aliases can be assigned to a single resource. Either by using a different `name` or by using a different `separator`. Each `separator` can have a specific standard for displaying and processing data, based on its semantic meaning. + +## Backwards Compatibility + +Will be added. + +## Test Cases + +Will be added. + +## Implementation + +An in-work implementation can be found at https://github.com/pipeos-one/dType/blob/master/contracts/contracts/Alias.sol. +This proposal will be updated with an appropriate implementation when consensus is reached on the specifications. + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 0b1c7f75bde144c0e9acd5556071b56d2b5a886c Mon Sep 17 00:00:00 2001 From: xinbenlv Date: Mon, 22 Jul 2019 19:42:49 -0700 Subject: [PATCH 337/431] Check-In first draft of EIP-2135 (#2171) * Update the minimized eip-1202 to get ready of publication * Add eip-2135 init draft * Update EIP-2135 at https://github.com/xinbenlv/eip-2135/blob/6e4e4011182799451abc850e4f81fa19a0df9e03/eip-2135.md --- EIPS/eip-2135.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 EIPS/eip-2135.md diff --git a/EIPS/eip-2135.md b/EIPS/eip-2135.md new file mode 100644 index 00000000..547a3ead --- /dev/null +++ b/EIPS/eip-2135.md @@ -0,0 +1,79 @@ +--- +eip: 2135 +title: Consumable Interface +author: Zainan Victor Zhou (@xinbenlv) +discussions-to: https://github.com/ethereum/EIPs/issues/2135 +status: Draft +type: Standards Track +category: ERC +created: 2019-06-23 +--- + +## Simple Summary +An interface marking certain digital assets being consumable. + +## Abstract +The interface identifies functions and events needed for creating a contract to be able to mark a digital asset as "consumable", and react to the request of "consumption". + +## Motivation +Being a digital assets sometimes means a consumable power. One most common seen examples would be a concert ticket. It will be "consumed" at the moment the ticket-holder uses the ticket to get access to enter a concert. + +By having a standard ERC interface, the Ethereum ecosystem can interoperate to provide services, clients, UI, and inter-contract functionalities on top of this very general use-case. + +## Specification +The standard will mainly contain the following interface. + +### The required interface + +```solidity +pragma solidity ^0.5.8; + +contract EIP2135 { + // The main consume function + function consume(uint256 assetId) public returns(bool success); + + // The interface to check whether an asset is consumable. + function isConsumable(uint256 assetId) public view returns (bool consumable); + + // The interface to check whether an asset is consumable. + event OnConsumption(uint256 indexed assetId); +} +``` + +## Rationale + +The function `consume` performs the consume action. Being an interface standard, +this EIP does not impose any assumption of + + - who has the power to perform such activity. + - under what condition such consumption can occur. + +It does, however, assume the asset can be identified in a `uint256` assetId as in th parameter. A design convention and compatibility consideration is put in place to follow the ERC-721 + +The event notifies subscribers whoever are interested to learn an asset is being consumed. The boolean function of `isConsumable` can be used to check whether an asset is still consumable. + +To keep it simple, this standard *intentionally* contains no functions or events related to creation of a consumable asset. This is because the creation of a consumable asset will need to make assumption of the nature of an actual use-case. If we see some common use-case of creation, we can have another follow up standard. + +We also left out metadata associated to the consumables from the standard. If necessary, related metadata can be created with a separate metadata extension interface like [`ERC721Metadata`](https://eips.ethereum.org/EIPS/eip-721) + +## Backwards Compatibility + +This interface is designed to be compatible with ERC-721. + +## Implementation + +A reference implementation accompany with tests of **ERC-721 based ticket** contract is built and you can found it [here](https://github.com/xinbenlv/eip-2135/blob/master/impl/contracts/Ticket721.sol). + +See [Github/xinbenlv/eip-2135/impl](https://github.com/xinbenlv/eip-2135/tree/master/impl) + +## Test Cases + +See [Github/xinbenlv/eip-2135/impl/test](https://github.com/xinbenlv/eip-2135/tree/master/impl/test) + +## Reference + +### Standards +- [ERC-721](https://eips.ethereum.org/EIPS/eip-721) + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From a83a10fedf7536780b02b804d189ff058d2bf2ef Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 23 Jul 2019 10:32:39 +0100 Subject: [PATCH 338/431] Rename eip-X template to eip-template (#2201) * Rename eip-X template to eip-template To reduce potential confusion. * Rename explanation of assets/eip-X to assets/eip-N --- EIPS/eip-1.md | 2 +- ISSUE_TEMPLATE.md | 2 +- PULL_REQUEST_TEMPLATE.md | 2 +- README.md | 4 ++-- _config.yml | 2 +- eip-X.md => eip-template.md | 0 index.html | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename eip-X.md => eip-template.md (100%) diff --git a/EIPS/eip-1.md b/EIPS/eip-1.md index 50d55747..f8a560b0 100644 --- a/EIPS/eip-1.md +++ b/EIPS/eip-1.md @@ -116,7 +116,7 @@ Each EIP should have the following parts: ## EIP Formats and Templates EIPs should be written in [markdown] format. -Image files should be included in a subdirectory of the `assets` folder for that EIP as follows: `assets/eip-X` (for eip **X**). When linking to an image in the EIP, use relative links such as `../assets/eip-X/image.png`. +Image files should be included in a subdirectory of the `assets` folder for that EIP as follows: `assets/eip-N` (where **N** is to be replaced with the EIP number). When linking to an image in the EIP, use relative links such as `../assets/eip-1/image.png`. ## EIP Header Preamble diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 28fdd587..f18eb4fd 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,5 +1,5 @@ -ATTENTION! If you would like to submit an EIP and it has already been written as a draft (see the [template](https://github.com/ethereum/EIPs/blob/master/eip-X.md) for an example), please submit it as a [Pull Request](https://github.com/ethereum/EIPs/pulls). +ATTENTION! If you would like to submit an EIP and it has already been written as a draft (see the [template](https://github.com/ethereum/EIPs/blob/master/eip-template.md) for an example), please submit it as a [Pull Request](https://github.com/ethereum/EIPs/pulls). If you are considering a proposal but would like to get some feedback on the idea before submitting a draft, then continue opening an Issue as a thread for discussion. Note that the more clearly and completely you state your idea the higher the quality of the feedback you are likely to receive. diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 03f1f3da..bff8b61e 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,4 @@ -When opening a pull request to submit a new EIP, please use the suggested template: https://github.com/ethereum/EIPs/blob/master/eip-X.md +When opening a pull request to submit a new EIP, please use the suggested template: https://github.com/ethereum/EIPs/blob/master/eip-template.md We have a GitHub bot that automatically merges some PRs. It will merge yours immediately if certain criteria are met: diff --git a/README.md b/README.md index 5dcd63d8..843d7f05 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ A browsable version of all current and draft EIPs can be found on [the official 1. Review [EIP-1](EIPS/eip-1.md). 2. Fork the repository by clicking "Fork" in the top right. - 3. Add your EIP to your fork of the repository. There is a [template EIP here](eip-X.md). + 3. Add your EIP to your fork of the repository. There is a [template EIP here](eip-template.md). 4. Submit a Pull Request to Ethereum's [EIPs repository](https://github.com/ethereum/EIPs). Your first PR should be a first draft of the final EIP. 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 EIP 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 EIP as a whole. -If your EIP requires images, the image files should be included in a subdirectory of the `assets` folder for that EIP as follows: `assets/eip-X` (for eip **X**). When linking to an image in the EIP, use relative links such as `../assets/eip-X/image.png`. +If your EIP requires images, the image files should be included in a subdirectory of the `assets` folder for that EIP as follows: `assets/eip-N` (where **N** is to be replaced with the EIP number). When linking to an image in the EIP, use relative links such as `../assets/eip-1/image.png`. Once your first PR is merged, we have a bot that helps out by automatically merging PRs to draft EIPs. 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 EIP contains either your Github username or your email address inside . If you use your email address, that address must be the one publicly shown on [your GitHub profile](https://github.com/settings/profile). diff --git a/_config.yml b/_config.yml index b0fbe061..5eac0624 100644 --- a/_config.yml +++ b/_config.yml @@ -54,4 +54,4 @@ exclude: - vendor/cache/ - vendor/gems/ - vendor/ruby/ - - eip-X.md + - eip-template.md diff --git a/eip-X.md b/eip-template.md similarity index 100% rename from eip-X.md rename to eip-template.md diff --git a/index.html b/index.html index 8e495bde..670b8e56 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ title: Home

    Ethereum Improvement Proposals (EIPs) describe standards for the Ethereum platform, including core protocol specifications, client APIs, and contract standards.

    Contributing

    -

    First review EIP-1. Then clone the repository and add your EIP to it. There is a template EIP here. Then submit a Pull Request to Ethereum's EIPs repository.

    +

    First review EIP-1. Then clone the repository and add your EIP to it. There is a template EIP here. Then submit a Pull Request to Ethereum's EIPs repository.

    EIP status terms