{"action":"created","issue":{"url":"https://api.github.com/repos/ethereum/EIPs/issues/1538","repository_url":"https://api.github.com/repos/ethereum/EIPs","labels_url":"https://api.github.com/repos/ethereum/EIPs/issues/1538/labels{/name}","comments_url":"https://api.github.com/repos/ethereum/EIPs/issues/1538/comments","events_url":"https://api.github.com/repos/ethereum/EIPs/issues/1538/events","html_url":"https://github.com/ethereum/EIPs/issues/1538","id":375653151,"node_id":"MDU6SXNzdWUzNzU2NTMxNTE=","number":1538,"title":"ERC1538: Transparent Contract Standard","user":{"login":"mudgen","id":49092,"node_id":"MDQ6VXNlcjQ5MDky","avatar_url":"https://avatars1.githubusercontent.com/u/49092?v=4","gravatar_id":"","url":"https://api.github.com/users/mudgen","html_url":"https://github.com/mudgen","followers_url":"https://api.github.com/users/mudgen/followers","following_url":"https://api.github.com/users/mudgen/following{/other_user}","gists_url":"https://api.github.com/users/mudgen/gists{/gist_id}","starred_url":"https://api.github.com/users/mudgen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mudgen/subscriptions","organizations_url":"https://api.github.com/users/mudgen/orgs","repos_url":"https://api.github.com/users/mudgen/repos","events_url":"https://api.github.com/users/mudgen/events{/privacy}","received_events_url":"https://api.github.com/users/mudgen/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":37,"created_at":"2018-10-30T19:20:51Z","updated_at":"2018-11-12T19:06:57Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"---\r\neip: 1538\r\ntitle: Transparent Contract Standard\r\nauthor: Nick Mudge <nick@mokens.io>\r\nstatus: Draft\r\ntype: Standards Track\r\ncategory ERC\r\ncreated: 31 October 2018\r\n---\r\n\r\n<!--You can leave these HTML comments in your merged EIP and delete the visible duplicate text guides, they will not appear and may be helpful to refer to if you edit it again. This is the suggested template for new EIPs. Note that an EIP number will be assigned by an editor. When opening a pull request to submit your EIP, please use an abbreviated title in the filename, `eip-draft_title_abbrev.md`. The title should be 44 characters or less.-->\r\n\r\n\r\nFeedback about this proposal is appreciated.\r\n\r\n## Simple Summary\r\n<!--\"If you can't explain it simply, you don't understand it well enough.\" Provide a simplified and layman-accessible explanation of the EIP.-->\r\nThis standard provides a contract architecture that makes upgradeable contracts flexible, unlimited in size, and transparent. \r\n\r\nA transparent contract publicly documents the full history of all changes made to it.\r\n\r\nAll changes to a transparent contract are reported in a standard format.\r\n\r\n## Abstract\r\n<!--A short (~200 word) description of the technical issue being addressed.-->\r\n\r\nThis standard addresses the following technical issues:\r\n\r\n1. A way to add, replace and remove functions from a contract.\r\n1. Standard events to show what functions are added, replaced and removed from a contract, and why the changes are made.\r\n2. A standard way to query a contract to discover and retrieve information about all functions exposed by it.\r\n3. 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.\r\n4. Enables an upgradeable contract to become immutable in the future if desired.\r\n\r\nNote that with this standard multiple functions can be added, replaced or removed at the same time.\r\n\r\n## Motivation\r\n<!--The motivation is critical for EIPs that want to change the Ethereum protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EIP solves. EIP submissions without sufficient motivation may be rejected outright.-->\r\nA 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.\r\n\r\nHowever, a fundamental problem with trustless contracts that cannot be changed is that they cannot be changed. \r\n\r\n#### Bugs\r\n\r\nBugs and security vulnerabilities are unwittingly written into immutable contracts that ruin them.\r\n\r\n#### Improvements\r\n\r\nImmutable, trustless contracts cannot be improved, resulting in increasingly inferior contracts over time.\r\n\r\nContract 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.\r\n\r\nIn 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.\r\n\r\n### Middle Ground\r\n\r\nTransparent contracts provide a middle ground between immutable trustless contracts that can't be improved and upgradeable contracts that can't be trusted.\r\n\r\n### Purposes\r\n\r\n1. Create upgradeable contracts that earn trust by showing a provable history of trustworthiness. \r\n2. Document the development of contracts so their development and change is provably public and can be understood.\r\n3. Create upgradeable contracts that can become immutable in the future if desired.\r\n\r\n### Benefits & Use Cases\r\nThis standard is for use cases that benefit from the following:\r\n1. The ability to add, replace or remove any function.\r\n2. Each time a function is added, replaced or removed, it is documented with events.\r\n3. Build trust over time by showing all changes made to a contract.\r\n4. Unlimited contract size.\r\n5. The ability to query information about functions currently supported by the contract.\r\n6. One contract address that provides all needed functionality and never needs to be replaced by another contract address.\r\n7. The ability for a contract to be upgradeable for a time, and then become immutable.\r\n\r\n### New Software Possibilities\r\n\r\nThis standard enables a form contract version control software to be written.\r\n\r\nSoftware 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. \r\n\r\nUser interfaces and software can also use this standard to assist or automate changes of contracts.\r\n\r\n## Specification\r\n<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->\r\n\r\n> **Note:**\r\nThe solidity `delegatecall` opcode enables a contract to execute a function from another contract, but it is executed as if the function were 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.\r\n\r\nA transparent contract implements the following design points:\r\n\r\n1. A transparent contract is a contract that contains no functions except a constructor and a fallback function.\r\n2. A transparent contract has a mapping that associates functions with contracts. These contracts are referred to as \"delegate contracts\" in this standard.\r\n3. When a function is called on a transparent contract its fallback function is executed. The fallback function finds the delegate contract associated with the function call and executes the function call using `delegatecall` and the delegate contract.\r\n4. The constructor of a transparent contract associates the `updateContract` function with a delegate contract that implements the ERC1538 interface.\r\n5. Other functions are added, replaced and removed by calling the `updateContract` function.\r\n6. The `updateContract` function associates functions with delegate contracts that implement those functions, and emits the `CommitMessage` and `FunctionUpdate` events that document function changes.\r\n7. 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 it is only emitted after any `FunctionUpdate` events are emitted.\r\n8. 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.\r\n9. The source code of the transparent contract and all delegate contract used by it are publicly viewable and verified.\r\n\r\nThe 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.\r\n\r\nTypically 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.\r\n\r\nHere is an example of an implementation of a transparent contract:\r\n\r\n```solidity\r\ncontract MyTransparentContract {\r\n  //owner of the contract\r\n  address internal contractOwner;\r\n  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\r\n\r\n  // maps functions to the delegate contracts that execute the functions\r\n  // funcId => delegate contract\r\n  mapping(bytes4 => address) internal delegates;\r\n    \r\n  event CommitMessage(string message);\r\n  event FunctionUpdate(bytes4 indexed functionId, address indexed oldDelegate, address indexed newDelegate, string functionSignature);\r\n\r\n  constructor(address _erc1538Delegate) public {\r\n    contractOwner = msg.sender;\r\n    emit OwnershipTransferred(address(0), msg.sender);\r\n\r\n    // adding ERC1538 updateContract function\r\n    bytes memory signature = \"updateContract(address,string,string)\";\r\n    bytes4 funcId = bytes4(keccak256(signature));\r\n    delegates[funcId] = _erc1538Delegate;\r\n    emit FunctionUpdate(funcId, address(0), _erc1538Delegate, string(signature));\r\n    emit CommitMessage(\"Added ERC1538 updateContract function at contract creation\");\r\n  }\r\n\r\n  function() external payable {\r\n    // Delegate every function call to a delegate contract\r\n    address delegate = delegates[msg.sig];\r\n    require(delegate != address(0), \"Function does not exist.\");\r\n    assembly {\r\n      let ptr := mload(0x40)\r\n      calldatacopy(ptr, 0, calldatasize)\r\n      let result := delegatecall(gas, delegate, ptr, calldatasize, 0, 0)\r\n      let size := returndatasize\r\n      returndatacopy(ptr, 0, size)\r\n      switch result\r\n      case 0 {revert(ptr, size)}\r\n      default {return (ptr, size)}\r\n    }\r\n  }\r\n}\r\n```\r\nAs can be seen in the above implementation, every function call is delegated to a delegate contract.\r\n\r\nSo the constructor function adds the first function to the transparent contract, which is then used to add other functions to the transparent contract.\r\n\r\nEach 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.\r\n\r\nThe delegate contract that implements the `updateContract` function implements the following interface: \r\n### ERC1538 Interface\r\n\r\n```solidity\r\npragma solidity ^0.4.25;\r\n\r\n/// @title ERC1538 Transparent Contract Standard\r\n/// @dev Required interface\r\n///  Note: the ERC-165 identifier for this interface is 0x61455567\r\ninterface ERC1538 {\r\n  /// @dev This emits when one or a set of functions are updated in a transparent contract.\r\n  ///  The message string should give a short description of the change and why\r\n  ///  the change was made.\r\n  event CommitMessage(string message);\r\n  \r\n  /// @dev This emits for each function that is updated in a transparent contract.\r\n  ///  functionId is the bytes4 of the keccak256 of the function signature.\r\n  ///  oldDelegate is the delegate contract address of the old delegate contract if\r\n  ///  the function is being replaced or removed.\r\n  ///  oldDelegate is the zero value address(0) if a function is being added for the\r\n  ///  first time.\r\n  ///  newDelegate is the delegate contract address of the new delegate contract if \r\n  ///  the function is being added for the first time or if the function is being \r\n  ///  replaced.\r\n  ///  newDelegate is the zero value address(0) if the function is being removed.\r\n  event FunctionUpdate(\r\n    bytes4 indexed functionId, \r\n    address indexed oldDelegate, \r\n    address indexed newDelegate, \r\n    string functionSignature\r\n  );\r\n\r\n  /// @notice Updates functions in a transparent contract.\r\n  /// @dev If the value of _delegate is zero then the functions specified \r\n  ///  in _functionSignatures are removed.\r\n  ///  If the value of _delegate is a delegate contract address then the functions \r\n  ///  specified in _functionSignatures will be delegated to that address.\r\n  /// @param _delegate The address of a delegate contract to delegate to or zero\r\n  /// @param _functionSignatures A list of function signatures listed one after the other\r\n  /// @param _commitMessage A short description of the change and why it is made\r\n  ///        This message is passed to the CommitMessage event.          \r\n  function updateContract(address _delegate, string _functionSignatures, string commitMessage) external;  \r\n}\r\n```\r\nThe 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.\r\n\r\nHere is an example of calling the `updateContract` function that adds the ERC721 standard functions to a transparent contract:\r\n```javascript\r\nfunctionSignatures = \"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)\"\r\ntx = await transparentContract.updateContract(erc721Delegate.address, functionSignatures, \"Adding ERC721 functions\");\r\n```\r\nThe 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.\r\n<!--\r\nA transparent contract must implement the [ERC-165 Standard Interface Detection standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md) via a delegate contract by adding the `supportsInterface` function using the `updateContract` function. The interfaceID for the ERC1538 standard is `0x61455567`.\r\n-->\r\n\r\n### ERC1538Query\r\n\r\nOptionally, 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.\r\n\r\nThe following is an optional interface for querying function information from a transparent contract:\r\n\r\n```solidity\r\ninterface ERC1538Query {\r\n    \r\n  /// @notice Gets the total number of functions the transparent contract has.\r\n  function totalFunctions() external view returns(uint256);\r\n\t\r\n  /// @notice Gets information about a specific function\r\n  /// @param _index The index position of a function signature that is stored in an array\r\n  function functionByIndex(uint256 _index) \r\n    external \r\n    view \r\n    returns(\r\n      string memory functionSignature, \r\n      bytes4 functionId, \r\n      address delegate\r\n    );\r\n\t\r\n  /// @notice Checks to see if a function exists\r\n  /// @param The function signature to check\r\n  function functionExists(string _functionSignature) external view returns(bool);\r\n\t\r\n  /// @notice Gets all the function signatures of functions supported by the transparent contract\r\n  function functionSignatures() external view returns(string);\r\n\t\r\n  /// @notice Gets all the function signatures supported by a specific delegate contract\r\n  /// @param _delegate The delegate contract address\r\n  function delegateFunctionSignatures(address _delegate) external view returns(string);\r\n\t\r\n  /// @notice Gets the delegate contract address that supports the given function signature\r\n  /// @param The function signature\r\n  function delegateAddress(string _functionSignature) external view returns(address);\r\n\t\r\n  /// @notice Gets information about a function\r\n  /// @param _functionSignature The function signature of the function to get information about\r\n  function functionBySignature(string _functionSignature)\r\n    external \r\n    view \r\n    returns(\r\n      bytes4 functionId, \r\n      address delegate\r\n    );\r\n\t\r\n  /// @notice Gets information about a function\r\n  /// @param _functionId The id of the function to get information about.\r\n  function functionById(bytes4 _functionId) \r\n    external \r\n    view \r\n    returns(\r\n      string signature, \r\n      address delegate\r\n    );\r\n\t\r\n  /// @notice Get all the delegate contract addresses used by the transparent contract\r\n  function delegateAddresses() external view returns(address[]);\r\n}\r\n```\r\n\r\nSee the [reference implementation of ERC1538](https://github.com/mudgen/transparent-contracts-erc1538) to see how this is implemented.\r\n\r\nThe 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)\"`\r\n\r\n### How To Deploy A Transparent Contract\r\n1. 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.\r\n2. Create your transparent contract with a fallback function as given above. Your transparent contract also needs a constructor that adds the `updateContract` function.\r\n3. Deploy your transparent contract to a blockchain. Pass in the address of the ERC1538 delegate contract to your constructor if it requires it.\r\n\r\nSee the [reference implementation](https://github.com/mudgen/transparent-contracts-erc1538) for examples of these contracts.\r\n\r\n### Decentralized Authority\r\nIt 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.\r\n\r\n## Rationale\r\n<!--The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The rationale may also provide evidence of consensus within the community, and should discuss important objections or concerns raised during discussion.-->\r\n\r\n### Gas Considerations\r\n\r\nDelegating function calls does have some gas overhead. This is mitigated in two ways: \r\n1. 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.\r\n2. 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).\r\n\r\n### Storage\r\n\r\nThe standard does not specify how data is stored or organized by a transparent contract. But here are some suggestions:\r\n\r\n**Inherited Storage**\r\n\r\n1. 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.\r\n\r\n2. 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.\r\n\r\n**Unstructured Storage**\r\n\r\nAssembly 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.\r\n\r\n**Eternal Storage**\r\n\r\nData 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)\r\n\r\n### Becoming Immutable\r\nIt 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.\r\n\r\n### Inspiration\r\n\r\nThis standard was inspired by ZeppelinOS's implementation of [Upgradeability with vtables](https://github.com/zeppelinos/labs/tree/master/upgradeability_with_vtable). \r\n\r\nThis 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).\r\n\r\n## Backwards Compatibility\r\n<!--All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EIP must explain how the author proposes to deal with these incompatibilities. EIP submissions without a sufficient backwards compatibility treatise may be rejected outright.-->\r\nThis standard makes a contract compatible with future standards and functionality because new functions can be added and existing functions can be replaced or removed.\r\n\r\nThis standard future proofs a contract.\r\n\r\n## Implementation\r\n<!--The implementations must be completed before any EIP is given status \"Final\", but it need not be completed before the EIP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of \"rough consensus and running code\" is still useful when it comes to resolving many discussions of API details.-->\r\nA reference implementation of this standard is given in the [transparent-contracts-erc1538](https://github.com/mudgen/transparent-contracts-erc1538) repository.\r\n\r\n\r\n## Copyright\r\nCopyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).\r\n"},"comment":{"url":"https://api.github.com/repos/ethereum/EIPs/issues/comments/437994521","html_url":"https://github.com/ethereum/EIPs/issues/1538#issuecomment-437994521","issue_url":"https://api.github.com/repos/ethereum/EIPs/issues/1538","id":437994521,"node_id":"MDEyOklzc3VlQ29tbWVudDQzNzk5NDUyMQ==","user":{"login":"spalladino","id":429604,"node_id":"MDQ6VXNlcjQyOTYwNA==","avatar_url":"https://avatars2.githubusercontent.com/u/429604?v=4","gravatar_id":"","url":"https://api.github.com/users/spalladino","html_url":"https://github.com/spalladino","followers_url":"https://api.github.com/users/spalladino/followers","following_url":"https://api.github.com/users/spalladino/following{/other_user}","gists_url":"https://api.github.com/users/spalladino/gists{/gist_id}","starred_url":"https://api.github.com/users/spalladino/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spalladino/subscriptions","organizations_url":"https://api.github.com/users/spalladino/orgs","repos_url":"https://api.github.com/users/spalladino/repos","events_url":"https://api.github.com/users/spalladino/events{/privacy}","received_events_url":"https://api.github.com/users/spalladino/received_events","type":"User","site_admin":false},"created_at":"2018-11-12T19:06:57Z","updated_at":"2018-11-12T19:06:57Z","author_association":"NONE","body":"> I also like the vtable name. The standard could be renamed to \"Transparent vTable Contract Standard\". But does this clash with your vtable implementation name? Would you prefer this standard was named that rather than \"Transparent Contract Standard\"? I think \"Transparent\" is a key part of the name of this standard because a very major thing this standard does is report information about the change of every function.\r\n\r\nIt's fine with me if you pick up the vtable name, as we won't be pursuing that pattern in ZeppelinOS in the short term. And to be honest I love the fact that an experiment was picked up by a member of the community and driven forward until it becomes a standard!\r\n\r\nAs for transparent being a key part of the name, maybe I have a different idea in my mind about what \"transparent\" implies. To me it was about the proxy being invisible to a client, who would not be able to distinguish it from the actual contract, and not so much about reporting the changes of all functions. In that sense, something along the lines of \"registry\", \"logging\", \"history\", \"reporting\" may be better suited (though I don't really like any of those!). Anyway, to make a long story short, feel free to grab the vtable name for this standard! I'd be happy if you do :-)"}}
{"actor":{"display_login":"spalladino"}}