From 2e0713becbdfb7a311213964140213f8dc282cd1 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 31 Aug 2018 16:13:07 -0300 Subject: [PATCH] Rename ERC interfaces to I prefix (#1252) * rename ERC20 to IERC20 * move ERC20.sol to IERC20.sol * rename StandardToken to ERC20 * rename StandardTokenMock to ERC20Mock * move StandardToken.sol to ERC20.sol, likewise test and mock files * rename MintableToken to ERC20Mintable * move MintableToken.sol to ERC20Mintable.sol, likewise test and mock files * rename BurnableToken to ERC20Burnable * move BurnableToken.sol to ERC20Burnable.sol, likewise for related files * rename CappedToken to ERC20Capped * move CappedToken.sol to ERC20Capped.sol, likewise for related files * rename PausableToken to ERC20Pausable * move PausableToken.sol to ERC20Pausable.sol, likewise for related files * rename DetailedERC20 to ERC20Detailed * move DetailedERC20.sol to ERC20Detailed.sol, likewise for related files * rename ERC721 to IERC721, and likewise for other related interfaces * move ERC721.sol to IERC721.sol, likewise for other 721 interfaces * rename ERC721Token to ERC721 * move ERC721Token.sol to ERC721.sol, likewise for related files * rename ERC721BasicToken to ERC721Basic * move ERC721BasicToken.sol to ERC721Basic.sol, likewise for related files * rename ERC721PausableToken to ERC721Pausable * move ERC721PausableToken.sol to ERC721Pausable.sol * rename ERC165 to IERC165 * move ERC165.sol to IERC165.sol * amend comment that ERC20 is based on FirstBlood * fix comments mentioning IERC721Receiver --- contracts/AutoIncrementing.sol | 2 +- contracts/crowdsale/Crowdsale.sol | 10 +- .../distribution/PostDeliveryCrowdsale.sol | 2 +- .../crowdsale/emission/AllowanceCrowdsale.sol | 4 +- .../crowdsale/emission/MintedCrowdsale.sol | 4 +- contracts/examples/SampleCrowdsale.sol | 6 +- contracts/examples/SimpleToken.sol | 6 +- .../introspection/{ERC165.sol => IERC165.sol} | 4 +- .../SupportsInterfaceWithLookup.sol | 4 +- contracts/lifecycle/TokenDestructible.sol | 4 +- contracts/mocks/AllowanceCrowdsaleImpl.sol | 4 +- contracts/mocks/CappedCrowdsaleImpl.sol | 4 +- contracts/mocks/DetailedERC20Mock.sol | 8 +- .../ERC165/ERC165InterfacesSupported.sol | 4 +- ...bleTokenMock.sol => ERC20BurnableMock.sol} | 4 +- .../{StandardTokenMock.sol => ERC20Mock.sol} | 6 +- ...bleTokenMock.sol => ERC20PausableMock.sol} | 6 +- contracts/mocks/ERC20WithMetadataMock.sol | 4 +- contracts/mocks/ERC223TokenMock.sol | 4 +- ...BasicTokenMock.sol => ERC721BasicMock.sol} | 6 +- .../{ERC721TokenMock.sol => ERC721Mock.sol} | 8 +- ...leTokenMock.sol => ERC721PausableMock.sol} | 6 +- contracts/mocks/ERC721ReceiverMock.sol | 4 +- contracts/mocks/FinalizableCrowdsaleImpl.sol | 4 +- .../mocks/IncreasingPriceCrowdsaleImpl.sol | 2 +- .../mocks/IndividuallyCappedCrowdsaleImpl.sol | 4 +- contracts/mocks/MintedCrowdsaleImpl.sol | 4 +- contracts/mocks/PostDeliveryCrowdsaleImpl.sol | 4 +- contracts/mocks/RBACCappedTokenMock.sol | 6 +- contracts/mocks/RefundableCrowdsaleImpl.sol | 4 +- contracts/mocks/SafeERC20Helper.sol | 12 +- contracts/mocks/TimedCrowdsaleImpl.sol | 4 +- contracts/mocks/WhitelistedCrowdsaleImpl.sol | 4 +- contracts/ownership/CanReclaimToken.sol | 6 +- contracts/proposals/ERC1046/TokenMetadata.sol | 6 +- contracts/token/ERC20/ERC20.sol | 213 +++++++++-- .../{BurnableToken.sol => ERC20Burnable.sol} | 6 +- .../{CappedToken.sol => ERC20Capped.sol} | 4 +- .../{DetailedERC20.sol => ERC20Detailed.sol} | 6 +- .../{MintableToken.sol => ERC20Mintable.sol} | 4 +- .../{PausableToken.sol => ERC20Pausable.sol} | 6 +- contracts/token/ERC20/IERC20.sol | 35 ++ contracts/token/ERC20/RBACMintableToken.sol | 4 +- contracts/token/ERC20/SafeERC20.sol | 8 +- contracts/token/ERC20/StandardToken.sol | 204 ----------- contracts/token/ERC20/TokenTimelock.sol | 6 +- contracts/token/ERC20/TokenVesting.sol | 10 +- contracts/token/ERC721/ERC721.sol | 203 +++++++++-- contracts/token/ERC721/ERC721Basic.sol | 344 +++++++++++++++--- contracts/token/ERC721/ERC721BasicToken.sol | 310 ---------------- contracts/token/ERC721/ERC721Holder.sol | 4 +- ...21PausableToken.sol => ERC721Pausable.sol} | 6 +- contracts/token/ERC721/ERC721Token.sol | 201 ---------- ...ecatedERC721.sol => IDeprecatedERC721.sol} | 4 +- contracts/token/ERC721/IERC721.sol | 40 ++ contracts/token/ERC721/IERC721Basic.sol | 80 ++++ ...ERC721Receiver.sol => IERC721Receiver.sol} | 4 +- test/crowdsale/FinalizableCrowdsale.test.js | 4 +- test/crowdsale/MintedCrowdsale.test.js | 10 +- test/lifecycle/TokenDestructible.test.js | 4 +- test/ownership/CanReclaimToken.test.js | 4 +- test/token/ERC20/BurnableToken.test.js | 12 - test/token/ERC20/CappedToken.test.js | 25 -- test/token/ERC20/DetailedERC20.test.js | 6 +- .../{StandardToken.test.js => ERC20.test.js} | 6 +- ....behavior.js => ERC20Burnable.behavior.js} | 4 +- test/token/ERC20/ERC20Burnable.test.js | 12 + ...en.behavior.js => ERC20Capped.behavior.js} | 4 +- test/token/ERC20/ERC20Capped.test.js | 25 ++ ....behavior.js => ERC20Mintable.behavior.js} | 4 +- test/token/ERC20/ERC20Mintable.test.js | 10 + ...bleToken.test.js => ERC20Pausable.test.js} | 6 +- test/token/ERC20/MintableToken.test.js | 10 - test/token/ERC20/RBACCappedToken.test.js | 8 +- test/token/ERC20/RBACMintableToken.test.js | 4 +- test/token/ERC20/TokenTimelock.test.js | 4 +- test/token/ERC20/TokenVesting.test.js | 4 +- .../{ERC721Token.test.js => ERC721.test.js} | 14 +- ...en.behavior.js => ERC721Basic.behavior.js} | 6 +- test/token/ERC721/ERC721Basic.test.js | 18 + test/token/ERC721/ERC721BasicToken.test.js | 18 - test/token/ERC721/ERC721MintBurn.behavior.js | 6 +- ...leToken.test.js => ERC721Pausable.test.js} | 12 +- .../ERC721/ERC721PausedToken.behavior.js | 2 +- 84 files changed, 1059 insertions(+), 1059 deletions(-) rename contracts/introspection/{ERC165.sol => IERC165.sol} (92%) rename contracts/mocks/{BurnableTokenMock.sol => ERC20BurnableMock.sol} (63%) rename contracts/mocks/{StandardTokenMock.sol => ERC20Mock.sol} (78%) rename contracts/mocks/{PausableTokenMock.sol => ERC20PausableMock.sol} (55%) rename contracts/mocks/{ERC721BasicTokenMock.sol => ERC721BasicMock.sol} (70%) rename contracts/mocks/{ERC721TokenMock.sol => ERC721Mock.sol} (84%) rename contracts/mocks/{ERC721PausableTokenMock.sol => ERC721PausableMock.sol} (74%) rename contracts/token/ERC20/{BurnableToken.sol => ERC20Burnable.sol} (85%) rename contracts/token/ERC20/{CappedToken.sol => ERC20Capped.sol} (89%) rename contracts/token/ERC20/{DetailedERC20.sol => ERC20Detailed.sol} (83%) rename contracts/token/ERC20/{MintableToken.sol => ERC20Mintable.sol} (93%) rename contracts/token/ERC20/{PausableToken.sol => ERC20Pausable.sol} (88%) create mode 100644 contracts/token/ERC20/IERC20.sol delete mode 100644 contracts/token/ERC20/StandardToken.sol delete mode 100644 contracts/token/ERC721/ERC721BasicToken.sol rename contracts/token/ERC721/{ERC721PausableToken.sol => ERC721Pausable.sol} (79%) delete mode 100644 contracts/token/ERC721/ERC721Token.sol rename contracts/token/ERC721/{DeprecatedERC721.sol => IDeprecatedERC721.sol} (88%) create mode 100644 contracts/token/ERC721/IERC721.sol create mode 100644 contracts/token/ERC721/IERC721Basic.sol rename contracts/token/ERC721/{ERC721Receiver.sol => IERC721Receiver.sol} (92%) delete mode 100644 test/token/ERC20/BurnableToken.test.js delete mode 100644 test/token/ERC20/CappedToken.test.js rename test/token/ERC20/{StandardToken.test.js => ERC20.test.js} (99%) rename test/token/ERC20/{BurnableToken.behavior.js => ERC20Burnable.behavior.js} (97%) create mode 100644 test/token/ERC20/ERC20Burnable.test.js rename test/token/ERC20/{CappedToken.behavior.js => ERC20Capped.behavior.js} (91%) create mode 100644 test/token/ERC20/ERC20Capped.test.js rename test/token/ERC20/{MintableToken.behavior.js => ERC20Mintable.behavior.js} (98%) create mode 100644 test/token/ERC20/ERC20Mintable.test.js rename test/token/ERC20/{PausableToken.test.js => ERC20Pausable.test.js} (97%) delete mode 100644 test/token/ERC20/MintableToken.test.js rename test/token/ERC721/{ERC721Token.test.js => ERC721.test.js} (94%) rename test/token/ERC721/{ERC721BasicToken.behavior.js => ERC721Basic.behavior.js} (99%) create mode 100644 test/token/ERC721/ERC721Basic.test.js delete mode 100644 test/token/ERC721/ERC721BasicToken.test.js rename test/token/ERC721/{ERC721PausableToken.test.js => ERC721Pausable.test.js} (61%) diff --git a/contracts/AutoIncrementing.sol b/contracts/AutoIncrementing.sol index cf46e2f57fc..8c01861fb68 100644 --- a/contracts/AutoIncrementing.sol +++ b/contracts/AutoIncrementing.sol @@ -5,7 +5,7 @@ pragma solidity ^0.4.24; * @title AutoIncrementing * @author Matt Condon (@shrugs) * @dev Provides an auto-incrementing uint256 id acquired by the `Counter#nextId` getter. - * Use this for issuing ERC721Token ids or keeping track of request ids, anything you want, really. + * Use this for issuing ERC721 ids or keeping track of request ids, anything you want, really. * * Include with `using AutoIncrementing for AutoIncrementing.Counter;` * @notice Does not allow an Id of 0, which is popularly used to signify a null state in solidity. diff --git a/contracts/crowdsale/Crowdsale.sol b/contracts/crowdsale/Crowdsale.sol index 9e219a304f9..8bf055ada87 100644 --- a/contracts/crowdsale/Crowdsale.sol +++ b/contracts/crowdsale/Crowdsale.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../math/SafeMath.sol"; import "../token/ERC20/SafeERC20.sol"; @@ -19,17 +19,17 @@ import "../token/ERC20/SafeERC20.sol"; */ contract Crowdsale { using SafeMath for uint256; - using SafeERC20 for ERC20; + using SafeERC20 for IERC20; // The token being sold - ERC20 public token; + IERC20 public token; // Address where funds are collected address public wallet; // How many token units a buyer gets per wei. // The rate is the conversion between wei and the smallest and indivisible token unit. - // So, if you are using a rate of 1 with a DetailedERC20 token with 3 decimals called TOK + // So, if you are using a rate of 1 with a ERC20Detailed token with 3 decimals called TOK // 1 wei will give you 1 unit, or 0.001 TOK. uint256 public rate; @@ -55,7 +55,7 @@ contract Crowdsale { * @param _wallet Address where collected funds will be forwarded to * @param _token Address of the token being sold */ - constructor(uint256 _rate, address _wallet, ERC20 _token) public { + constructor(uint256 _rate, address _wallet, IERC20 _token) public { require(_rate > 0); require(_wallet != address(0)); require(_token != address(0)); diff --git a/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol b/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol index 652f21e5d74..b09d09709a5 100644 --- a/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol +++ b/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "../validation/TimedCrowdsale.sol"; -import "../../token/ERC20/ERC20.sol"; +import "../../token/ERC20/IERC20.sol"; import "../../math/SafeMath.sol"; diff --git a/contracts/crowdsale/emission/AllowanceCrowdsale.sol b/contracts/crowdsale/emission/AllowanceCrowdsale.sol index 4b0665cba20..4e48638ab74 100644 --- a/contracts/crowdsale/emission/AllowanceCrowdsale.sol +++ b/contracts/crowdsale/emission/AllowanceCrowdsale.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "../Crowdsale.sol"; -import "../../token/ERC20/ERC20.sol"; +import "../../token/ERC20/IERC20.sol"; import "../../token/ERC20/SafeERC20.sol"; import "../../math/SafeMath.sol"; @@ -12,7 +12,7 @@ import "../../math/SafeMath.sol"; */ contract AllowanceCrowdsale is Crowdsale { using SafeMath for uint256; - using SafeERC20 for ERC20; + using SafeERC20 for IERC20; address public tokenWallet; diff --git a/contracts/crowdsale/emission/MintedCrowdsale.sol b/contracts/crowdsale/emission/MintedCrowdsale.sol index 0db3a7436cd..9f3a8b4b115 100644 --- a/contracts/crowdsale/emission/MintedCrowdsale.sol +++ b/contracts/crowdsale/emission/MintedCrowdsale.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "../Crowdsale.sol"; -import "../../token/ERC20/MintableToken.sol"; +import "../../token/ERC20/ERC20Mintable.sol"; /** @@ -23,6 +23,6 @@ contract MintedCrowdsale is Crowdsale { internal { // Potentially dangerous assumption about the type of the token. - require(MintableToken(address(token)).mint(_beneficiary, _tokenAmount)); + require(ERC20Mintable(address(token)).mint(_beneficiary, _tokenAmount)); } } diff --git a/contracts/examples/SampleCrowdsale.sol b/contracts/examples/SampleCrowdsale.sol index 0a3f1042edf..564c6a0873e 100644 --- a/contracts/examples/SampleCrowdsale.sol +++ b/contracts/examples/SampleCrowdsale.sol @@ -3,7 +3,7 @@ pragma solidity ^0.4.24; import "../crowdsale/validation/CappedCrowdsale.sol"; import "../crowdsale/distribution/RefundableCrowdsale.sol"; import "../crowdsale/emission/MintedCrowdsale.sol"; -import "../token/ERC20/MintableToken.sol"; +import "../token/ERC20/ERC20Mintable.sol"; /** @@ -11,7 +11,7 @@ import "../token/ERC20/MintableToken.sol"; * @dev Very simple ERC20 Token that can be minted. * It is meant to be used in a crowdsale contract. */ -contract SampleCrowdsaleToken is MintableToken { +contract SampleCrowdsaleToken is ERC20Mintable { string public constant name = "Sample Crowdsale Token"; string public constant symbol = "SCT"; @@ -44,7 +44,7 @@ contract SampleCrowdsale is CappedCrowdsale, RefundableCrowdsale, MintedCrowdsal uint256 _rate, address _wallet, uint256 _cap, - MintableToken _token, + ERC20Mintable _token, uint256 _goal ) public diff --git a/contracts/examples/SimpleToken.sol b/contracts/examples/SimpleToken.sol index 73df121dd8f..67de00ca420 100644 --- a/contracts/examples/SimpleToken.sol +++ b/contracts/examples/SimpleToken.sol @@ -1,16 +1,16 @@ pragma solidity ^0.4.24; -import "../token/ERC20/StandardToken.sol"; +import "../token/ERC20/ERC20.sol"; /** * @title SimpleToken * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator. * Note they can later distribute these tokens as they wish using `transfer` and other - * `StandardToken` functions. + * `ERC20` functions. */ -contract SimpleToken is StandardToken { +contract SimpleToken is ERC20 { string public constant name = "SimpleToken"; string public constant symbol = "SIM"; diff --git a/contracts/introspection/ERC165.sol b/contracts/introspection/IERC165.sol similarity index 92% rename from contracts/introspection/ERC165.sol rename to contracts/introspection/IERC165.sol index 06f20a074b4..f3361f0a46d 100644 --- a/contracts/introspection/ERC165.sol +++ b/contracts/introspection/IERC165.sol @@ -2,10 +2,10 @@ pragma solidity ^0.4.24; /** - * @title ERC165 + * @title IERC165 * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md */ -interface ERC165 { +interface IERC165 { /** * @notice Query if a contract implements an interface diff --git a/contracts/introspection/SupportsInterfaceWithLookup.sol b/contracts/introspection/SupportsInterfaceWithLookup.sol index 20a00088c11..c2b009aea0f 100644 --- a/contracts/introspection/SupportsInterfaceWithLookup.sol +++ b/contracts/introspection/SupportsInterfaceWithLookup.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./ERC165.sol"; +import "./IERC165.sol"; /** @@ -8,7 +8,7 @@ import "./ERC165.sol"; * @author Matt Condon (@shrugs) * @dev Implements ERC165 using a lookup table. */ -contract SupportsInterfaceWithLookup is ERC165 { +contract SupportsInterfaceWithLookup is IERC165 { bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7; /** diff --git a/contracts/lifecycle/TokenDestructible.sol b/contracts/lifecycle/TokenDestructible.sol index 38aabcbb18a..783a4e7887b 100644 --- a/contracts/lifecycle/TokenDestructible.sol +++ b/contracts/lifecycle/TokenDestructible.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "../ownership/Ownable.sol"; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; /** @@ -25,7 +25,7 @@ contract TokenDestructible is Ownable { // Transfer tokens to owner for (uint256 i = 0; i < _tokens.length; i++) { - ERC20 token = ERC20(_tokens[i]); + IERC20 token = IERC20(_tokens[i]); uint256 balance = token.balanceOf(this); token.transfer(owner, balance); } diff --git a/contracts/mocks/AllowanceCrowdsaleImpl.sol b/contracts/mocks/AllowanceCrowdsaleImpl.sol index 5c179d2deb6..872dd66e193 100644 --- a/contracts/mocks/AllowanceCrowdsaleImpl.sol +++ b/contracts/mocks/AllowanceCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../crowdsale/emission/AllowanceCrowdsale.sol"; @@ -9,7 +9,7 @@ contract AllowanceCrowdsaleImpl is AllowanceCrowdsale { constructor ( uint256 _rate, address _wallet, - ERC20 _token, + IERC20 _token, address _tokenWallet ) public diff --git a/contracts/mocks/CappedCrowdsaleImpl.sol b/contracts/mocks/CappedCrowdsaleImpl.sol index a43c8b4176c..a05fbd7d25f 100644 --- a/contracts/mocks/CappedCrowdsaleImpl.sol +++ b/contracts/mocks/CappedCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../crowdsale/validation/CappedCrowdsale.sol"; @@ -9,7 +9,7 @@ contract CappedCrowdsaleImpl is CappedCrowdsale { constructor ( uint256 _rate, address _wallet, - ERC20 _token, + IERC20 _token, uint256 _cap ) public diff --git a/contracts/mocks/DetailedERC20Mock.sol b/contracts/mocks/DetailedERC20Mock.sol index a4f17529aab..e9aab88e95d 100644 --- a/contracts/mocks/DetailedERC20Mock.sol +++ b/contracts/mocks/DetailedERC20Mock.sol @@ -1,16 +1,16 @@ pragma solidity ^0.4.24; -import "../token/ERC20/StandardToken.sol"; -import "../token/ERC20/DetailedERC20.sol"; +import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/ERC20Detailed.sol"; -contract DetailedERC20Mock is StandardToken, DetailedERC20 { +contract ERC20DetailedMock is ERC20, ERC20Detailed { constructor( string _name, string _symbol, uint8 _decimals ) - DetailedERC20(_name, _symbol, _decimals) + ERC20Detailed(_name, _symbol, _decimals) public {} } diff --git a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol index be07f947c74..9f472b64825 100644 --- a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol +++ b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../../introspection/ERC165.sol"; +import "../../introspection/IERC165.sol"; /** @@ -11,7 +11,7 @@ import "../../introspection/ERC165.sol"; * therefore, because this contract is staticcall'd we need to not emit events (which is how solidity-coverage works) * solidity-coverage ignores the /mocks folder, so we duplicate its implementation here to avoid instrumenting it */ -contract SupportsInterfaceWithLookupMock is ERC165 { +contract SupportsInterfaceWithLookupMock is IERC165 { bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7; /** diff --git a/contracts/mocks/BurnableTokenMock.sol b/contracts/mocks/ERC20BurnableMock.sol similarity index 63% rename from contracts/mocks/BurnableTokenMock.sol rename to contracts/mocks/ERC20BurnableMock.sol index a148f17f47e..79819b748c7 100644 --- a/contracts/mocks/BurnableTokenMock.sol +++ b/contracts/mocks/ERC20BurnableMock.sol @@ -1,9 +1,9 @@ pragma solidity ^0.4.24; -import "../token/ERC20/BurnableToken.sol"; +import "../token/ERC20/ERC20Burnable.sol"; -contract BurnableTokenMock is BurnableToken { +contract ERC20BurnableMock is ERC20Burnable { constructor(address _initialAccount, uint256 _initialBalance) public { _mint(_initialAccount, _initialBalance); diff --git a/contracts/mocks/StandardTokenMock.sol b/contracts/mocks/ERC20Mock.sol similarity index 78% rename from contracts/mocks/StandardTokenMock.sol rename to contracts/mocks/ERC20Mock.sol index e4420c470bc..600169743b3 100644 --- a/contracts/mocks/StandardTokenMock.sol +++ b/contracts/mocks/ERC20Mock.sol @@ -1,10 +1,10 @@ pragma solidity ^0.4.24; -import "../token/ERC20/StandardToken.sol"; +import "../token/ERC20/ERC20.sol"; -// mock class using StandardToken -contract StandardTokenMock is StandardToken { +// mock class using ERC20 +contract ERC20Mock is ERC20 { constructor(address _initialAccount, uint256 _initialBalance) public { _mint(_initialAccount, _initialBalance); diff --git a/contracts/mocks/PausableTokenMock.sol b/contracts/mocks/ERC20PausableMock.sol similarity index 55% rename from contracts/mocks/PausableTokenMock.sol rename to contracts/mocks/ERC20PausableMock.sol index 24ef281bade..a60f8a12da6 100644 --- a/contracts/mocks/PausableTokenMock.sol +++ b/contracts/mocks/ERC20PausableMock.sol @@ -1,10 +1,10 @@ pragma solidity ^0.4.24; -import "../token/ERC20/PausableToken.sol"; +import "../token/ERC20/ERC20Pausable.sol"; -// mock class using PausableToken -contract PausableTokenMock is PausableToken { +// mock class using ERC20Pausable +contract ERC20PausableMock is ERC20Pausable { constructor(address _initialAccount, uint _initialBalance) public { _mint(_initialAccount, _initialBalance); diff --git a/contracts/mocks/ERC20WithMetadataMock.sol b/contracts/mocks/ERC20WithMetadataMock.sol index 6e102bbacac..025f154ab64 100644 --- a/contracts/mocks/ERC20WithMetadataMock.sol +++ b/contracts/mocks/ERC20WithMetadataMock.sol @@ -1,10 +1,10 @@ pragma solidity ^0.4.21; -import "../token/ERC20/StandardToken.sol"; +import "../token/ERC20/ERC20.sol"; import "../proposals/ERC1046/TokenMetadata.sol"; -contract ERC20WithMetadataMock is StandardToken, ERC20WithMetadata { +contract ERC20WithMetadataMock is ERC20, ERC20WithMetadata { constructor(string _tokenURI) public ERC20WithMetadata(_tokenURI) { diff --git a/contracts/mocks/ERC223TokenMock.sol b/contracts/mocks/ERC223TokenMock.sol index 2f92bc5f1f4..de3dec54456 100644 --- a/contracts/mocks/ERC223TokenMock.sol +++ b/contracts/mocks/ERC223TokenMock.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/StandardToken.sol"; +import "../token/ERC20/ERC20.sol"; contract ERC223ContractInterface { @@ -8,7 +8,7 @@ contract ERC223ContractInterface { } -contract ERC223TokenMock is StandardToken { +contract ERC223TokenMock is ERC20 { constructor(address _initialAccount, uint256 _initialBalance) public { _mint(_initialAccount, _initialBalance); diff --git a/contracts/mocks/ERC721BasicTokenMock.sol b/contracts/mocks/ERC721BasicMock.sol similarity index 70% rename from contracts/mocks/ERC721BasicTokenMock.sol rename to contracts/mocks/ERC721BasicMock.sol index 704728198d6..87add3adb7e 100644 --- a/contracts/mocks/ERC721BasicTokenMock.sol +++ b/contracts/mocks/ERC721BasicMock.sol @@ -1,13 +1,13 @@ pragma solidity ^0.4.24; -import "../token/ERC721/ERC721BasicToken.sol"; +import "../token/ERC721/ERC721Basic.sol"; /** - * @title ERC721BasicTokenMock + * @title ERC721BasicMock * This mock just provides a public mint and burn functions for testing purposes */ -contract ERC721BasicTokenMock is ERC721BasicToken { +contract ERC721BasicMock is ERC721Basic { function mint(address _to, uint256 _tokenId) public { super._mint(_to, _tokenId); } diff --git a/contracts/mocks/ERC721TokenMock.sol b/contracts/mocks/ERC721Mock.sol similarity index 84% rename from contracts/mocks/ERC721TokenMock.sol rename to contracts/mocks/ERC721Mock.sol index a16f16f3b96..8c4b0373f15 100644 --- a/contracts/mocks/ERC721TokenMock.sol +++ b/contracts/mocks/ERC721Mock.sol @@ -1,16 +1,16 @@ pragma solidity ^0.4.24; -import "../token/ERC721/ERC721Token.sol"; +import "../token/ERC721/ERC721.sol"; /** - * @title ERC721TokenMock + * @title ERC721Mock * This mock just provides a public mint and burn functions for testing purposes, * and a public setter for metadata URI */ -contract ERC721TokenMock is ERC721Token { +contract ERC721Mock is ERC721 { constructor(string name, string symbol) public - ERC721Token(name, symbol) + ERC721(name, symbol) { } function mint(address _to, uint256 _tokenId) public { diff --git a/contracts/mocks/ERC721PausableTokenMock.sol b/contracts/mocks/ERC721PausableMock.sol similarity index 74% rename from contracts/mocks/ERC721PausableTokenMock.sol rename to contracts/mocks/ERC721PausableMock.sol index b48608114b4..ef2722f4ace 100644 --- a/contracts/mocks/ERC721PausableTokenMock.sol +++ b/contracts/mocks/ERC721PausableMock.sol @@ -1,13 +1,13 @@ pragma solidity ^0.4.24; -import "../token/ERC721/ERC721PausableToken.sol"; +import "../token/ERC721/ERC721Pausable.sol"; /** - * @title ERC721PausableTokenMock + * @title ERC721PausableMock * This mock just provides a public mint, burn and exists functions for testing purposes */ -contract ERC721PausableTokenMock is ERC721PausableToken { +contract ERC721PausableMock is ERC721Pausable { function mint(address _to, uint256 _tokenId) public { super._mint(_to, _tokenId); } diff --git a/contracts/mocks/ERC721ReceiverMock.sol b/contracts/mocks/ERC721ReceiverMock.sol index 82b8a2610dc..cfe73a2e293 100644 --- a/contracts/mocks/ERC721ReceiverMock.sol +++ b/contracts/mocks/ERC721ReceiverMock.sol @@ -1,9 +1,9 @@ pragma solidity ^0.4.24; -import "../token/ERC721/ERC721Receiver.sol"; +import "../token/ERC721/IERC721Receiver.sol"; -contract ERC721ReceiverMock is ERC721Receiver { +contract ERC721ReceiverMock is IERC721Receiver { bytes4 retval_; bool reverts_; diff --git a/contracts/mocks/FinalizableCrowdsaleImpl.sol b/contracts/mocks/FinalizableCrowdsaleImpl.sol index 8321bdb9926..aa419b82211 100644 --- a/contracts/mocks/FinalizableCrowdsaleImpl.sol +++ b/contracts/mocks/FinalizableCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/MintableToken.sol"; +import "../token/ERC20/ERC20Mintable.sol"; import "../crowdsale/distribution/FinalizableCrowdsale.sol"; @@ -11,7 +11,7 @@ contract FinalizableCrowdsaleImpl is FinalizableCrowdsale { uint256 _closingTime, uint256 _rate, address _wallet, - MintableToken _token + ERC20Mintable _token ) public Crowdsale(_rate, _wallet, _token) diff --git a/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol b/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol index 286eb616c89..95e4e367c54 100644 --- a/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol +++ b/contracts/mocks/IncreasingPriceCrowdsaleImpl.sol @@ -10,7 +10,7 @@ contract IncreasingPriceCrowdsaleImpl is IncreasingPriceCrowdsale { uint256 _openingTime, uint256 _closingTime, address _wallet, - ERC20 _token, + IERC20 _token, uint256 _initialRate, uint256 _finalRate ) diff --git a/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol b/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol index b796060ed07..b4b470f7ca6 100644 --- a/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol +++ b/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../crowdsale/validation/IndividuallyCappedCrowdsale.sol"; @@ -9,7 +9,7 @@ contract IndividuallyCappedCrowdsaleImpl is IndividuallyCappedCrowdsale { constructor ( uint256 _rate, address _wallet, - ERC20 _token + IERC20 _token ) public Crowdsale(_rate, _wallet, _token) diff --git a/contracts/mocks/MintedCrowdsaleImpl.sol b/contracts/mocks/MintedCrowdsaleImpl.sol index b776db3e044..77e3430b52e 100644 --- a/contracts/mocks/MintedCrowdsaleImpl.sol +++ b/contracts/mocks/MintedCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/MintableToken.sol"; +import "../token/ERC20/ERC20Mintable.sol"; import "../crowdsale/emission/MintedCrowdsale.sol"; @@ -9,7 +9,7 @@ contract MintedCrowdsaleImpl is MintedCrowdsale { constructor ( uint256 _rate, address _wallet, - MintableToken _token + ERC20Mintable _token ) public Crowdsale(_rate, _wallet, _token) diff --git a/contracts/mocks/PostDeliveryCrowdsaleImpl.sol b/contracts/mocks/PostDeliveryCrowdsaleImpl.sol index add2d866b01..b4dea2700e5 100644 --- a/contracts/mocks/PostDeliveryCrowdsaleImpl.sol +++ b/contracts/mocks/PostDeliveryCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../crowdsale/distribution/PostDeliveryCrowdsale.sol"; @@ -11,7 +11,7 @@ contract PostDeliveryCrowdsaleImpl is PostDeliveryCrowdsale { uint256 _closingTime, uint256 _rate, address _wallet, - ERC20 _token + IERC20 _token ) public TimedCrowdsale(_openingTime, _closingTime) diff --git a/contracts/mocks/RBACCappedTokenMock.sol b/contracts/mocks/RBACCappedTokenMock.sol index bf4ff8f2d6a..8d182c6e5be 100644 --- a/contracts/mocks/RBACCappedTokenMock.sol +++ b/contracts/mocks/RBACCappedTokenMock.sol @@ -1,12 +1,12 @@ pragma solidity ^0.4.24; import "../token/ERC20/RBACMintableToken.sol"; -import "../token/ERC20/CappedToken.sol"; +import "../token/ERC20/ERC20Capped.sol"; -contract RBACCappedTokenMock is CappedToken, RBACMintableToken { +contract RBACCappedTokenMock is ERC20Capped, RBACMintableToken { constructor(uint256 _cap) - CappedToken(_cap) + ERC20Capped(_cap) public {} } diff --git a/contracts/mocks/RefundableCrowdsaleImpl.sol b/contracts/mocks/RefundableCrowdsaleImpl.sol index b4ff6040a12..b581031bfd5 100644 --- a/contracts/mocks/RefundableCrowdsaleImpl.sol +++ b/contracts/mocks/RefundableCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/MintableToken.sol"; +import "../token/ERC20/ERC20Mintable.sol"; import "../crowdsale/distribution/RefundableCrowdsale.sol"; @@ -11,7 +11,7 @@ contract RefundableCrowdsaleImpl is RefundableCrowdsale { uint256 _closingTime, uint256 _rate, address _wallet, - MintableToken _token, + ERC20Mintable _token, uint256 _goal ) public diff --git a/contracts/mocks/SafeERC20Helper.sol b/contracts/mocks/SafeERC20Helper.sol index 60254af7c7d..d64d7c0deb2 100644 --- a/contracts/mocks/SafeERC20Helper.sol +++ b/contracts/mocks/SafeERC20Helper.sol @@ -1,10 +1,10 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../token/ERC20/SafeERC20.sol"; -contract ERC20FailingMock is ERC20 { +contract ERC20FailingMock is IERC20 { function totalSupply() public view returns (uint256) { return 0; } @@ -31,7 +31,7 @@ contract ERC20FailingMock is ERC20 { } -contract ERC20SucceedingMock is ERC20 { +contract ERC20SucceedingMock is IERC20 { function totalSupply() public view returns (uint256) { return 0; } @@ -59,10 +59,10 @@ contract ERC20SucceedingMock is ERC20 { contract SafeERC20Helper { - using SafeERC20 for ERC20; + using SafeERC20 for IERC20; - ERC20 failing; - ERC20 succeeding; + IERC20 failing; + IERC20 succeeding; constructor() public { failing = new ERC20FailingMock(); diff --git a/contracts/mocks/TimedCrowdsaleImpl.sol b/contracts/mocks/TimedCrowdsaleImpl.sol index 9e9c17486d8..b99178aee7c 100644 --- a/contracts/mocks/TimedCrowdsaleImpl.sol +++ b/contracts/mocks/TimedCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../crowdsale/validation/TimedCrowdsale.sol"; @@ -11,7 +11,7 @@ contract TimedCrowdsaleImpl is TimedCrowdsale { uint256 _closingTime, uint256 _rate, address _wallet, - ERC20 _token + IERC20 _token ) public Crowdsale(_rate, _wallet, _token) diff --git a/contracts/mocks/WhitelistedCrowdsaleImpl.sol b/contracts/mocks/WhitelistedCrowdsaleImpl.sol index 4cfd739ec40..25cd5118aea 100644 --- a/contracts/mocks/WhitelistedCrowdsaleImpl.sol +++ b/contracts/mocks/WhitelistedCrowdsaleImpl.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../crowdsale/validation/WhitelistedCrowdsale.sol"; import "../crowdsale/Crowdsale.sol"; @@ -10,7 +10,7 @@ contract WhitelistedCrowdsaleImpl is Crowdsale, WhitelistedCrowdsale { constructor ( uint256 _rate, address _wallet, - ERC20 _token + IERC20 _token ) Crowdsale(_rate, _wallet, _token) public diff --git a/contracts/ownership/CanReclaimToken.sol b/contracts/ownership/CanReclaimToken.sol index 37a78918cfb..858a1db84e8 100644 --- a/contracts/ownership/CanReclaimToken.sol +++ b/contracts/ownership/CanReclaimToken.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "./Ownable.sol"; -import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/IERC20.sol"; import "../token/ERC20/SafeERC20.sol"; @@ -12,13 +12,13 @@ import "../token/ERC20/SafeERC20.sol"; * This will prevent any accidental loss of tokens. */ contract CanReclaimToken is Ownable { - using SafeERC20 for ERC20; + using SafeERC20 for IERC20; /** * @dev Reclaim all ERC20 compatible tokens * @param _token ERC20 The address of the token contract */ - function reclaimToken(ERC20 _token) external onlyOwner { + function reclaimToken(IERC20 _token) external onlyOwner { uint256 balance = _token.balanceOf(this); _token.safeTransfer(owner, balance); } diff --git a/contracts/proposals/ERC1046/TokenMetadata.sol b/contracts/proposals/ERC1046/TokenMetadata.sol index 38edbd06419..6efb4ed72db 100644 --- a/contracts/proposals/ERC1046/TokenMetadata.sol +++ b/contracts/proposals/ERC1046/TokenMetadata.sol @@ -1,15 +1,15 @@ pragma solidity ^0.4.21; -import "../../token/ERC20/ERC20.sol"; +import "../../token/ERC20/IERC20.sol"; /** * @title ERC-1047 Token Metadata * @dev See https://eips.ethereum.org/EIPS/eip-1046 * @dev tokenURI must respond with a URI that implements https://eips.ethereum.org/EIPS/eip-1047 - * @dev TODO - update https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721.sol#L17 when 1046 is finalized + * @dev TODO - update https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/IERC721.sol#L17 when 1046 is finalized */ -contract ERC20TokenMetadata is ERC20 { +contract ERC20TokenMetadata is IERC20 { function tokenURI() external view returns (string); } diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index 7b152953f0f..0201cc0b849 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -1,35 +1,204 @@ pragma solidity ^0.4.24; +import "./IERC20.sol"; +import "../../math/SafeMath.sol"; + /** - * @title ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/20 + * @title Standard ERC20 token + * + * @dev Implementation of the basic standard token. + * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md + * Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol */ -contract ERC20 { - function totalSupply() public view returns (uint256); +contract ERC20 is IERC20 { + using SafeMath for uint256; + + mapping (address => uint256) private balances_; + + mapping (address => mapping (address => uint256)) private allowed_; + + uint256 private totalSupply_; + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return totalSupply_; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public view returns (uint256) { + return balances_[_owner]; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance( + address _owner, + address _spender + ) + public + view + returns (uint256) + { + return allowed_[_owner][_spender]; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_value <= balances_[msg.sender]); + require(_to != address(0)); + + balances_[msg.sender] = balances_[msg.sender].sub(_value); + balances_[_to] = balances_[_to].add(_value); + emit Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * Beware that changing an allowance with this method brings the risk that someone may use both the old + * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) public returns (bool) { + allowed_[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amount of tokens to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _value + ) + public + returns (bool) + { + require(_value <= balances_[_from]); + require(_value <= allowed_[_from][msg.sender]); + require(_to != address(0)); + + balances_[_from] = balances_[_from].sub(_value); + balances_[_to] = balances_[_to].add(_value); + allowed_[_from][msg.sender] = allowed_[_from][msg.sender].sub(_value); + emit Transfer(_from, _to, _value); + return true; + } - function balanceOf(address _who) public view returns (uint256); + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed_[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + */ + function increaseApproval( + address _spender, + uint256 _addedValue + ) + public + returns (bool) + { + allowed_[msg.sender][_spender] = ( + allowed_[msg.sender][_spender].add(_addedValue)); + emit Approval(msg.sender, _spender, allowed_[msg.sender][_spender]); + return true; + } - function allowance(address _owner, address _spender) - public view returns (uint256); + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed_[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseApproval( + address _spender, + uint256 _subtractedValue + ) + public + returns (bool) + { + uint256 oldValue = allowed_[msg.sender][_spender]; + if (_subtractedValue >= oldValue) { + allowed_[msg.sender][_spender] = 0; + } else { + allowed_[msg.sender][_spender] = oldValue.sub(_subtractedValue); + } + emit Approval(msg.sender, _spender, allowed_[msg.sender][_spender]); + return true; + } - function transfer(address _to, uint256 _value) public returns (bool); + /** + * @dev Internal function that mints an amount of the token and assigns it to + * an account. This encapsulates the modification of balances such that the + * proper events are emitted. + * @param _account The account that will receive the created tokens. + * @param _amount The amount that will be created. + */ + function _mint(address _account, uint256 _amount) internal { + require(_account != 0); + totalSupply_ = totalSupply_.add(_amount); + balances_[_account] = balances_[_account].add(_amount); + emit Transfer(address(0), _account, _amount); + } - function approve(address _spender, uint256 _value) - public returns (bool); + /** + * @dev Internal function that burns an amount of the token of a given + * account. + * @param _account The account whose tokens will be burnt. + * @param _amount The amount that will be burnt. + */ + function _burn(address _account, uint256 _amount) internal { + require(_account != 0); + require(_amount <= balances_[_account]); - function transferFrom(address _from, address _to, uint256 _value) - public returns (bool); + totalSupply_ = totalSupply_.sub(_amount); + balances_[_account] = balances_[_account].sub(_amount); + emit Transfer(_account, address(0), _amount); + } - event Transfer( - address indexed from, - address indexed to, - uint256 value - ); + /** + * @dev Internal function that burns an amount of the token of a given + * account, deducting from the sender's allowance for said account. Uses the + * internal _burn function. + * @param _account The account whose tokens will be burnt. + * @param _amount The amount that will be burnt. + */ + function _burnFrom(address _account, uint256 _amount) internal { + require(_amount <= allowed_[_account][msg.sender]); - event Approval( - address indexed owner, - address indexed spender, - uint256 value - ); + // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted, + // this function needs to emit an event with the updated approval. + allowed_[_account][msg.sender] = allowed_[_account][msg.sender].sub( + _amount); + _burn(_account, _amount); + } } diff --git a/contracts/token/ERC20/BurnableToken.sol b/contracts/token/ERC20/ERC20Burnable.sol similarity index 85% rename from contracts/token/ERC20/BurnableToken.sol rename to contracts/token/ERC20/ERC20Burnable.sol index d944c2097fe..1fc83b77a00 100644 --- a/contracts/token/ERC20/BurnableToken.sol +++ b/contracts/token/ERC20/ERC20Burnable.sol @@ -1,13 +1,13 @@ pragma solidity ^0.4.24; -import "./StandardToken.sol"; +import "./ERC20.sol"; /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ -contract BurnableToken is StandardToken { +contract ERC20Burnable is ERC20 { event TokensBurned(address indexed burner, uint256 value); @@ -29,7 +29,7 @@ contract BurnableToken is StandardToken { } /** - * @dev Overrides StandardToken._burn in order for burn and burnFrom to emit + * @dev Overrides ERC20._burn in order for burn and burnFrom to emit * an additional Burn event. */ function _burn(address _who, uint256 _value) internal { diff --git a/contracts/token/ERC20/CappedToken.sol b/contracts/token/ERC20/ERC20Capped.sol similarity index 89% rename from contracts/token/ERC20/CappedToken.sol rename to contracts/token/ERC20/ERC20Capped.sol index 1af8bdcb647..3af03f167cd 100644 --- a/contracts/token/ERC20/CappedToken.sol +++ b/contracts/token/ERC20/ERC20Capped.sol @@ -1,13 +1,13 @@ pragma solidity ^0.4.24; -import "./MintableToken.sol"; +import "./ERC20Mintable.sol"; /** * @title Capped token * @dev Mintable token with a token cap. */ -contract CappedToken is MintableToken { +contract ERC20Capped is ERC20Mintable { uint256 public cap; diff --git a/contracts/token/ERC20/DetailedERC20.sol b/contracts/token/ERC20/ERC20Detailed.sol similarity index 83% rename from contracts/token/ERC20/DetailedERC20.sol rename to contracts/token/ERC20/ERC20Detailed.sol index 20ba0f60c91..ad6f1dd059a 100644 --- a/contracts/token/ERC20/DetailedERC20.sol +++ b/contracts/token/ERC20/ERC20Detailed.sol @@ -1,15 +1,15 @@ pragma solidity ^0.4.24; -import "./ERC20.sol"; +import "./IERC20.sol"; /** - * @title DetailedERC20 token + * @title ERC20Detailed token * @dev The decimals are only for visualization purposes. * All the operations are done using the smallest and indivisible token unit, * just as on Ethereum all the operations are done in wei. */ -contract DetailedERC20 is ERC20 { +contract ERC20Detailed is IERC20 { string public name; string public symbol; uint8 public decimals; diff --git a/contracts/token/ERC20/MintableToken.sol b/contracts/token/ERC20/ERC20Mintable.sol similarity index 93% rename from contracts/token/ERC20/MintableToken.sol rename to contracts/token/ERC20/ERC20Mintable.sol index ba1ca68336f..0ba200cdfac 100644 --- a/contracts/token/ERC20/MintableToken.sol +++ b/contracts/token/ERC20/ERC20Mintable.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./StandardToken.sol"; +import "./ERC20.sol"; import "../../ownership/Ownable.sol"; @@ -9,7 +9,7 @@ import "../../ownership/Ownable.sol"; * @dev Simple ERC20 Token example, with mintable token creation * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol */ -contract MintableToken is StandardToken, Ownable { +contract ERC20Mintable is ERC20, Ownable { event Mint(address indexed to, uint256 amount); event MintFinished(); diff --git a/contracts/token/ERC20/PausableToken.sol b/contracts/token/ERC20/ERC20Pausable.sol similarity index 88% rename from contracts/token/ERC20/PausableToken.sol rename to contracts/token/ERC20/ERC20Pausable.sol index 75b4b938c69..d631fe1d960 100644 --- a/contracts/token/ERC20/PausableToken.sol +++ b/contracts/token/ERC20/ERC20Pausable.sol @@ -1,14 +1,14 @@ pragma solidity ^0.4.24; -import "./StandardToken.sol"; +import "./ERC20.sol"; import "../../lifecycle/Pausable.sol"; /** * @title Pausable token - * @dev StandardToken modified with pausable transfers. + * @dev ERC20 modified with pausable transfers. **/ -contract PausableToken is StandardToken, Pausable { +contract ERC20Pausable is ERC20, Pausable { function transfer( address _to, diff --git a/contracts/token/ERC20/IERC20.sol b/contracts/token/ERC20/IERC20.sol new file mode 100644 index 00000000000..8f8c40528da --- /dev/null +++ b/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.4.24; + + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +interface IERC20 { + function totalSupply() public view returns (uint256); + + function balanceOf(address _who) public view returns (uint256); + + function allowance(address _owner, address _spender) + public view returns (uint256); + + function transfer(address _to, uint256 _value) public returns (bool); + + function approve(address _spender, uint256 _value) + public returns (bool); + + function transferFrom(address _from, address _to, uint256 _value) + public returns (bool); + + event Transfer( + address indexed from, + address indexed to, + uint256 value + ); + + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); +} diff --git a/contracts/token/ERC20/RBACMintableToken.sol b/contracts/token/ERC20/RBACMintableToken.sol index ed7e8d210c3..6cf9f6aba4d 100644 --- a/contracts/token/ERC20/RBACMintableToken.sol +++ b/contracts/token/ERC20/RBACMintableToken.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./MintableToken.sol"; +import "./ERC20Mintable.sol"; import "../../access/rbac/RBAC.sol"; @@ -9,7 +9,7 @@ import "../../access/rbac/RBAC.sol"; * @author Vittorio Minacori (@vittominacori) * @dev Mintable Token, with RBAC minter permissions */ -contract RBACMintableToken is MintableToken, RBAC { +contract RBACMintableToken is ERC20Mintable, RBAC { /** * A constant role name for indicating minters. */ diff --git a/contracts/token/ERC20/SafeERC20.sol b/contracts/token/ERC20/SafeERC20.sol index 92aaa0fd2e2..451cf136c81 100644 --- a/contracts/token/ERC20/SafeERC20.sol +++ b/contracts/token/ERC20/SafeERC20.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; -import "./StandardToken.sol"; import "./ERC20.sol"; +import "./IERC20.sol"; /** @@ -12,7 +12,7 @@ import "./ERC20.sol"; */ library SafeERC20 { function safeTransfer( - ERC20 _token, + IERC20 _token, address _to, uint256 _value ) @@ -22,7 +22,7 @@ library SafeERC20 { } function safeTransferFrom( - ERC20 _token, + IERC20 _token, address _from, address _to, uint256 _value @@ -33,7 +33,7 @@ library SafeERC20 { } function safeApprove( - ERC20 _token, + IERC20 _token, address _spender, uint256 _value ) diff --git a/contracts/token/ERC20/StandardToken.sol b/contracts/token/ERC20/StandardToken.sol deleted file mode 100644 index bf902a8c062..00000000000 --- a/contracts/token/ERC20/StandardToken.sol +++ /dev/null @@ -1,204 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ERC20.sol"; -import "../../math/SafeMath.sol"; - - -/** - * @title Standard ERC20 token - * - * @dev Implementation of the basic standard token. - * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md - * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol - */ -contract StandardToken is ERC20 { - using SafeMath for uint256; - - mapping (address => uint256) private balances_; - - mapping (address => mapping (address => uint256)) private allowed_; - - uint256 private totalSupply_; - - /** - * @dev Total number of tokens in existence - */ - function totalSupply() public view returns (uint256) { - return totalSupply_; - } - - /** - * @dev Gets the balance of the specified address. - * @param _owner The address to query the the balance of. - * @return An uint256 representing the amount owned by the passed address. - */ - function balanceOf(address _owner) public view returns (uint256) { - return balances_[_owner]; - } - - /** - * @dev Function to check the amount of tokens that an owner allowed to a spender. - * @param _owner address The address which owns the funds. - * @param _spender address The address which will spend the funds. - * @return A uint256 specifying the amount of tokens still available for the spender. - */ - function allowance( - address _owner, - address _spender - ) - public - view - returns (uint256) - { - return allowed_[_owner][_spender]; - } - - /** - * @dev Transfer token for a specified address - * @param _to The address to transfer to. - * @param _value The amount to be transferred. - */ - function transfer(address _to, uint256 _value) public returns (bool) { - require(_value <= balances_[msg.sender]); - require(_to != address(0)); - - balances_[msg.sender] = balances_[msg.sender].sub(_value); - balances_[_to] = balances_[_to].add(_value); - emit Transfer(msg.sender, _to, _value); - return true; - } - - /** - * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. - * Beware that changing an allowance with this method brings the risk that someone may use both the old - * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this - * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * @param _spender The address which will spend the funds. - * @param _value The amount of tokens to be spent. - */ - function approve(address _spender, uint256 _value) public returns (bool) { - allowed_[msg.sender][_spender] = _value; - emit Approval(msg.sender, _spender, _value); - return true; - } - - /** - * @dev Transfer tokens from one address to another - * @param _from address The address which you want to send tokens from - * @param _to address The address which you want to transfer to - * @param _value uint256 the amount of tokens to be transferred - */ - function transferFrom( - address _from, - address _to, - uint256 _value - ) - public - returns (bool) - { - require(_value <= balances_[_from]); - require(_value <= allowed_[_from][msg.sender]); - require(_to != address(0)); - - balances_[_from] = balances_[_from].sub(_value); - balances_[_to] = balances_[_to].add(_value); - allowed_[_from][msg.sender] = allowed_[_from][msg.sender].sub(_value); - emit Transfer(_from, _to, _value); - return true; - } - - /** - * @dev Increase the amount of tokens that an owner allowed to a spender. - * approve should be called when allowed_[_spender] == 0. To increment - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * @param _spender The address which will spend the funds. - * @param _addedValue The amount of tokens to increase the allowance by. - */ - function increaseApproval( - address _spender, - uint256 _addedValue - ) - public - returns (bool) - { - allowed_[msg.sender][_spender] = ( - allowed_[msg.sender][_spender].add(_addedValue)); - emit Approval(msg.sender, _spender, allowed_[msg.sender][_spender]); - return true; - } - - /** - * @dev Decrease the amount of tokens that an owner allowed to a spender. - * approve should be called when allowed_[_spender] == 0. To decrement - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * @param _spender The address which will spend the funds. - * @param _subtractedValue The amount of tokens to decrease the allowance by. - */ - function decreaseApproval( - address _spender, - uint256 _subtractedValue - ) - public - returns (bool) - { - uint256 oldValue = allowed_[msg.sender][_spender]; - if (_subtractedValue >= oldValue) { - allowed_[msg.sender][_spender] = 0; - } else { - allowed_[msg.sender][_spender] = oldValue.sub(_subtractedValue); - } - emit Approval(msg.sender, _spender, allowed_[msg.sender][_spender]); - return true; - } - - /** - * @dev Internal function that mints an amount of the token and assigns it to - * an account. This encapsulates the modification of balances such that the - * proper events are emitted. - * @param _account The account that will receive the created tokens. - * @param _amount The amount that will be created. - */ - function _mint(address _account, uint256 _amount) internal { - require(_account != 0); - totalSupply_ = totalSupply_.add(_amount); - balances_[_account] = balances_[_account].add(_amount); - emit Transfer(address(0), _account, _amount); - } - - /** - * @dev Internal function that burns an amount of the token of a given - * account. - * @param _account The account whose tokens will be burnt. - * @param _amount The amount that will be burnt. - */ - function _burn(address _account, uint256 _amount) internal { - require(_account != 0); - require(_amount <= balances_[_account]); - - totalSupply_ = totalSupply_.sub(_amount); - balances_[_account] = balances_[_account].sub(_amount); - emit Transfer(_account, address(0), _amount); - } - - /** - * @dev Internal function that burns an amount of the token of a given - * account, deducting from the sender's allowance for said account. Uses the - * internal _burn function. - * @param _account The account whose tokens will be burnt. - * @param _amount The amount that will be burnt. - */ - function _burnFrom(address _account, uint256 _amount) internal { - require(_amount <= allowed_[_account][msg.sender]); - - // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted, - // this function needs to emit an event with the updated approval. - allowed_[_account][msg.sender] = allowed_[_account][msg.sender].sub( - _amount); - _burn(_account, _amount); - } -} diff --git a/contracts/token/ERC20/TokenTimelock.sol b/contracts/token/ERC20/TokenTimelock.sol index 2e3cd6dd55e..a24642f6de5 100644 --- a/contracts/token/ERC20/TokenTimelock.sol +++ b/contracts/token/ERC20/TokenTimelock.sol @@ -9,10 +9,10 @@ import "./SafeERC20.sol"; * beneficiary to extract the tokens after a given release time */ contract TokenTimelock { - using SafeERC20 for ERC20; + using SafeERC20 for IERC20; // ERC20 basic token contract being held - ERC20 public token; + IERC20 public token; // beneficiary of tokens after they are released address public beneficiary; @@ -21,7 +21,7 @@ contract TokenTimelock { uint256 public releaseTime; constructor( - ERC20 _token, + IERC20 _token, address _beneficiary, uint256 _releaseTime ) diff --git a/contracts/token/ERC20/TokenVesting.sol b/contracts/token/ERC20/TokenVesting.sol index 2ceaa31352e..31fac8882ce 100644 --- a/contracts/token/ERC20/TokenVesting.sol +++ b/contracts/token/ERC20/TokenVesting.sol @@ -15,7 +15,7 @@ import "../../math/SafeMath.sol"; */ contract TokenVesting is Ownable { using SafeMath for uint256; - using SafeERC20 for ERC20; + using SafeERC20 for IERC20; event Released(uint256 amount); event Revoked(); @@ -65,7 +65,7 @@ contract TokenVesting is Ownable { * @notice Transfers vested tokens to beneficiary. * @param _token ERC20 token which is being vested */ - function release(ERC20 _token) public { + function release(IERC20 _token) public { uint256 unreleased = releasableAmount(_token); require(unreleased > 0); @@ -82,7 +82,7 @@ contract TokenVesting is Ownable { * remain in the contract, the rest are returned to the owner. * @param _token ERC20 token which is being vested */ - function revoke(ERC20 _token) public onlyOwner { + function revoke(IERC20 _token) public onlyOwner { require(revocable); require(!revoked[_token]); @@ -102,7 +102,7 @@ contract TokenVesting is Ownable { * @dev Calculates the amount that has already vested but hasn't been released yet. * @param _token ERC20 token which is being vested */ - function releasableAmount(ERC20 _token) public view returns (uint256) { + function releasableAmount(IERC20 _token) public view returns (uint256) { return vestedAmount(_token).sub(released[_token]); } @@ -110,7 +110,7 @@ contract TokenVesting is Ownable { * @dev Calculates the amount that has already vested. * @param _token ERC20 token which is being vested */ - function vestedAmount(ERC20 _token) public view returns (uint256) { + function vestedAmount(IERC20 _token) public view returns (uint256) { uint256 currentBalance = _token.balanceOf(this); uint256 totalBalance = currentBalance.add(released[_token]); diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index a988d8f4059..ef6a98453c4 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -1,40 +1,201 @@ pragma solidity ^0.4.24; +import "./IERC721.sol"; import "./ERC721Basic.sol"; +import "../../introspection/SupportsInterfaceWithLookup.sol"; /** - * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension - * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + * @title Full ERC721 Token + * This implementation includes all the required and some optional functionality of the ERC721 standard + * Moreover, it includes approve all functionality using operator terminology + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ -contract ERC721Enumerable is ERC721Basic { - function totalSupply() public view returns (uint256); +contract ERC721 is SupportsInterfaceWithLookup, ERC721Basic, IERC721 { + + // Token name + string internal name_; + + // Token symbol + string internal symbol_; + + // Mapping from owner to list of owned token IDs + mapping(address => uint256[]) internal ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) internal ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] internal allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) internal allTokensIndex; + + // Optional mapping for token URIs + mapping(uint256 => string) internal tokenURIs; + + /** + * @dev Constructor function + */ + constructor(string _name, string _symbol) public { + name_ = _name; + symbol_ = _symbol; + + // register the supported interfaces to conform to ERC721 via ERC165 + _registerInterface(InterfaceId_ERC721Enumerable); + _registerInterface(InterfaceId_ERC721Metadata); + } + + /** + * @dev Gets the token name + * @return string representing the token name + */ + function name() external view returns (string) { + return name_; + } + + /** + * @dev Gets the token symbol + * @return string representing the token symbol + */ + function symbol() external view returns (string) { + return symbol_; + } + + /** + * @dev Returns an URI for a given token ID + * Throws if the token ID does not exist. May return an empty string. + * @param _tokenId uint256 ID of the token to query + */ + function tokenURI(uint256 _tokenId) public view returns (string) { + require(_exists(_tokenId)); + return tokenURIs[_tokenId]; + } + + /** + * @dev Gets the token ID at a given index of the tokens list of the requested owner + * @param _owner address owning the tokens list to be accessed + * @param _index uint256 representing the index to be accessed of the requested tokens list + * @return uint256 token ID at the given index of the tokens list owned by the requested address + */ function tokenOfOwnerByIndex( address _owner, uint256 _index ) public view - returns (uint256 _tokenId); + returns (uint256) + { + require(_index < balanceOf(_owner)); + return ownedTokens[_owner][_index]; + } - function tokenByIndex(uint256 _index) public view returns (uint256); -} + /** + * @dev Gets the total amount of tokens stored by the contract + * @return uint256 representing the total amount of tokens + */ + function totalSupply() public view returns (uint256) { + return allTokens.length; + } + /** + * @dev Gets the token ID at a given index of all the tokens in this contract + * Reverts if the index is greater or equal to the total number of tokens + * @param _index uint256 representing the index to be accessed of the tokens list + * @return uint256 token ID at the given index of the tokens list + */ + function tokenByIndex(uint256 _index) public view returns (uint256) { + require(_index < totalSupply()); + return allTokens[_index]; + } -/** - * @title ERC-721 Non-Fungible Token Standard, optional metadata extension - * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md - */ -contract ERC721Metadata is ERC721Basic { - function name() external view returns (string _name); - function symbol() external view returns (string _symbol); - function tokenURI(uint256 _tokenId) public view returns (string); -} + /** + * @dev Internal function to set the token URI for a given token + * Reverts if the token ID does not exist + * @param _tokenId uint256 ID of the token to set its URI + * @param _uri string URI to assign + */ + function _setTokenURI(uint256 _tokenId, string _uri) internal { + require(_exists(_tokenId)); + tokenURIs[_tokenId] = _uri; + } + /** + * @dev Internal function to add a token ID to the list of a given address + * @param _to address representing the new owner of the given token ID + * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function addTokenTo(address _to, uint256 _tokenId) internal { + super.addTokenTo(_to, _tokenId); + uint256 length = ownedTokens[_to].length; + ownedTokens[_to].push(_tokenId); + ownedTokensIndex[_tokenId] = length; + } + + /** + * @dev Internal function to remove a token ID from the list of a given address + * @param _from address representing the previous owner of the given token ID + * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function removeTokenFrom(address _from, uint256 _tokenId) internal { + super.removeTokenFrom(_from, _tokenId); + + // To prevent a gap in the array, we store the last token in the index of the token to delete, and + // then delete the last slot. + uint256 tokenIndex = ownedTokensIndex[_tokenId]; + uint256 lastTokenIndex = ownedTokens[_from].length.sub(1); + uint256 lastToken = ownedTokens[_from][lastTokenIndex]; + + ownedTokens[_from][tokenIndex] = lastToken; + // This also deletes the contents at the last position of the array + ownedTokens[_from].length--; + + // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to + // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping + // the lastToken to the first position, and then dropping the element placed in the last position of the list + + ownedTokensIndex[_tokenId] = 0; + ownedTokensIndex[lastToken] = tokenIndex; + } + + /** + * @dev Internal function to mint a new token + * Reverts if the given token ID already exists + * @param _to address the beneficiary that will own the minted token + * @param _tokenId uint256 ID of the token to be minted by the msg.sender + */ + function _mint(address _to, uint256 _tokenId) internal { + super._mint(_to, _tokenId); + + allTokensIndex[_tokenId] = allTokens.length; + allTokens.push(_tokenId); + } + + /** + * @dev Internal function to burn a specific token + * Reverts if the token does not exist + * @param _owner owner of the token to burn + * @param _tokenId uint256 ID of the token being burned by the msg.sender + */ + function _burn(address _owner, uint256 _tokenId) internal { + super._burn(_owner, _tokenId); + + // Clear metadata (if any) + if (bytes(tokenURIs[_tokenId]).length != 0) { + delete tokenURIs[_tokenId]; + } + + // Reorg all tokens array + uint256 tokenIndex = allTokensIndex[_tokenId]; + uint256 lastTokenIndex = allTokens.length.sub(1); + uint256 lastToken = allTokens[lastTokenIndex]; + + allTokens[tokenIndex] = lastToken; + allTokens[lastTokenIndex] = 0; + + allTokens.length--; + allTokensIndex[_tokenId] = 0; + allTokensIndex[lastToken] = tokenIndex; + } -/** - * @title ERC-721 Non-Fungible Token Standard, full implementation interface - * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md - */ -contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata { } diff --git a/contracts/token/ERC721/ERC721Basic.sol b/contracts/token/ERC721/ERC721Basic.sol index f9075f06004..58a40cae893 100644 --- a/contracts/token/ERC721/ERC721Basic.sol +++ b/contracts/token/ERC721/ERC721Basic.sol @@ -1,80 +1,310 @@ pragma solidity ^0.4.24; -import "../../introspection/ERC165.sol"; +import "./IERC721Basic.sol"; +import "./IERC721Receiver.sol"; +import "../../math/SafeMath.sol"; +import "../../AddressUtils.sol"; +import "../../introspection/SupportsInterfaceWithLookup.sol"; /** - * @title ERC721 Non-Fungible Token Standard basic interface + * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md */ -contract ERC721Basic is ERC165 { - - bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd; - /* - * 0x80ac58cd === - * bytes4(keccak256('balanceOf(address)')) ^ - * bytes4(keccak256('ownerOf(uint256)')) ^ - * bytes4(keccak256('approve(address,uint256)')) ^ - * bytes4(keccak256('getApproved(uint256)')) ^ - * bytes4(keccak256('setApprovalForAll(address,bool)')) ^ - * bytes4(keccak256('isApprovedForAll(address,address)')) ^ - * bytes4(keccak256('transferFrom(address,address,uint256)')) ^ - * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ - * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) +contract ERC721Basic is SupportsInterfaceWithLookup, IERC721Basic { + + using SafeMath for uint256; + using AddressUtils for address; + + // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` + bytes4 private constant ERC721_RECEIVED = 0x150b7a02; + + // Mapping from token ID to owner + mapping (uint256 => address) internal tokenOwner; + + // Mapping from token ID to approved address + mapping (uint256 => address) internal tokenApprovals; + + // Mapping from owner to number of owned token + mapping (address => uint256) internal ownedTokensCount; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) internal operatorApprovals; + + constructor() + public + { + // register the supported interfaces to conform to ERC721 via ERC165 + _registerInterface(InterfaceId_ERC721); + } + + /** + * @dev Gets the balance of the specified address + * @param _owner address to query the balance of + * @return uint256 representing the amount owned by the passed address + */ + function balanceOf(address _owner) public view returns (uint256) { + require(_owner != address(0)); + return ownedTokensCount[_owner]; + } + + /** + * @dev Gets the owner of the specified token ID + * @param _tokenId uint256 ID of the token to query the owner of + * @return owner address currently marked as the owner of the given token ID + */ + function ownerOf(uint256 _tokenId) public view returns (address) { + address owner = tokenOwner[_tokenId]; + require(owner != address(0)); + return owner; + } + + /** + * @dev Approves another address to transfer the given token ID + * The zero address indicates there is no approved address. + * There can only be one approved address per token at a given time. + * Can only be called by the token owner or an approved operator. + * @param _to address to be approved for the given token ID + * @param _tokenId uint256 ID of the token to be approved + */ + function approve(address _to, uint256 _tokenId) public { + address owner = ownerOf(_tokenId); + require(_to != owner); + require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); + + tokenApprovals[_tokenId] = _to; + emit Approval(owner, _to, _tokenId); + } + + /** + * @dev Gets the approved address for a token ID, or zero if no address set + * @param _tokenId uint256 ID of the token to query the approval of + * @return address currently approved for the given token ID */ + function getApproved(uint256 _tokenId) public view returns (address) { + return tokenApprovals[_tokenId]; + } - bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63; /** - * 0x780e9d63 === - * bytes4(keccak256('totalSupply()')) ^ - * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ - * bytes4(keccak256('tokenByIndex(uint256)')) + * @dev Sets or unsets the approval of a given operator + * An operator is allowed to transfer all tokens of the sender on their behalf + * @param _to operator address to set the approval + * @param _approved representing the status of the approval to be set */ + function setApprovalForAll(address _to, bool _approved) public { + require(_to != msg.sender); + operatorApprovals[msg.sender][_to] = _approved; + emit ApprovalForAll(msg.sender, _to, _approved); + } - bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f; /** - * 0x5b5e139f === - * bytes4(keccak256('name()')) ^ - * bytes4(keccak256('symbol()')) ^ - * bytes4(keccak256('tokenURI(uint256)')) + * @dev Tells whether an operator is approved by a given owner + * @param _owner owner address which you want to query the approval of + * @param _operator operator address which you want to query the approval of + * @return bool whether the given operator is approved by the given owner */ + function isApprovedForAll( + address _owner, + address _operator + ) + public + view + returns (bool) + { + return operatorApprovals[_owner][_operator]; + } + + /** + * @dev Transfers the ownership of a given token ID to another address + * Usage of this method is discouraged, use `safeTransferFrom` whenever possible + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _tokenId + ) + public + { + require(isApprovedOrOwner(msg.sender, _tokenId)); + require(_to != address(0)); + + clearApproval(_from, _tokenId); + removeTokenFrom(_from, _tokenId); + addTokenTo(_to, _tokenId); - event Transfer( - address indexed _from, - address indexed _to, - uint256 indexed _tokenId - ); - event Approval( - address indexed _owner, - address indexed _approved, - uint256 indexed _tokenId - ); - event ApprovalForAll( - address indexed _owner, - address indexed _operator, - bool _approved - ); - - function balanceOf(address _owner) public view returns (uint256 _balance); - function ownerOf(uint256 _tokenId) public view returns (address _owner); - - function approve(address _to, uint256 _tokenId) public; - function getApproved(uint256 _tokenId) - public view returns (address _operator); - - function setApprovalForAll(address _operator, bool _approved) public; - function isApprovedForAll(address _owner, address _operator) - public view returns (bool); - - function transferFrom(address _from, address _to, uint256 _tokenId) public; - function safeTransferFrom(address _from, address _to, uint256 _tokenId) - public; + emit Transfer(_from, _to, _tokenId); + } + + /** + * @dev Safely transfers the ownership of a given token ID to another address + * If the target address is a contract, it must implement `onERC721Received`, + * which is called upon a safe transfer, and return the magic value + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, + * the transfer is reverted. + * + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + */ + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId + ) + public + { + // solium-disable-next-line arg-overflow + safeTransferFrom(_from, _to, _tokenId, ""); + } + /** + * @dev Safely transfers the ownership of a given token ID to another address + * If the target address is a contract, it must implement `onERC721Received`, + * which is called upon a safe transfer, and return the magic value + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, + * the transfer is reverted. + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + * @param _data bytes data to send along with a safe transfer check + */ function safeTransferFrom( address _from, address _to, uint256 _tokenId, bytes _data ) - public; + public + { + transferFrom(_from, _to, _tokenId); + // solium-disable-next-line arg-overflow + require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data)); + } + + /** + * @dev Returns whether the specified token exists + * @param _tokenId uint256 ID of the token to query the existence of + * @return whether the token exists + */ + function _exists(uint256 _tokenId) internal view returns (bool) { + address owner = tokenOwner[_tokenId]; + return owner != address(0); + } + + /** + * @dev Returns whether the given spender can transfer a given token ID + * @param _spender address of the spender to query + * @param _tokenId uint256 ID of the token to be transferred + * @return bool whether the msg.sender is approved for the given token ID, + * is an operator of the owner, or is the owner of the token + */ + function isApprovedOrOwner( + address _spender, + uint256 _tokenId + ) + internal + view + returns (bool) + { + address owner = ownerOf(_tokenId); + // Disable solium check because of + // https://github.com/duaraghav8/Solium/issues/175 + // solium-disable-next-line operator-whitespace + return ( + _spender == owner || + getApproved(_tokenId) == _spender || + isApprovedForAll(owner, _spender) + ); + } + + /** + * @dev Internal function to mint a new token + * Reverts if the given token ID already exists + * @param _to The address that will own the minted token + * @param _tokenId uint256 ID of the token to be minted by the msg.sender + */ + function _mint(address _to, uint256 _tokenId) internal { + require(_to != address(0)); + addTokenTo(_to, _tokenId); + emit Transfer(address(0), _to, _tokenId); + } + + /** + * @dev Internal function to burn a specific token + * Reverts if the token does not exist + * @param _tokenId uint256 ID of the token being burned by the msg.sender + */ + function _burn(address _owner, uint256 _tokenId) internal { + clearApproval(_owner, _tokenId); + removeTokenFrom(_owner, _tokenId); + emit Transfer(_owner, address(0), _tokenId); + } + + /** + * @dev Internal function to clear current approval of a given token ID + * Reverts if the given address is not indeed the owner of the token + * @param _owner owner of the token + * @param _tokenId uint256 ID of the token to be transferred + */ + function clearApproval(address _owner, uint256 _tokenId) internal { + require(ownerOf(_tokenId) == _owner); + if (tokenApprovals[_tokenId] != address(0)) { + tokenApprovals[_tokenId] = address(0); + } + } + + /** + * @dev Internal function to add a token ID to the list of a given address + * @param _to address representing the new owner of the given token ID + * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function addTokenTo(address _to, uint256 _tokenId) internal { + require(tokenOwner[_tokenId] == address(0)); + tokenOwner[_tokenId] = _to; + ownedTokensCount[_to] = ownedTokensCount[_to].add(1); + } + + /** + * @dev Internal function to remove a token ID from the list of a given address + * @param _from address representing the previous owner of the given token ID + * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function removeTokenFrom(address _from, uint256 _tokenId) internal { + require(ownerOf(_tokenId) == _from); + ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); + tokenOwner[_tokenId] = address(0); + } + + /** + * @dev Internal function to invoke `onERC721Received` on a target address + * The call is not executed if the target address is not a contract + * @param _from address representing the previous owner of the given token ID + * @param _to target address that will receive the tokens + * @param _tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return whether the call correctly returned the expected magic value + */ + function checkAndCallSafeTransfer( + address _from, + address _to, + uint256 _tokenId, + bytes _data + ) + internal + returns (bool) + { + if (!_to.isContract()) { + return true; + } + bytes4 retval = IERC721Receiver(_to).onERC721Received( + msg.sender, _from, _tokenId, _data); + return (retval == ERC721_RECEIVED); + } } diff --git a/contracts/token/ERC721/ERC721BasicToken.sol b/contracts/token/ERC721/ERC721BasicToken.sol deleted file mode 100644 index 568be300cbc..00000000000 --- a/contracts/token/ERC721/ERC721BasicToken.sol +++ /dev/null @@ -1,310 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ERC721Basic.sol"; -import "./ERC721Receiver.sol"; -import "../../math/SafeMath.sol"; -import "../../AddressUtils.sol"; -import "../../introspection/SupportsInterfaceWithLookup.sol"; - - -/** - * @title ERC721 Non-Fungible Token Standard basic implementation - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md - */ -contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic { - - using SafeMath for uint256; - using AddressUtils for address; - - // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` - // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` - bytes4 private constant ERC721_RECEIVED = 0x150b7a02; - - // Mapping from token ID to owner - mapping (uint256 => address) internal tokenOwner; - - // Mapping from token ID to approved address - mapping (uint256 => address) internal tokenApprovals; - - // Mapping from owner to number of owned token - mapping (address => uint256) internal ownedTokensCount; - - // Mapping from owner to operator approvals - mapping (address => mapping (address => bool)) internal operatorApprovals; - - constructor() - public - { - // register the supported interfaces to conform to ERC721 via ERC165 - _registerInterface(InterfaceId_ERC721); - } - - /** - * @dev Gets the balance of the specified address - * @param _owner address to query the balance of - * @return uint256 representing the amount owned by the passed address - */ - function balanceOf(address _owner) public view returns (uint256) { - require(_owner != address(0)); - return ownedTokensCount[_owner]; - } - - /** - * @dev Gets the owner of the specified token ID - * @param _tokenId uint256 ID of the token to query the owner of - * @return owner address currently marked as the owner of the given token ID - */ - function ownerOf(uint256 _tokenId) public view returns (address) { - address owner = tokenOwner[_tokenId]; - require(owner != address(0)); - return owner; - } - - /** - * @dev Approves another address to transfer the given token ID - * The zero address indicates there is no approved address. - * There can only be one approved address per token at a given time. - * Can only be called by the token owner or an approved operator. - * @param _to address to be approved for the given token ID - * @param _tokenId uint256 ID of the token to be approved - */ - function approve(address _to, uint256 _tokenId) public { - address owner = ownerOf(_tokenId); - require(_to != owner); - require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); - - tokenApprovals[_tokenId] = _to; - emit Approval(owner, _to, _tokenId); - } - - /** - * @dev Gets the approved address for a token ID, or zero if no address set - * @param _tokenId uint256 ID of the token to query the approval of - * @return address currently approved for the given token ID - */ - function getApproved(uint256 _tokenId) public view returns (address) { - return tokenApprovals[_tokenId]; - } - - /** - * @dev Sets or unsets the approval of a given operator - * An operator is allowed to transfer all tokens of the sender on their behalf - * @param _to operator address to set the approval - * @param _approved representing the status of the approval to be set - */ - function setApprovalForAll(address _to, bool _approved) public { - require(_to != msg.sender); - operatorApprovals[msg.sender][_to] = _approved; - emit ApprovalForAll(msg.sender, _to, _approved); - } - - /** - * @dev Tells whether an operator is approved by a given owner - * @param _owner owner address which you want to query the approval of - * @param _operator operator address which you want to query the approval of - * @return bool whether the given operator is approved by the given owner - */ - function isApprovedForAll( - address _owner, - address _operator - ) - public - view - returns (bool) - { - return operatorApprovals[_owner][_operator]; - } - - /** - * @dev Transfers the ownership of a given token ID to another address - * Usage of this method is discouraged, use `safeTransferFrom` whenever possible - * Requires the msg sender to be the owner, approved, or operator - * @param _from current owner of the token - * @param _to address to receive the ownership of the given token ID - * @param _tokenId uint256 ID of the token to be transferred - */ - function transferFrom( - address _from, - address _to, - uint256 _tokenId - ) - public - { - require(isApprovedOrOwner(msg.sender, _tokenId)); - require(_to != address(0)); - - clearApproval(_from, _tokenId); - removeTokenFrom(_from, _tokenId); - addTokenTo(_to, _tokenId); - - emit Transfer(_from, _to, _tokenId); - } - - /** - * @dev Safely transfers the ownership of a given token ID to another address - * If the target address is a contract, it must implement `onERC721Received`, - * which is called upon a safe transfer, and return the magic value - * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, - * the transfer is reverted. - * - * Requires the msg sender to be the owner, approved, or operator - * @param _from current owner of the token - * @param _to address to receive the ownership of the given token ID - * @param _tokenId uint256 ID of the token to be transferred - */ - function safeTransferFrom( - address _from, - address _to, - uint256 _tokenId - ) - public - { - // solium-disable-next-line arg-overflow - safeTransferFrom(_from, _to, _tokenId, ""); - } - - /** - * @dev Safely transfers the ownership of a given token ID to another address - * If the target address is a contract, it must implement `onERC721Received`, - * which is called upon a safe transfer, and return the magic value - * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, - * the transfer is reverted. - * Requires the msg sender to be the owner, approved, or operator - * @param _from current owner of the token - * @param _to address to receive the ownership of the given token ID - * @param _tokenId uint256 ID of the token to be transferred - * @param _data bytes data to send along with a safe transfer check - */ - function safeTransferFrom( - address _from, - address _to, - uint256 _tokenId, - bytes _data - ) - public - { - transferFrom(_from, _to, _tokenId); - // solium-disable-next-line arg-overflow - require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data)); - } - - /** - * @dev Returns whether the specified token exists - * @param _tokenId uint256 ID of the token to query the existence of - * @return whether the token exists - */ - function _exists(uint256 _tokenId) internal view returns (bool) { - address owner = tokenOwner[_tokenId]; - return owner != address(0); - } - - /** - * @dev Returns whether the given spender can transfer a given token ID - * @param _spender address of the spender to query - * @param _tokenId uint256 ID of the token to be transferred - * @return bool whether the msg.sender is approved for the given token ID, - * is an operator of the owner, or is the owner of the token - */ - function isApprovedOrOwner( - address _spender, - uint256 _tokenId - ) - internal - view - returns (bool) - { - address owner = ownerOf(_tokenId); - // Disable solium check because of - // https://github.com/duaraghav8/Solium/issues/175 - // solium-disable-next-line operator-whitespace - return ( - _spender == owner || - getApproved(_tokenId) == _spender || - isApprovedForAll(owner, _spender) - ); - } - - /** - * @dev Internal function to mint a new token - * Reverts if the given token ID already exists - * @param _to The address that will own the minted token - * @param _tokenId uint256 ID of the token to be minted by the msg.sender - */ - function _mint(address _to, uint256 _tokenId) internal { - require(_to != address(0)); - addTokenTo(_to, _tokenId); - emit Transfer(address(0), _to, _tokenId); - } - - /** - * @dev Internal function to burn a specific token - * Reverts if the token does not exist - * @param _tokenId uint256 ID of the token being burned by the msg.sender - */ - function _burn(address _owner, uint256 _tokenId) internal { - clearApproval(_owner, _tokenId); - removeTokenFrom(_owner, _tokenId); - emit Transfer(_owner, address(0), _tokenId); - } - - /** - * @dev Internal function to clear current approval of a given token ID - * Reverts if the given address is not indeed the owner of the token - * @param _owner owner of the token - * @param _tokenId uint256 ID of the token to be transferred - */ - function clearApproval(address _owner, uint256 _tokenId) internal { - require(ownerOf(_tokenId) == _owner); - if (tokenApprovals[_tokenId] != address(0)) { - tokenApprovals[_tokenId] = address(0); - } - } - - /** - * @dev Internal function to add a token ID to the list of a given address - * @param _to address representing the new owner of the given token ID - * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address - */ - function addTokenTo(address _to, uint256 _tokenId) internal { - require(tokenOwner[_tokenId] == address(0)); - tokenOwner[_tokenId] = _to; - ownedTokensCount[_to] = ownedTokensCount[_to].add(1); - } - - /** - * @dev Internal function to remove a token ID from the list of a given address - * @param _from address representing the previous owner of the given token ID - * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address - */ - function removeTokenFrom(address _from, uint256 _tokenId) internal { - require(ownerOf(_tokenId) == _from); - ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); - tokenOwner[_tokenId] = address(0); - } - - /** - * @dev Internal function to invoke `onERC721Received` on a target address - * The call is not executed if the target address is not a contract - * @param _from address representing the previous owner of the given token ID - * @param _to target address that will receive the tokens - * @param _tokenId uint256 ID of the token to be transferred - * @param _data bytes optional data to send along with the call - * @return whether the call correctly returned the expected magic value - */ - function checkAndCallSafeTransfer( - address _from, - address _to, - uint256 _tokenId, - bytes _data - ) - internal - returns (bool) - { - if (!_to.isContract()) { - return true; - } - bytes4 retval = ERC721Receiver(_to).onERC721Received( - msg.sender, _from, _tokenId, _data); - return (retval == ERC721_RECEIVED); - } -} diff --git a/contracts/token/ERC721/ERC721Holder.sol b/contracts/token/ERC721/ERC721Holder.sol index 0f9299c6cc7..332061339e7 100644 --- a/contracts/token/ERC721/ERC721Holder.sol +++ b/contracts/token/ERC721/ERC721Holder.sol @@ -1,9 +1,9 @@ pragma solidity ^0.4.24; -import "./ERC721Receiver.sol"; +import "./IERC721Receiver.sol"; -contract ERC721Holder is ERC721Receiver { +contract ERC721Holder is IERC721Receiver { function onERC721Received( address, address, diff --git a/contracts/token/ERC721/ERC721PausableToken.sol b/contracts/token/ERC721/ERC721Pausable.sol similarity index 79% rename from contracts/token/ERC721/ERC721PausableToken.sol rename to contracts/token/ERC721/ERC721Pausable.sol index 2da188a7edc..4604597d923 100644 --- a/contracts/token/ERC721/ERC721PausableToken.sol +++ b/contracts/token/ERC721/ERC721Pausable.sol @@ -1,14 +1,14 @@ pragma solidity ^0.4.24; -import "./ERC721BasicToken.sol"; +import "./ERC721Basic.sol"; import "../../lifecycle/Pausable.sol"; /** * @title ERC721 Non-Fungible Pausable token - * @dev ERC721BasicToken modified with pausable transfers. + * @dev ERC721Basic modified with pausable transfers. **/ -contract ERC721PausableToken is ERC721BasicToken, Pausable { +contract ERC721Pausable is ERC721Basic, Pausable { function approve( address _to, uint256 _tokenId diff --git a/contracts/token/ERC721/ERC721Token.sol b/contracts/token/ERC721/ERC721Token.sol deleted file mode 100644 index af610fa245a..00000000000 --- a/contracts/token/ERC721/ERC721Token.sol +++ /dev/null @@ -1,201 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ERC721.sol"; -import "./ERC721BasicToken.sol"; -import "../../introspection/SupportsInterfaceWithLookup.sol"; - - -/** - * @title Full ERC721 Token - * This implementation includes all the required and some optional functionality of the ERC721 standard - * Moreover, it includes approve all functionality using operator terminology - * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md - */ -contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 { - - // Token name - string internal name_; - - // Token symbol - string internal symbol_; - - // Mapping from owner to list of owned token IDs - mapping(address => uint256[]) internal ownedTokens; - - // Mapping from token ID to index of the owner tokens list - mapping(uint256 => uint256) internal ownedTokensIndex; - - // Array with all token ids, used for enumeration - uint256[] internal allTokens; - - // Mapping from token id to position in the allTokens array - mapping(uint256 => uint256) internal allTokensIndex; - - // Optional mapping for token URIs - mapping(uint256 => string) internal tokenURIs; - - /** - * @dev Constructor function - */ - constructor(string _name, string _symbol) public { - name_ = _name; - symbol_ = _symbol; - - // register the supported interfaces to conform to ERC721 via ERC165 - _registerInterface(InterfaceId_ERC721Enumerable); - _registerInterface(InterfaceId_ERC721Metadata); - } - - /** - * @dev Gets the token name - * @return string representing the token name - */ - function name() external view returns (string) { - return name_; - } - - /** - * @dev Gets the token symbol - * @return string representing the token symbol - */ - function symbol() external view returns (string) { - return symbol_; - } - - /** - * @dev Returns an URI for a given token ID - * Throws if the token ID does not exist. May return an empty string. - * @param _tokenId uint256 ID of the token to query - */ - function tokenURI(uint256 _tokenId) public view returns (string) { - require(_exists(_tokenId)); - return tokenURIs[_tokenId]; - } - - /** - * @dev Gets the token ID at a given index of the tokens list of the requested owner - * @param _owner address owning the tokens list to be accessed - * @param _index uint256 representing the index to be accessed of the requested tokens list - * @return uint256 token ID at the given index of the tokens list owned by the requested address - */ - function tokenOfOwnerByIndex( - address _owner, - uint256 _index - ) - public - view - returns (uint256) - { - require(_index < balanceOf(_owner)); - return ownedTokens[_owner][_index]; - } - - /** - * @dev Gets the total amount of tokens stored by the contract - * @return uint256 representing the total amount of tokens - */ - function totalSupply() public view returns (uint256) { - return allTokens.length; - } - - /** - * @dev Gets the token ID at a given index of all the tokens in this contract - * Reverts if the index is greater or equal to the total number of tokens - * @param _index uint256 representing the index to be accessed of the tokens list - * @return uint256 token ID at the given index of the tokens list - */ - function tokenByIndex(uint256 _index) public view returns (uint256) { - require(_index < totalSupply()); - return allTokens[_index]; - } - - /** - * @dev Internal function to set the token URI for a given token - * Reverts if the token ID does not exist - * @param _tokenId uint256 ID of the token to set its URI - * @param _uri string URI to assign - */ - function _setTokenURI(uint256 _tokenId, string _uri) internal { - require(_exists(_tokenId)); - tokenURIs[_tokenId] = _uri; - } - - /** - * @dev Internal function to add a token ID to the list of a given address - * @param _to address representing the new owner of the given token ID - * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address - */ - function addTokenTo(address _to, uint256 _tokenId) internal { - super.addTokenTo(_to, _tokenId); - uint256 length = ownedTokens[_to].length; - ownedTokens[_to].push(_tokenId); - ownedTokensIndex[_tokenId] = length; - } - - /** - * @dev Internal function to remove a token ID from the list of a given address - * @param _from address representing the previous owner of the given token ID - * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address - */ - function removeTokenFrom(address _from, uint256 _tokenId) internal { - super.removeTokenFrom(_from, _tokenId); - - // To prevent a gap in the array, we store the last token in the index of the token to delete, and - // then delete the last slot. - uint256 tokenIndex = ownedTokensIndex[_tokenId]; - uint256 lastTokenIndex = ownedTokens[_from].length.sub(1); - uint256 lastToken = ownedTokens[_from][lastTokenIndex]; - - ownedTokens[_from][tokenIndex] = lastToken; - // This also deletes the contents at the last position of the array - ownedTokens[_from].length--; - - // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to - // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping - // the lastToken to the first position, and then dropping the element placed in the last position of the list - - ownedTokensIndex[_tokenId] = 0; - ownedTokensIndex[lastToken] = tokenIndex; - } - - /** - * @dev Internal function to mint a new token - * Reverts if the given token ID already exists - * @param _to address the beneficiary that will own the minted token - * @param _tokenId uint256 ID of the token to be minted by the msg.sender - */ - function _mint(address _to, uint256 _tokenId) internal { - super._mint(_to, _tokenId); - - allTokensIndex[_tokenId] = allTokens.length; - allTokens.push(_tokenId); - } - - /** - * @dev Internal function to burn a specific token - * Reverts if the token does not exist - * @param _owner owner of the token to burn - * @param _tokenId uint256 ID of the token being burned by the msg.sender - */ - function _burn(address _owner, uint256 _tokenId) internal { - super._burn(_owner, _tokenId); - - // Clear metadata (if any) - if (bytes(tokenURIs[_tokenId]).length != 0) { - delete tokenURIs[_tokenId]; - } - - // Reorg all tokens array - uint256 tokenIndex = allTokensIndex[_tokenId]; - uint256 lastTokenIndex = allTokens.length.sub(1); - uint256 lastToken = allTokens[lastTokenIndex]; - - allTokens[tokenIndex] = lastToken; - allTokens[lastTokenIndex] = 0; - - allTokens.length--; - allTokensIndex[_tokenId] = 0; - allTokensIndex[lastToken] = tokenIndex; - } - -} diff --git a/contracts/token/ERC721/DeprecatedERC721.sol b/contracts/token/ERC721/IDeprecatedERC721.sol similarity index 88% rename from contracts/token/ERC721/DeprecatedERC721.sol rename to contracts/token/ERC721/IDeprecatedERC721.sol index 3cf1f3b2d3b..5913d4476da 100644 --- a/contracts/token/ERC721/DeprecatedERC721.sol +++ b/contracts/token/ERC721/IDeprecatedERC721.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./ERC721.sol"; +import "./IERC721.sol"; /** @@ -8,7 +8,7 @@ import "./ERC721.sol"; * @dev Only use this interface for compatibility with previously deployed contracts * Use ERC721 for interacting with new contracts which are standard-compliant */ -contract DeprecatedERC721 is ERC721 { +contract IDeprecatedERC721 is IERC721 { function takeOwnership(uint256 _tokenId) public; function transfer(address _to, uint256 _tokenId) public; function tokensOf(address _owner) public view returns (uint256[]); diff --git a/contracts/token/ERC721/IERC721.sol b/contracts/token/ERC721/IERC721.sol new file mode 100644 index 00000000000..24b7e01ceeb --- /dev/null +++ b/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,40 @@ +pragma solidity ^0.4.24; + +import "./IERC721Basic.sol"; + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract IERC721Enumerable is IERC721Basic { + function totalSupply() public view returns (uint256); + function tokenOfOwnerByIndex( + address _owner, + uint256 _index + ) + public + view + returns (uint256 _tokenId); + + function tokenByIndex(uint256 _index) public view returns (uint256); +} + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract IERC721Metadata is IERC721Basic { + function name() external view returns (string _name); + function symbol() external view returns (string _symbol); + function tokenURI(uint256 _tokenId) public view returns (string); +} + + +/** + * @title ERC-721 Non-Fungible Token Standard, full implementation interface + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract IERC721 is IERC721Basic, IERC721Enumerable, IERC721Metadata { +} diff --git a/contracts/token/ERC721/IERC721Basic.sol b/contracts/token/ERC721/IERC721Basic.sol new file mode 100644 index 00000000000..6b53f10756d --- /dev/null +++ b/contracts/token/ERC721/IERC721Basic.sol @@ -0,0 +1,80 @@ +pragma solidity ^0.4.24; + +import "../../introspection/IERC165.sol"; + + +/** + * @title ERC721 Non-Fungible Token Standard basic interface + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract IERC721Basic is IERC165 { + + bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd; + /* + * 0x80ac58cd === + * bytes4(keccak256('balanceOf(address)')) ^ + * bytes4(keccak256('ownerOf(uint256)')) ^ + * bytes4(keccak256('approve(address,uint256)')) ^ + * bytes4(keccak256('getApproved(uint256)')) ^ + * bytes4(keccak256('setApprovalForAll(address,bool)')) ^ + * bytes4(keccak256('isApprovedForAll(address,address)')) ^ + * bytes4(keccak256('transferFrom(address,address,uint256)')) ^ + * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ + * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) + */ + + bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63; + /** + * 0x780e9d63 === + * bytes4(keccak256('totalSupply()')) ^ + * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ + * bytes4(keccak256('tokenByIndex(uint256)')) + */ + + bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f; + /** + * 0x5b5e139f === + * bytes4(keccak256('name()')) ^ + * bytes4(keccak256('symbol()')) ^ + * bytes4(keccak256('tokenURI(uint256)')) + */ + + event Transfer( + address indexed _from, + address indexed _to, + uint256 indexed _tokenId + ); + event Approval( + address indexed _owner, + address indexed _approved, + uint256 indexed _tokenId + ); + event ApprovalForAll( + address indexed _owner, + address indexed _operator, + bool _approved + ); + + function balanceOf(address _owner) public view returns (uint256 _balance); + function ownerOf(uint256 _tokenId) public view returns (address _owner); + + function approve(address _to, uint256 _tokenId) public; + function getApproved(uint256 _tokenId) + public view returns (address _operator); + + function setApprovalForAll(address _operator, bool _approved) public; + function isApprovedForAll(address _owner, address _operator) + public view returns (bool); + + function transferFrom(address _from, address _to, uint256 _tokenId) public; + function safeTransferFrom(address _from, address _to, uint256 _tokenId) + public; + + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId, + bytes _data + ) + public; +} diff --git a/contracts/token/ERC721/ERC721Receiver.sol b/contracts/token/ERC721/IERC721Receiver.sol similarity index 92% rename from contracts/token/ERC721/ERC721Receiver.sol rename to contracts/token/ERC721/IERC721Receiver.sol index 45440149a66..b4c228d88f1 100644 --- a/contracts/token/ERC721/ERC721Receiver.sol +++ b/contracts/token/ERC721/IERC721Receiver.sol @@ -6,11 +6,11 @@ pragma solidity ^0.4.24; * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ -contract ERC721Receiver { +contract IERC721Receiver { /** * @dev Magic value to be returned upon successful reception of an NFT * Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`, - * which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` + * which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` */ bytes4 internal constant ERC721_RECEIVED = 0x150b7a02; diff --git a/test/crowdsale/FinalizableCrowdsale.test.js b/test/crowdsale/FinalizableCrowdsale.test.js index e0c8eb30834..ed2d5314157 100644 --- a/test/crowdsale/FinalizableCrowdsale.test.js +++ b/test/crowdsale/FinalizableCrowdsale.test.js @@ -11,7 +11,7 @@ const should = require('chai') .should(); const FinalizableCrowdsale = artifacts.require('FinalizableCrowdsaleImpl'); -const MintableToken = artifacts.require('MintableToken'); +const ERC20Mintable = artifacts.require('ERC20Mintable'); contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { const rate = new BigNumber(1000); @@ -26,7 +26,7 @@ contract('FinalizableCrowdsale', function ([_, owner, wallet, thirdparty]) { this.closingTime = this.openingTime + duration.weeks(1); this.afterClosingTime = this.closingTime + duration.seconds(1); - this.token = await MintableToken.new(); + this.token = await ERC20Mintable.new(); this.crowdsale = await FinalizableCrowdsale.new( this.openingTime, this.closingTime, rate, wallet, this.token.address, { from: owner } ); diff --git a/test/crowdsale/MintedCrowdsale.test.js b/test/crowdsale/MintedCrowdsale.test.js index 5fc89422c54..27f64e6edd2 100644 --- a/test/crowdsale/MintedCrowdsale.test.js +++ b/test/crowdsale/MintedCrowdsale.test.js @@ -5,17 +5,17 @@ const { assertRevert } = require('../helpers/assertRevert'); const BigNumber = web3.BigNumber; const MintedCrowdsale = artifacts.require('MintedCrowdsaleImpl'); -const MintableToken = artifacts.require('MintableToken'); +const ERC20Mintable = artifacts.require('ERC20Mintable'); const RBACMintableToken = artifacts.require('RBACMintableToken'); -const StandardToken = artifacts.require('StandardToken'); +const ERC20 = artifacts.require('ERC20'); contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) { const rate = new BigNumber(1000); const value = ether(5); - describe('using MintableToken', function () { + describe('using ERC20Mintable', function () { beforeEach(async function () { - this.token = await MintableToken.new(); + this.token = await ERC20Mintable.new(); this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address); await this.token.transferOwnership(this.crowdsale.address); }); @@ -45,7 +45,7 @@ contract('MintedCrowdsale', function ([_, investor, wallet, purchaser]) { describe('using non-mintable token', function () { beforeEach(async function () { - this.token = await StandardToken.new(); + this.token = await ERC20.new(); this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address); }); diff --git a/test/lifecycle/TokenDestructible.test.js b/test/lifecycle/TokenDestructible.test.js index 5aa631da51e..7e61d800f72 100644 --- a/test/lifecycle/TokenDestructible.test.js +++ b/test/lifecycle/TokenDestructible.test.js @@ -1,7 +1,7 @@ const { ethGetBalance } = require('../helpers/web3'); const TokenDestructible = artifacts.require('TokenDestructible'); -const StandardTokenMock = artifacts.require('StandardTokenMock'); +const ERC20Mock = artifacts.require('ERC20Mock'); const BigNumber = web3.BigNumber; @@ -28,7 +28,7 @@ contract('TokenDestructible', function ([_, owner]) { }); it('should send tokens to owner after destruction', async function () { - const token = await StandardTokenMock.new(tokenDestructible.address, 100); + const token = await ERC20Mock.new(tokenDestructible.address, 100); (await token.balanceOf(tokenDestructible.address)).should.be.bignumber.equal(100); (await token.balanceOf(owner)).should.be.bignumber.equal(0); diff --git a/test/ownership/CanReclaimToken.test.js b/test/ownership/CanReclaimToken.test.js index 1710ad2d60d..dd3fef62201 100644 --- a/test/ownership/CanReclaimToken.test.js +++ b/test/ownership/CanReclaimToken.test.js @@ -1,7 +1,7 @@ const { expectThrow } = require('../helpers/expectThrow'); const CanReclaimToken = artifacts.require('CanReclaimToken'); -const StandardTokenMock = artifacts.require('StandardTokenMock'); +const ERC20Mock = artifacts.require('ERC20Mock'); const BigNumber = web3.BigNumber; @@ -15,7 +15,7 @@ contract('CanReclaimToken', function ([_, owner, anyone]) { beforeEach(async function () { // Create contract and token - token = await StandardTokenMock.new(owner, 100, { from: owner }); + token = await ERC20Mock.new(owner, 100, { from: owner }); canReclaimToken = await CanReclaimToken.new({ from: owner }); // Force token into contract diff --git a/test/token/ERC20/BurnableToken.test.js b/test/token/ERC20/BurnableToken.test.js deleted file mode 100644 index 0622a48b607..00000000000 --- a/test/token/ERC20/BurnableToken.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const { shouldBehaveLikeBurnableToken } = require('./BurnableToken.behavior'); -const BurnableTokenMock = artifacts.require('BurnableTokenMock'); - -contract('BurnableToken', function ([_, owner, ...otherAccounts]) { - const initialBalance = 1000; - - beforeEach(async function () { - this.token = await BurnableTokenMock.new(owner, initialBalance, { from: owner }); - }); - - shouldBehaveLikeBurnableToken(owner, initialBalance, otherAccounts); -}); diff --git a/test/token/ERC20/CappedToken.test.js b/test/token/ERC20/CappedToken.test.js deleted file mode 100644 index 1098de2942c..00000000000 --- a/test/token/ERC20/CappedToken.test.js +++ /dev/null @@ -1,25 +0,0 @@ -const { assertRevert } = require('../../helpers/assertRevert'); -const { ether } = require('../../helpers/ether'); -const { shouldBehaveLikeMintableToken } = require('./MintableToken.behavior'); -const { shouldBehaveLikeCappedToken } = require('./CappedToken.behavior'); - -const CappedToken = artifacts.require('CappedToken'); - -contract('Capped', function ([_, owner, ...otherAccounts]) { - const cap = ether(1000); - - it('requires a non-zero cap', async function () { - await assertRevert( - CappedToken.new(0, { from: owner }) - ); - }); - - context('once deployed', async function () { - beforeEach(async function () { - this.token = await CappedToken.new(cap, { from: owner }); - }); - - shouldBehaveLikeCappedToken(owner, otherAccounts, cap); - shouldBehaveLikeMintableToken(owner, owner, otherAccounts); - }); -}); diff --git a/test/token/ERC20/DetailedERC20.test.js b/test/token/ERC20/DetailedERC20.test.js index 4d42f04e6aa..71b22a7b9a8 100644 --- a/test/token/ERC20/DetailedERC20.test.js +++ b/test/token/ERC20/DetailedERC20.test.js @@ -4,9 +4,9 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -const DetailedERC20Mock = artifacts.require('DetailedERC20Mock'); +const ERC20DetailedMock = artifacts.require('ERC20DetailedMock'); -contract('DetailedERC20', function () { +contract('ERC20Detailed', function () { let detailedERC20 = null; const _name = 'My Detailed ERC20'; @@ -14,7 +14,7 @@ contract('DetailedERC20', function () { const _decimals = 18; beforeEach(async function () { - detailedERC20 = await DetailedERC20Mock.new(_name, _symbol, _decimals); + detailedERC20 = await ERC20DetailedMock.new(_name, _symbol, _decimals); }); it('has a name', async function () { diff --git a/test/token/ERC20/StandardToken.test.js b/test/token/ERC20/ERC20.test.js similarity index 99% rename from test/token/ERC20/StandardToken.test.js rename to test/token/ERC20/ERC20.test.js index 7cd3388928b..a5ca274c79f 100644 --- a/test/token/ERC20/StandardToken.test.js +++ b/test/token/ERC20/ERC20.test.js @@ -1,7 +1,7 @@ const { assertRevert } = require('../../helpers/assertRevert'); const expectEvent = require('../../helpers/expectEvent'); -const StandardToken = artifacts.require('StandardTokenMock'); +const ERC20 = artifacts.require('ERC20Mock'); const BigNumber = web3.BigNumber; @@ -9,11 +9,11 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -contract('StandardToken', function ([_, owner, recipient, anotherAccount]) { +contract('ERC20', function ([_, owner, recipient, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; beforeEach(async function () { - this.token = await StandardToken.new(owner, 100); + this.token = await ERC20.new(owner, 100); }); describe('total supply', function () { diff --git a/test/token/ERC20/BurnableToken.behavior.js b/test/token/ERC20/ERC20Burnable.behavior.js similarity index 97% rename from test/token/ERC20/BurnableToken.behavior.js rename to test/token/ERC20/ERC20Burnable.behavior.js index 6e4e29181c6..69c5bf51541 100644 --- a/test/token/ERC20/BurnableToken.behavior.js +++ b/test/token/ERC20/ERC20Burnable.behavior.js @@ -8,7 +8,7 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -function shouldBehaveLikeBurnableToken (owner, initialBalance, [burner]) { +function shouldBehaveLikeERC20Burnable (owner, initialBalance, [burner]) { describe('burn', function () { describe('when the given amount is not greater than balance of the sender', function () { context('for a zero amount', function () { @@ -113,5 +113,5 @@ function shouldBehaveLikeBurnableToken (owner, initialBalance, [burner]) { } module.exports = { - shouldBehaveLikeBurnableToken, + shouldBehaveLikeERC20Burnable, }; diff --git a/test/token/ERC20/ERC20Burnable.test.js b/test/token/ERC20/ERC20Burnable.test.js new file mode 100644 index 00000000000..0e18e786766 --- /dev/null +++ b/test/token/ERC20/ERC20Burnable.test.js @@ -0,0 +1,12 @@ +const { shouldBehaveLikeERC20Burnable } = require('./ERC20Burnable.behavior'); +const ERC20BurnableMock = artifacts.require('ERC20BurnableMock'); + +contract('ERC20Burnable', function ([_, owner, ...otherAccounts]) { + const initialBalance = 1000; + + beforeEach(async function () { + this.token = await ERC20BurnableMock.new(owner, initialBalance, { from: owner }); + }); + + shouldBehaveLikeERC20Burnable(owner, initialBalance, otherAccounts); +}); diff --git a/test/token/ERC20/CappedToken.behavior.js b/test/token/ERC20/ERC20Capped.behavior.js similarity index 91% rename from test/token/ERC20/CappedToken.behavior.js rename to test/token/ERC20/ERC20Capped.behavior.js index 46c541c597c..004d512c042 100644 --- a/test/token/ERC20/CappedToken.behavior.js +++ b/test/token/ERC20/ERC20Capped.behavior.js @@ -7,7 +7,7 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -function shouldBehaveLikeCappedToken (minter, [anyone], cap) { +function shouldBehaveLikeERC20Capped (minter, [anyone], cap) { describe('capped token', function () { const from = minter; @@ -33,5 +33,5 @@ function shouldBehaveLikeCappedToken (minter, [anyone], cap) { } module.exports = { - shouldBehaveLikeCappedToken, + shouldBehaveLikeERC20Capped, }; diff --git a/test/token/ERC20/ERC20Capped.test.js b/test/token/ERC20/ERC20Capped.test.js new file mode 100644 index 00000000000..820a37be872 --- /dev/null +++ b/test/token/ERC20/ERC20Capped.test.js @@ -0,0 +1,25 @@ +const { assertRevert } = require('../../helpers/assertRevert'); +const { ether } = require('../../helpers/ether'); +const { shouldBehaveLikeERC20Mintable } = require('./ERC20Mintable.behavior'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); + +const ERC20Capped = artifacts.require('ERC20Capped'); + +contract('ERC20Capped', function ([_, owner, ...otherAccounts]) { + const cap = ether(1000); + + it('requires a non-zero cap', async function () { + await assertRevert( + ERC20Capped.new(0, { from: owner }) + ); + }); + + context('once deployed', async function () { + beforeEach(async function () { + this.token = await ERC20Capped.new(cap, { from: owner }); + }); + + shouldBehaveLikeERC20Capped(owner, otherAccounts, cap); + shouldBehaveLikeERC20Mintable(owner, owner, otherAccounts); + }); +}); diff --git a/test/token/ERC20/MintableToken.behavior.js b/test/token/ERC20/ERC20Mintable.behavior.js similarity index 98% rename from test/token/ERC20/MintableToken.behavior.js rename to test/token/ERC20/ERC20Mintable.behavior.js index a6f39780eef..63fb861b551 100644 --- a/test/token/ERC20/MintableToken.behavior.js +++ b/test/token/ERC20/ERC20Mintable.behavior.js @@ -7,7 +7,7 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -function shouldBehaveLikeMintableToken (owner, minter, [anyone]) { +function shouldBehaveLikeERC20Mintable (owner, minter, [anyone]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; describe('as a basic mintable token', function () { @@ -160,5 +160,5 @@ function shouldBehaveLikeMintableToken (owner, minter, [anyone]) { } module.exports = { - shouldBehaveLikeMintableToken, + shouldBehaveLikeERC20Mintable, }; diff --git a/test/token/ERC20/ERC20Mintable.test.js b/test/token/ERC20/ERC20Mintable.test.js new file mode 100644 index 00000000000..20727dafd9a --- /dev/null +++ b/test/token/ERC20/ERC20Mintable.test.js @@ -0,0 +1,10 @@ +const { shouldBehaveLikeERC20Mintable } = require('./ERC20Mintable.behavior'); +const ERC20Mintable = artifacts.require('ERC20Mintable'); + +contract('ERC20Mintable', function ([_, owner, ...otherAccounts]) { + beforeEach(async function () { + this.token = await ERC20Mintable.new({ from: owner }); + }); + + shouldBehaveLikeERC20Mintable(owner, owner, otherAccounts); +}); diff --git a/test/token/ERC20/PausableToken.test.js b/test/token/ERC20/ERC20Pausable.test.js similarity index 97% rename from test/token/ERC20/PausableToken.test.js rename to test/token/ERC20/ERC20Pausable.test.js index 5f7ccf125f4..8fbe4f70876 100644 --- a/test/token/ERC20/PausableToken.test.js +++ b/test/token/ERC20/ERC20Pausable.test.js @@ -1,9 +1,9 @@ const { assertRevert } = require('../../helpers/assertRevert'); -const PausableToken = artifacts.require('PausableTokenMock'); +const ERC20Pausable = artifacts.require('ERC20PausableMock'); -contract('PausableToken', function ([_, owner, recipient, anotherAccount]) { +contract('ERC20Pausable', function ([_, owner, recipient, anotherAccount]) { beforeEach(async function () { - this.token = await PausableToken.new(owner, 100, { from: owner }); + this.token = await ERC20Pausable.new(owner, 100, { from: owner }); }); describe('pause', function () { diff --git a/test/token/ERC20/MintableToken.test.js b/test/token/ERC20/MintableToken.test.js deleted file mode 100644 index c06380a80ce..00000000000 --- a/test/token/ERC20/MintableToken.test.js +++ /dev/null @@ -1,10 +0,0 @@ -const { shouldBehaveLikeMintableToken } = require('./MintableToken.behavior'); -const MintableToken = artifacts.require('MintableToken'); - -contract('MintableToken', function ([_, owner, ...otherAccounts]) { - beforeEach(async function () { - this.token = await MintableToken.new({ from: owner }); - }); - - shouldBehaveLikeMintableToken(owner, owner, otherAccounts); -}); diff --git a/test/token/ERC20/RBACCappedToken.test.js b/test/token/ERC20/RBACCappedToken.test.js index 3f3ca71a78e..988a415d450 100644 --- a/test/token/ERC20/RBACCappedToken.test.js +++ b/test/token/ERC20/RBACCappedToken.test.js @@ -1,7 +1,7 @@ const { ether } = require('../../helpers/ether'); const { shouldBehaveLikeRBACMintableToken } = require('./RBACMintableToken.behavior'); -const { shouldBehaveLikeMintableToken } = require('./MintableToken.behavior'); -const { shouldBehaveLikeCappedToken } = require('./CappedToken.behavior'); +const { shouldBehaveLikeERC20Mintable } = require('./ERC20Mintable.behavior'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); const RBACCappedTokenMock = artifacts.require('RBACCappedTokenMock'); @@ -13,7 +13,7 @@ contract('RBACCappedToken', function ([_, owner, minter, ...otherAccounts]) { await this.token.addMinter(minter, { from: owner }); }); - shouldBehaveLikeMintableToken(owner, minter, otherAccounts); + shouldBehaveLikeERC20Mintable(owner, minter, otherAccounts); shouldBehaveLikeRBACMintableToken(owner, otherAccounts); - shouldBehaveLikeCappedToken(minter, otherAccounts, cap); + shouldBehaveLikeERC20Capped(minter, otherAccounts, cap); }); diff --git a/test/token/ERC20/RBACMintableToken.test.js b/test/token/ERC20/RBACMintableToken.test.js index 839b73db8b6..2caf4bface8 100644 --- a/test/token/ERC20/RBACMintableToken.test.js +++ b/test/token/ERC20/RBACMintableToken.test.js @@ -1,5 +1,5 @@ const { shouldBehaveLikeRBACMintableToken } = require('./RBACMintableToken.behavior'); -const { shouldBehaveLikeMintableToken } = require('./MintableToken.behavior'); +const { shouldBehaveLikeERC20Mintable } = require('./ERC20Mintable.behavior'); const RBACMintableToken = artifacts.require('RBACMintableToken'); @@ -10,5 +10,5 @@ contract('RBACMintableToken', function ([_, owner, minter, ...otherAccounts]) { }); shouldBehaveLikeRBACMintableToken(owner, otherAccounts); - shouldBehaveLikeMintableToken(owner, minter, otherAccounts); + shouldBehaveLikeERC20Mintable(owner, minter, otherAccounts); }); diff --git a/test/token/ERC20/TokenTimelock.test.js b/test/token/ERC20/TokenTimelock.test.js index 4f3535efca5..168992707af 100644 --- a/test/token/ERC20/TokenTimelock.test.js +++ b/test/token/ERC20/TokenTimelock.test.js @@ -8,7 +8,7 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -const MintableToken = artifacts.require('MintableToken'); +const ERC20Mintable = artifacts.require('ERC20Mintable'); const TokenTimelock = artifacts.require('TokenTimelock'); contract('TokenTimelock', function ([_, owner, beneficiary]) { @@ -16,7 +16,7 @@ contract('TokenTimelock', function ([_, owner, beneficiary]) { context('with token', function () { beforeEach(async function () { - this.token = await MintableToken.new({ from: owner }); + this.token = await ERC20Mintable.new({ from: owner }); }); it('rejects a release time in the past', async function () { diff --git a/test/token/ERC20/TokenVesting.test.js b/test/token/ERC20/TokenVesting.test.js index 48dfa2bc0f9..60d773511ec 100644 --- a/test/token/ERC20/TokenVesting.test.js +++ b/test/token/ERC20/TokenVesting.test.js @@ -10,7 +10,7 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -const MintableToken = artifacts.require('MintableToken'); +const ERC20Mintable = artifacts.require('ERC20Mintable'); const TokenVesting = artifacts.require('TokenVesting'); contract('TokenVesting', function ([_, owner, beneficiary]) { @@ -44,7 +44,7 @@ contract('TokenVesting', function ([_, owner, beneficiary]) { beforeEach(async function () { this.vesting = await TokenVesting.new(beneficiary, this.start, this.cliff, this.duration, true, { from: owner }); - this.token = await MintableToken.new({ from: owner }); + this.token = await ERC20Mintable.new({ from: owner }); await this.token.mint(this.vesting.address, amount, { from: owner }); }); diff --git a/test/token/ERC721/ERC721Token.test.js b/test/token/ERC721/ERC721.test.js similarity index 94% rename from test/token/ERC721/ERC721Token.test.js rename to test/token/ERC721/ERC721.test.js index aa3056eb3db..1881c4b8fe3 100644 --- a/test/token/ERC721/ERC721Token.test.js +++ b/test/token/ERC721/ERC721.test.js @@ -1,17 +1,17 @@ const { assertRevert } = require('../../helpers/assertRevert'); -const { shouldBehaveLikeERC721BasicToken } = require('./ERC721BasicToken.behavior'); -const { shouldBehaveLikeMintAndBurnERC721Token } = require('./ERC721MintBurn.behavior'); +const { shouldBehaveLikeERC721Basic } = require('./ERC721Basic.behavior'); +const { shouldBehaveLikeMintAndBurnERC721 } = require('./ERC721MintBurn.behavior'); const { shouldSupportInterfaces } = require('../../introspection/SupportsInterface.behavior'); const _ = require('lodash'); const BigNumber = web3.BigNumber; -const ERC721Token = artifacts.require('ERC721TokenMock.sol'); +const ERC721 = artifacts.require('ERC721Mock.sol'); require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -contract('ERC721Token', function (accounts) { +contract('ERC721', function (accounts) { const name = 'Non Fungible Token'; const symbol = 'NFT'; const firstTokenId = 100; @@ -21,11 +21,11 @@ contract('ERC721Token', function (accounts) { const anyone = accounts[9]; beforeEach(async function () { - this.token = await ERC721Token.new(name, symbol, { from: creator }); + this.token = await ERC721.new(name, symbol, { from: creator }); }); - shouldBehaveLikeERC721BasicToken(accounts); - shouldBehaveLikeMintAndBurnERC721Token(accounts); + shouldBehaveLikeERC721Basic(accounts); + shouldBehaveLikeMintAndBurnERC721(accounts); describe('like a full ERC721', function () { beforeEach(async function () { diff --git a/test/token/ERC721/ERC721BasicToken.behavior.js b/test/token/ERC721/ERC721Basic.behavior.js similarity index 99% rename from test/token/ERC721/ERC721BasicToken.behavior.js rename to test/token/ERC721/ERC721Basic.behavior.js index 3eec9ff92f0..969ddceeda8 100644 --- a/test/token/ERC721/ERC721BasicToken.behavior.js +++ b/test/token/ERC721/ERC721Basic.behavior.js @@ -11,7 +11,7 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -function shouldBehaveLikeERC721BasicToken (accounts) { +function shouldBehaveLikeERC721Basic (accounts) { const firstTokenId = 1; const secondTokenId = 2; const unknownTokenId = 3; @@ -19,7 +19,7 @@ function shouldBehaveLikeERC721BasicToken (accounts) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; const RECEIVER_MAGIC_VALUE = '0x150b7a02'; - describe('like an ERC721BasicToken', function () { + describe('like an ERC721Basic', function () { beforeEach(async function () { await this.token.mint(creator, firstTokenId, { from: creator }); await this.token.mint(creator, secondTokenId, { from: creator }); @@ -521,5 +521,5 @@ function shouldBehaveLikeERC721BasicToken (accounts) { } module.exports = { - shouldBehaveLikeERC721BasicToken, + shouldBehaveLikeERC721Basic, }; diff --git a/test/token/ERC721/ERC721Basic.test.js b/test/token/ERC721/ERC721Basic.test.js new file mode 100644 index 00000000000..f86a97f5b68 --- /dev/null +++ b/test/token/ERC721/ERC721Basic.test.js @@ -0,0 +1,18 @@ +const { shouldBehaveLikeERC721Basic } = require('./ERC721Basic.behavior'); +const { shouldBehaveLikeMintAndBurnERC721 } = require('./ERC721MintBurn.behavior'); + +const BigNumber = web3.BigNumber; +const ERC721Basic = artifacts.require('ERC721BasicMock.sol'); + +require('chai') + .use(require('chai-bignumber')(BigNumber)) + .should(); + +contract('ERC721Basic', function (accounts) { + beforeEach(async function () { + this.token = await ERC721Basic.new({ from: accounts[0] }); + }); + + shouldBehaveLikeERC721Basic(accounts); + shouldBehaveLikeMintAndBurnERC721(accounts); +}); diff --git a/test/token/ERC721/ERC721BasicToken.test.js b/test/token/ERC721/ERC721BasicToken.test.js deleted file mode 100644 index 4525c7dc57d..00000000000 --- a/test/token/ERC721/ERC721BasicToken.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const { shouldBehaveLikeERC721BasicToken } = require('./ERC721BasicToken.behavior'); -const { shouldBehaveLikeMintAndBurnERC721Token } = require('./ERC721MintBurn.behavior'); - -const BigNumber = web3.BigNumber; -const ERC721BasicToken = artifacts.require('ERC721BasicTokenMock.sol'); - -require('chai') - .use(require('chai-bignumber')(BigNumber)) - .should(); - -contract('ERC721BasicToken', function (accounts) { - beforeEach(async function () { - this.token = await ERC721BasicToken.new({ from: accounts[0] }); - }); - - shouldBehaveLikeERC721BasicToken(accounts); - shouldBehaveLikeMintAndBurnERC721Token(accounts); -}); diff --git a/test/token/ERC721/ERC721MintBurn.behavior.js b/test/token/ERC721/ERC721MintBurn.behavior.js index c09480a38b7..faf9d756f21 100644 --- a/test/token/ERC721/ERC721MintBurn.behavior.js +++ b/test/token/ERC721/ERC721MintBurn.behavior.js @@ -5,14 +5,14 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -function shouldBehaveLikeMintAndBurnERC721Token (accounts) { +function shouldBehaveLikeMintAndBurnERC721 (accounts) { const firstTokenId = 1; const secondTokenId = 2; const unknownTokenId = 3; const creator = accounts[0]; const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - describe('like a mintable and burnable ERC721Token', function () { + describe('like a mintable and burnable ERC721', function () { beforeEach(async function () { await this.token.mint(creator, firstTokenId, { from: creator }); await this.token.mint(creator, secondTokenId, { from: creator }); @@ -106,5 +106,5 @@ function shouldBehaveLikeMintAndBurnERC721Token (accounts) { } module.exports = { - shouldBehaveLikeMintAndBurnERC721Token, + shouldBehaveLikeMintAndBurnERC721, }; diff --git a/test/token/ERC721/ERC721PausableToken.test.js b/test/token/ERC721/ERC721Pausable.test.js similarity index 61% rename from test/token/ERC721/ERC721PausableToken.test.js rename to test/token/ERC721/ERC721Pausable.test.js index 03274ffb2b1..7c03c888ab5 100644 --- a/test/token/ERC721/ERC721PausableToken.test.js +++ b/test/token/ERC721/ERC721Pausable.test.js @@ -1,16 +1,16 @@ const { shouldBehaveLikeERC721PausedToken } = require('./ERC721PausedToken.behavior'); -const { shouldBehaveLikeERC721BasicToken } = require('./ERC721BasicToken.behavior'); +const { shouldBehaveLikeERC721Basic } = require('./ERC721Basic.behavior'); const BigNumber = web3.BigNumber; -const ERC721PausableToken = artifacts.require('ERC721PausableTokenMock.sol'); +const ERC721Pausable = artifacts.require('ERC721PausableMock.sol'); require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -contract('ERC721PausableToken', function ([_, owner, recipient, operator, ...otherAccounts]) { +contract('ERC721Pausable', function ([_, owner, recipient, operator, ...otherAccounts]) { beforeEach(async function () { - this.token = await ERC721PausableToken.new({ from: owner }); + this.token = await ERC721Pausable.new({ from: owner }); }); context('when token is paused', function () { @@ -22,7 +22,7 @@ contract('ERC721PausableToken', function ([_, owner, recipient, operator, ...oth }); context('when token is not paused yet', function () { - shouldBehaveLikeERC721BasicToken([owner, ...otherAccounts]); + shouldBehaveLikeERC721Basic([owner, ...otherAccounts]); }); context('when token is paused and then unpaused', function () { @@ -31,6 +31,6 @@ contract('ERC721PausableToken', function ([_, owner, recipient, operator, ...oth await this.token.unpause({ from: owner }); }); - shouldBehaveLikeERC721BasicToken([owner, ...otherAccounts]); + shouldBehaveLikeERC721Basic([owner, ...otherAccounts]); }); }); diff --git a/test/token/ERC721/ERC721PausedToken.behavior.js b/test/token/ERC721/ERC721PausedToken.behavior.js index 2ef21ec0790..d14e6a39533 100644 --- a/test/token/ERC721/ERC721PausedToken.behavior.js +++ b/test/token/ERC721/ERC721PausedToken.behavior.js @@ -13,7 +13,7 @@ function shouldBehaveLikeERC721PausedToken (owner, [recipient, operator]) { const mockData = '0x42'; const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - describe('like a paused ERC721Token', function () { + describe('like a paused ERC721', function () { beforeEach(async function () { await this.token.mint(owner, firstTokenId, { from: owner }); });