From d6698c3bfbd9640b72079ab614dcd562c657c9a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 23 Jan 2020 13:36:21 -0300 Subject: [PATCH 1/5] Copy docsite landing to readme (#2058) * Copy docsite landing to readme * Fix code sample * Apply suggestions from code review Co-Authored-By: Francisco Giordano * Update code sample Co-authored-by: Francisco Giordano --- README.md | 63 ++++++++++++++++++------------ docs/modules/ROOT/pages/index.adoc | 8 ++-- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 37be37a13..6874c2a30 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,27 @@ [![Build Status](https://circleci.com/gh/OpenZeppelin/openzeppelin-contracts.svg?style=shield)](https://circleci.com/gh/OpenZeppelin/openzeppelin-contracts) [![Coverage Status](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts/graph/badge.svg)](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts) -**OpenZeppelin Contracts is a library for secure smart contract development.** It provides implementations of standards like ERC20 and ERC721 which you can deploy as-is or extend to suit your needs, as well as Solidity components to build custom contracts and more complex decentralized systems. +**A library for secure smart contract development.** Build on a solid foundation of community-vetted code. -## Install + * Implementations of standards like [ERC20](https://docs.openzeppelin.com/contracts/erc20) and [ERC721](https://docs.openzeppelin.com/contracts/erc721). + * Flexible [role-based permissioning](https://docs.openzeppelin.com/contracts/access-control) scheme. + * Reusable [Solidity components](https://docs.openzeppelin.com/contracts/utilities) to build custom contracts and complex decentralized systems. + * First-class integration with the [Gas Station Network](https://docs.openzeppelin.com/contracts/gsn) for systems with no gas fees! + * Audited by leading security firms. -``` -npm install @openzeppelin/contracts +## Overview + +### Installation + +```console +$ npm install @openzeppelin/contracts ``` -OpenZeppelin Contracts features a stable API, which means your contracts won't break unexpectedly when upgrading to a newer minor version. You can read ṫhe details in our [API Stability] document. +OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/contracts/releases-stability#api-stability), which means your contracts won't break unexpectedly when upgrading to a newer minor version. -## Usage +### Usage -To write your custom contracts, import ours and extend them through inheritance. +Once installed, you can use the contracts in the library by importing them: ```solidity pragma solidity ^0.5.0; @@ -25,18 +33,35 @@ import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721Mintable.sol"; contract MyNFT is ERC721Full, ERC721Mintable { - constructor() ERC721Full("MyNFT", "MNFT") public { - } + constructor() ERC721Full("MyNFT", "MNFT") public { + } } ``` -> You need an ethereum development framework for the above import statements to work! Check out these guides for [OpenZeppelin CLI], [Truffle], [Embark] or [Buidler]. +_If you're new to smart contract development, head to [Developing Smart Contracts](https://docs.openzeppelin.com/contracts/learn::developing-smart-contracts) to learn about creating a new project and compiling your contracts._ -On our site you will find a few [guides] to learn about the different parts of OpenZeppelin, as well as [documentation for the API][API docs]. Keep in mind that the API docs are work in progress, and don’t hesitate to ask questions in [our forum][forum]. +To keep your system secure, you should **always** use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself. + +## Learn More + +The guides in the sidebar will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: + +* [Access Control](https://docs.openzeppelin.com/contracts/access-control): decide who can perform each of the actions on your system. +* [Tokens](https://docs.openzeppelin.com/contracts/tokens): create tradeable assets or collectives, and distribute them via [Crowdsales](https://docs.openzeppelin.com/contracts/crowdsales). +* [Gas Station Network](https://docs.openzeppelin.com/contracts/gsn): let your users interact with your contracts without having to pay for gas themselves. +* [Utilities](https://docs.openzeppelin.com/contracts/utilities): generic useful tools, including non-overflowing math, signature verification, and trustless paying systems. + +The [full API](https://docs.openzeppelin.com/contracts/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the [community forum](https://forum.openzeppelin.com). + +Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/guides), which cover several common use cases and good practices.. The following articles provide great background reading, though please note, some of the referenced tools have changed as the tooling in the ecosystem continues to rapidly evolve. + +* [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment. +* [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform. +* For a more in-depth dive, you may read the guide [Designing the Architecture for Your Ethereum Application](https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317), which discusses how to better structure your application and its relationship to the real world. ## Security -This project is maintained by [OpenZeppelin], and developed following our high standards for code quality and security. OpenZeppelin is meant to provide tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problems you might experience. +This project is maintained by [OpenZeppelin](https://openzeppelin.com), and developed following our high standards for code quality and security. OpenZeppelin is meant to provide tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problems you might experience. The core development principles and strategies that OpenZeppelin is based on include: security in depth, simple and modular code, clarity-driven naming conventions, comprehensive unit testing, pre-and-post-condition sanity checks, code consistency, and regular audits. @@ -46,20 +71,8 @@ Please report any security issues you find to security@openzeppelin.org. ## Contribute -OpenZeppelin exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide]! +OpenZeppelin exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide](CONTRIBUTING.md)! ## License OpenZeppelin is released under the [MIT License](LICENSE). - - -[API docs]: https://docs.openzeppelin.com/contracts/api/token/erc20 -[guides]: https://docs.openzeppelin.com/contracts -[API Stability]: https://docs.openzeppelin.com/contracts/releases-stability -[forum]: https://forum.openzeppelin.com -[OpenZeppelin]: https://openzeppelin.com -[contribution guide]: CONTRIBUTING.md -[OpenZeppelin CLI]: https://docs.openzeppelin.com/cli -[Truffle]: https://truffleframework.com/docs/truffle/quickstart -[Embark]: https://embark.status.im/docs/quick_start.html -[Buidler]: https://buidler.dev/getting-started/#overview diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 35a7292a7..f2c5eef15 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -28,10 +28,12 @@ Once installed, you can use the contracts in the library by importing them: ---- pragma solidity ^0.5.0; -import "@openzeppelin/contracts/ownership/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721Mintable.sol"; -contract MyContract is Ownable { - ... +contract MyNFT is ERC721Full, ERC721Mintable { + constructor() ERC721Full("MyNFT", "MNFT") public { + } } ---- From 8c40a5b27553f106115affd5ccdd69ebc8533de9 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 23 Jan 2020 15:08:54 -0300 Subject: [PATCH 2/5] Create2 feature pending tasks (#2013) * Add Create2 library (#1744) * feat(contracts): Add Create2 library to use create2 evm opcode * Upgrade sol-coverage * Add changelog entry * Update comments and code style * Remove create2 helper * Fix linter error * Fix truffle dependency * Fix linter error * refactor(Create2): Remove _deploy internal function * test(Create2): test Create2 with inline assembly code * fix(Create2): Check address returned form create2 instead of codesize of created contract * refactor(Create2):Add revert reason when Create2 deploy fails (#2062) * fix merge with master * fix test Co-authored-by: Augusto Lemble --- .solcover.js | 3 +- CHANGELOG.md | 1 + contracts/mocks/Create2Impl.sol | 23 +++++++++++ contracts/utils/Create2.sol | 47 ++++++++++++++++++++++ contracts/utils/README.adoc | 2 + test/utils/Create2.test.js | 71 +++++++++++++++++++++++++++++++++ 6 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 contracts/mocks/Create2Impl.sol create mode 100644 contracts/utils/Create2.sol create mode 100644 test/utils/Create2.test.js diff --git a/.solcover.js b/.solcover.js index 9e7285e1f..ca9a114a9 100644 --- a/.solcover.js +++ b/.solcover.js @@ -3,7 +3,6 @@ module.exports = { testCommand: 'npm test', compileCommand: 'npm run compile', skipFiles: [ - 'lifecycle/Migrations.sol', - 'mocks' + 'mocks', ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index d8bece08f..373e93fe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### New features * `SafeCast.toUintXX`: new library for integer downcasting, which allows for safe operation on smaller types (e.g. `uint32`) when combined with `SafeMath`. ([#1926](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1926)) * `ERC721Metadata`: added `baseURI`, which can be used for dramatic gas savings when all token URIs share a prefix (e.g. `http://api.myapp.com/tokens/`). ([#1970](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1970)) + * `Create2`: simple library to make usage of the `CREATE2` opcode easier. ([#1744](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1744)) ### Improvements * `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) diff --git a/contracts/mocks/Create2Impl.sol b/contracts/mocks/Create2Impl.sol new file mode 100644 index 000000000..de3a14f23 --- /dev/null +++ b/contracts/mocks/Create2Impl.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.5.0; + +import "../utils/Create2.sol"; +import "../token/ERC20/ERC20.sol"; + +contract Create2Impl { + function deploy(bytes32 salt, bytes memory code) public { + Create2.deploy(salt, code); + } + + function deployERC20(bytes32 salt) public { + // solhint-disable-next-line indent + Create2.deploy(salt, type(ERC20).creationCode); + } + + function computeAddress(bytes32 salt, bytes memory code) public view returns (address) { + return Create2.computeAddress(salt, code); + } + + function computeAddress(bytes32 salt, bytes memory code, address deployer) public pure returns (address) { + return Create2.computeAddress(salt, code, deployer); + } +} diff --git a/contracts/utils/Create2.sol b/contracts/utils/Create2.sol new file mode 100644 index 000000000..6cc0c9b29 --- /dev/null +++ b/contracts/utils/Create2.sol @@ -0,0 +1,47 @@ +pragma solidity ^0.5.0; + +/** + * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. + * `CREATE2` can be used to compute in advance the address where a smart + * contract will be deployed, which allows for interesting new mechanisms known + * as 'counterfactual interactions'. + * + * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more + * information. + */ +library Create2 { + /** + * @dev Deploys a contract using `CREATE2`. The address where the contract + * will be deployed can be known in advance via {computeAddress}. Note that + * a contract cannot be deployed twice using the same salt. + */ + function deploy(bytes32 salt, bytes memory bytecode) internal returns (address) { + address addr; + // solhint-disable-next-line no-inline-assembly + assembly { + addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt) + } + require(addr != address(0), "Create2: Failed on deploy"); + return addr; + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the `bytecode` + * or `salt` will result in a new destination address. + */ + function computeAddress(bytes32 salt, bytes memory bytecode) internal view returns (address) { + return computeAddress(salt, bytecode, address(this)); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at + * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. + */ + function computeAddress(bytes32 salt, bytes memory bytecodeHash, address deployer) internal pure returns (address) { + bytes32 bytecodeHashHash = keccak256(bytecodeHash); + bytes32 _data = keccak256( + abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHashHash) + ); + return address(bytes20(_data << 96)); + } +} diff --git a/contracts/utils/README.adoc b/contracts/utils/README.adoc index 229080211..52d2c413a 100644 --- a/contracts/utils/README.adoc +++ b/contracts/utils/README.adoc @@ -10,4 +10,6 @@ Miscellaneous contracts containing utility functions, often related to working w {{Arrays}} +{{Create2}} + {{ReentrancyGuard}} diff --git a/test/utils/Create2.test.js b/test/utils/Create2.test.js new file mode 100644 index 000000000..5df385573 --- /dev/null +++ b/test/utils/Create2.test.js @@ -0,0 +1,71 @@ +const { contract, accounts, web3 } = require('@openzeppelin/test-environment'); +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const Create2Impl = contract.fromArtifact('Create2Impl'); +const ERC20Mock = contract.fromArtifact('ERC20Mock'); +const ERC20 = contract.fromArtifact('ERC20'); + +describe('Create2', function () { + const [deployerAccount] = accounts; + + const salt = 'salt message'; + const saltHex = web3.utils.soliditySha3(salt); + const constructorByteCode = `${ERC20Mock.bytecode}${web3.eth.abi + .encodeParameters(['address', 'uint256'], [deployerAccount, 100]).slice(2) + }`; + + beforeEach(async function () { + this.factory = await Create2Impl.new(); + }); + + it('should compute the correct contract address', async function () { + const onChainComputed = await this.factory + .computeAddress(saltHex, constructorByteCode); + const offChainComputed = + computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('should compute the correct contract address with deployer', async function () { + const onChainComputed = await this.factory + .computeAddress(saltHex, constructorByteCode, deployerAccount); + const offChainComputed = + computeCreate2Address(saltHex, constructorByteCode, deployerAccount); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('should deploy a ERC20 from inline assembly code', async function () { + const offChainComputed = + computeCreate2Address(saltHex, ERC20.bytecode, this.factory.address); + await this.factory + .deploy(saltHex, ERC20.bytecode, { from: deployerAccount }); + expect(ERC20.bytecode).to.include((await web3.eth.getCode(offChainComputed)).slice(2)); + }); + + it('should deploy a ERC20Mock with correct balances', async function () { + const offChainComputed = + computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + await this.factory + .deploy(saltHex, constructorByteCode, { from: deployerAccount }); + const erc20 = await ERC20Mock.at(offChainComputed); + expect(await erc20.balanceOf(deployerAccount)).to.be.bignumber.equal(new BN(100)); + }); + + it('should failed deploying a contract in an existent address', async function () { + await this.factory.deploy(saltHex, constructorByteCode, { from: deployerAccount }); + await expectRevert( + this.factory.deploy(saltHex, constructorByteCode, { from: deployerAccount }), 'Create2: Failed on deploy' + ); + }); +}); + +function computeCreate2Address (saltHex, bytecode, deployer) { + return web3.utils.toChecksumAddress(`0x${web3.utils.sha3(`0x${[ + 'ff', + deployer, + saltHex, + web3.utils.soliditySha3(bytecode), + ].map(x => x.replace(/0x/, '')).join('')}`).slice(-40)}`); +} From e493fb3e953cbc5e4d03184feb9638a864e14644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 23 Jan 2020 15:26:25 -0300 Subject: [PATCH 3/5] Add 'available since' notes. Fixes #2054 --- contracts/token/ERC721/ERC721Metadata.sol | 2 ++ contracts/utils/Create2.sol | 2 ++ contracts/utils/SafeCast.sol | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC721/ERC721Metadata.sol b/contracts/token/ERC721/ERC721Metadata.sol index e0e516065..ca0ce4bf0 100644 --- a/contracts/token/ERC721/ERC721Metadata.sol +++ b/contracts/token/ERC721/ERC721Metadata.sol @@ -80,6 +80,8 @@ contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata { * @dev Returns the base URI set via {_setBaseURI}. This will be * automatically added as a preffix in {tokenURI} to each token's URI, when * they are non-empty. + * + * _Available since v2.5.0._ */ function baseURI() external view returns (string memory) { return _baseURI; diff --git a/contracts/utils/Create2.sol b/contracts/utils/Create2.sol index 6cc0c9b29..e055ea85b 100644 --- a/contracts/utils/Create2.sol +++ b/contracts/utils/Create2.sol @@ -8,6 +8,8 @@ pragma solidity ^0.5.0; * * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more * information. + * + * _Available since v2.5.0._ */ library Create2 { /** diff --git a/contracts/utils/SafeCast.sol b/contracts/utils/SafeCast.sol index 349825624..5846190e9 100644 --- a/contracts/utils/SafeCast.sol +++ b/contracts/utils/SafeCast.sol @@ -5,9 +5,9 @@ pragma solidity ^0.5.0; * @dev Wrappers over Solidity's uintXX casting operators with added overflow * checks. * - * Downcasting from uint256 in Solidity does not revert on overflow. This can + * Downcasting from uint256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually - * assume that overflows raise errors. `SafeCast` restores this intuition by + * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire @@ -15,6 +15,8 @@ pragma solidity ^0.5.0; * * Can be combined with {SafeMath} to extend it to smaller types, by performing * all math on `uint256` and then downcasting. + * + * _Available since v2.5.0._ */ library SafeCast { From 7d7cbcad14aa17b0202f67e7d8d619f1687c94a6 Mon Sep 17 00:00:00 2001 From: "Hao (Alan) Tang" Date: Thu, 23 Jan 2020 11:33:09 -0800 Subject: [PATCH 4/5] Fix/improve revert reason #1727 (#2018) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adding mock contacts, test code * adding changes to ERC721.sol per @frangio's comments on original PR #1943 * fix solhint warnings * Update contracts/token/ERC721/ERC721.sol Co-Authored-By: Francisco Giordano * same revert wording per @frangio's review suggestion * per @frangio's feedback, changing the inline assembly to accomplish: we want to ignore the first 4 bytes of content, so we should read the length and decrease it by 4, then take the memory location and add 4 to it, then store the new length at the new memory location, then that is the new byte array that we want. * change revert msg assembly per PR comment by @frangio * unify revert msg in test code * fix some failed tests, wording change * Update contracts/token/ERC721/ERC721.sol Co-Authored-By: Francisco Giordano * Update contracts/token/ERC721/ERC721.sol Co-Authored-By: Francisco Giordano * fix test case, revert without reason * fix 'ERC721ReceiverRevertsMock: Transaction rejected by receiver' * style change per review by @frangio * fix revert reason forwarding * remove duplicate contracts/mocks/ERC721ReceiverRevertsMock.sol per review https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018\#issuecomment-574381034 * Add changelog entry * Fix tests * Make tests more clear Co-authored-by: Francisco Giordano Co-authored-by: Nicolás Venturo --- CHANGELOG.md | 1 + contracts/token/ERC721/ERC721.sol | 25 ++++++++++++++++++++++--- test/token/ERC721/ERC721.behavior.js | 24 +++++++++++++----------- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 373e93fe5..ece6c2fbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Improvements * `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) * `ReentrancyGuard`: greatly improved gas efficiency by using the net gas metering mechanism introduced in the Istanbul hardfork. ([#1992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1992), [#1996](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1996)) + * `ERC721`: improved revert reason when transferring tokens to a non-recipient contract. ([#2018](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018)) ### Breaking changes * `ERC165Checker` now requires a minimum Solidity compiler version of 0.5.10. ([#1829](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1829)) diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index 57c96e3a5..67742b842 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -330,9 +330,28 @@ contract ERC721 is Context, ERC165, IERC721 { if (!to.isContract()) { return true; } - - bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data); - return (retval == _ERC721_RECEIVED); + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory returndata) = to.call(abi.encodeWithSelector( + IERC721Receiver(to).onERC721Received.selector, + _msgSender(), + from, + tokenId, + _data + )); + if (!success) { + if (returndata.length > 0) { + // solhint-disable-next-line no-inline-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } + } else { + bytes4 retval = abi.decode(returndata, (bytes4)); + return (retval == _ERC721_RECEIVED); + } } /** diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index 8d8b8a464..bca0fc924 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -4,8 +4,8 @@ const { expect } = require('chai'); const { ZERO_ADDRESS } = constants; const { shouldSupportInterfaces } = require('../../introspection/SupportsInterface.behavior'); -const ERC721ReceiverMock = contract.fromArtifact('ERC721ReceiverMock'); const ERC721Mock = contract.fromArtifact('ERC721Mock'); +const ERC721ReceiverMock = contract.fromArtifact('ERC721ReceiverMock'); function shouldBehaveLikeERC721 ( creator, @@ -307,9 +307,9 @@ function shouldBehaveLikeERC721 ( describe('to a receiver contract that throws', function () { it('reverts', async function () { - const invalidReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true); + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true); await expectRevert( - this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }), + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), 'ERC721ReceiverMock: reverting' ); }); @@ -317,9 +317,10 @@ function shouldBehaveLikeERC721 ( describe('to a contract that does not implement the required function', function () { it('reverts', async function () { - const invalidReceiver = this.token; - await expectRevert.unspecified( - this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }) + const nonReceiver = this.token; + await expectRevert( + this.token.safeTransferFrom(owner, nonReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer' ); }); }); @@ -369,9 +370,9 @@ function shouldBehaveLikeERC721 ( context('to a receiver contract that throws', function () { it('reverts', async function () { - const invalidReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true); + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, true); await expectRevert( - this.ERC721Mock.safeMint(invalidReceiver.address, tokenId), + this.ERC721Mock.safeMint(revertingReceiver.address, tokenId), 'ERC721ReceiverMock: reverting' ); }); @@ -379,9 +380,10 @@ function shouldBehaveLikeERC721 ( context('to a contract that does not implement the required function', function () { it('reverts', async function () { - const invalidReceiver = this.token; - await expectRevert.unspecified( - this.ERC721Mock.safeMint(invalidReceiver.address, tokenId) + const nonReceiver = this.token; + await expectRevert( + this.ERC721Mock.safeMint(nonReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer' ); }); }); From 73abd54cbe89a1b14313215349bbb9166fb00047 Mon Sep 17 00:00:00 2001 From: Mick de Graaf Date: Thu, 23 Jan 2020 20:35:21 +0100 Subject: [PATCH 5/5] Made private methods internal to allow for overriding (#2027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Made private methods internal to allow for overriding * Revert package.lock changes. * Make _move private again * Expose the ERC1820 registry address * Add changelog entry Co-authored-by: Nicolás Venturo --- CHANGELOG.md | 1 + contracts/token/ERC777/ERC777.sol | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ece6c2fbf..96bc804d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### Improvements * `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) * `ReentrancyGuard`: greatly improved gas efficiency by using the net gas metering mechanism introduced in the Istanbul hardfork. ([#1992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1992), [#1996](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1996)) + * `ERC777`: improve extensibility by making `_send` and related functions `internal`. ([#2027](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2027)) * `ERC721`: improved revert reason when transferring tokens to a non-recipient contract. ([#2018](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018)) ### Breaking changes diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index 694636109..2a91f25df 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -28,7 +28,7 @@ contract ERC777 is Context, IERC777, IERC20 { using SafeMath for uint256; using Address for address; - IERC1820Registry constant private ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + IERC1820Registry constant internal ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); mapping(address => uint256) private _balances; @@ -350,7 +350,7 @@ contract ERC777 is Context, IERC777, IERC20 { bytes memory operatorData, bool requireReceptionAck ) - private + internal { require(from != address(0), "ERC777: send from the zero address"); require(to != address(0), "ERC777: send to the zero address"); @@ -408,7 +408,7 @@ contract ERC777 is Context, IERC777, IERC20 { emit Transfer(from, to, amount); } - function _approve(address holder, address spender, uint256 value) private { + function _approve(address holder, address spender, uint256 value) internal { // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is // currently unnecessary. //require(holder != address(0), "ERC777: approve from the zero address"); @@ -435,7 +435,7 @@ contract ERC777 is Context, IERC777, IERC20 { bytes memory userData, bytes memory operatorData ) - private + internal { address implementer = ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH); if (implementer != address(0)) { @@ -463,7 +463,7 @@ contract ERC777 is Context, IERC777, IERC20 { bytes memory operatorData, bool requireReceptionAck ) - private + internal { address implementer = ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH); if (implementer != address(0)) {