Unverified Commit c46f0353 by Santiago Palladino Committed by GitHub

Update ERC721 to latest 1.11.0 from OpenZeppelin-solidity (#11)

* Update ERC721 to latest 1.11.0 from OpenZeppelin-solidity

* Hardcode supported interfaces instead of using lookup table. This avoids shifting storage when extending supports interface.

* Update build artifacts

* Fix linter errors
parent 8f4610e0
......@@ -507,5 +507,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-23T17:26:04.150Z"
"updatedAt": "2018-08-27T20:45:00.202Z"
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"contractName": "ECRecovery",
"abi": [],
"bytecode": "0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146080604052600080fd00a165627a7a7230582095f4276bbe910450a81a9f24c9666db9e203894c52a3fdbade54b3b5738e695e0029",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fd00a165627a7a7230582095f4276bbe910450a81a9f24c9666db9e203894c52a3fdbade54b3b5738e695e0029",
"bytecode": "0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146080604052600080fd00a165627a7a723058205b790ca6c853c7e32fb7ac75e4760a40d639601e5e2dcf7ace2abff11907a7450029",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fd00a165627a7a723058205b790ca6c853c7e32fb7ac75e4760a40d639601e5e2dcf7ace2abff11907a7450029",
"sourceMap": "309:1640:1:-;;132:2:-1;166:7;155:9;146:7;137:37;252:7;246:14;243:1;238:23;232:4;229:33;270:1;265:20;;;;222:63;;265:20;274:9;222:63;;298:9;295:1;288:20;328:4;319:7;311:22;352:7;343;336:24",
"deployedSourceMap": "309:1640:1:-;;;;;;;;",
"source": "pragma solidity ^0.4.21;\n\n\n/**\n * @title Eliptic curve signature operations\n *\n * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d\n *\n * TODO Remove this library once solidity supports passing a signature to ecrecover.\n * See https://github.com/ethereum/solidity/issues/864\n *\n */\n\nlibrary ECRecovery {\n\n /**\n * @dev Recover signer address from a message by using their signature\n * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.\n * @param sig bytes signature, the signature is generated using web3.eth.sign()\n */\n function recover(bytes32 hash, bytes sig)\n internal\n pure\n returns (address)\n {\n bytes32 r;\n bytes32 s;\n uint8 v;\n\n // Check the signature length\n if (sig.length != 65) {\n return (address(0));\n }\n\n // Divide the signature in r, s and v variables\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n\n // Version of signature should be 27 or 28, but 0 and 1 are also possible versions\n if (v < 27) {\n v += 27;\n }\n\n // If the version is correct return the signer address\n if (v != 27 && v != 28) {\n return (address(0));\n } else {\n // solium-disable-next-line arg-overflow\n return ecrecover(hash, v, r, s);\n }\n }\n\n /**\n * toEthSignedMessageHash\n * @dev prefix a bytes32 value with \"\\x19Ethereum Signed Message:\"\n * @dev and hash the result\n */\n function toEthSignedMessageHash(bytes32 hash)\n internal\n pure\n returns (bytes32)\n {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(\n \"\\x19Ethereum Signed Message:\\n32\",\n hash\n );\n }\n}\n",
......@@ -691,7 +691,7 @@
"name": "ecrecover",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4776,
"referencedDeclaration": 4871,
"src": "1504:9:1",
"typeDescriptions": {
"typeIdentifier": "t_function_ecrecover_pure$_t_bytes32_$_t_uint8_$_t_bytes32_$_t_bytes32_$returns$_t_address_$",
......@@ -975,7 +975,7 @@
"name": "keccak256",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4778,
"referencedDeclaration": 4873,
"src": "1873:9:1",
"typeDescriptions": {
"typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$",
......@@ -1775,7 +1775,7 @@
"name": "ecrecover",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4776,
"referencedDeclaration": 4871,
"src": "1504:9:1",
"typeDescriptions": {
"typeIdentifier": "t_function_ecrecover_pure$_t_bytes32_$_t_uint8_$_t_bytes32_$_t_bytes32_$returns$_t_address_$",
......@@ -2059,7 +2059,7 @@
"name": "keccak256",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4778,
"referencedDeclaration": 4873,
"src": "1873:9:1",
"typeDescriptions": {
"typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$",
......@@ -2177,9 +2177,9 @@
},
"compiler": {
"name": "solc",
"version": "0.4.24+commit.e67f0147.Emscripten.clang"
"version": "0.4.23+commit.124ca40d.Emscripten.clang"
},
"networks": {},
"schemaVersion": "2.0.1",
"updatedAt": "2018-08-23T14:35:50.612Z"
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-27T20:45:00.202Z"
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"contractName": "MerkleProof",
"abi": [],
"bytecode": "0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146080604052600080fd00a165627a7a72305820ccc41da397538bcd62e42f28e2999ceae0d28d7b83d6c3bfbda80241383dc2fc0029",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fd00a165627a7a72305820ccc41da397538bcd62e42f28e2999ceae0d28d7b83d6c3bfbda80241383dc2fc0029",
"bytecode": "0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146080604052600080fd00a165627a7a72305820de3b6f14f81089bc425ad158bc3ccc2cf37c3fb8768224f30fc867a34dbc88ef0029",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fd00a165627a7a72305820de3b6f14f81089bc425ad158bc3ccc2cf37c3fb8768224f30fc867a34dbc88ef0029",
"sourceMap": "189:1052:2:-;;132:2:-1;166:7;155:9;146:7;137:37;252:7;246:14;243:1;238:23;232:4;229:33;270:1;265:20;;;;222:63;;265:20;274:9;222:63;;298:9;295:1;288:20;328:4;319:7;311:22;352:7;343;336:24",
"deployedSourceMap": "189:1052:2:-;;;;;;;;",
"source": "pragma solidity ^0.4.21;\n\n\n/*\n * @title MerkleProof\n * @dev Merkle proof verification\n * @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol\n */\nlibrary MerkleProof {\n /*\n * @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves\n * and each pair of pre-images is sorted.\n * @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree\n * @param _root Merkle root\n * @param _leaf Leaf of Merkle tree\n */\n function verifyProof(bytes32[] _proof, bytes32 _root, bytes32 _leaf) internal pure returns (bool) {\n bytes32 computedHash = _leaf;\n\n for (uint256 i = 0; i < _proof.length; i++) {\n bytes32 proofElement = _proof[i];\n\n if (computedHash < proofElement) {\n // Hash(current computed hash + current element of the proof)\n computedHash = keccak256(computedHash, proofElement);\n } else {\n // Hash(current element of the proof + current computed hash)\n computedHash = keccak256(proofElement, computedHash);\n }\n }\n\n // Check if the computed hash (root) is equal to the provided root\n return computedHash == _root;\n }\n}\n",
......@@ -297,7 +297,7 @@
"name": "keccak256",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4778,
"referencedDeclaration": 4873,
"src": "1077:9:2",
"typeDescriptions": {
"typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$",
......@@ -406,7 +406,7 @@
"name": "keccak256",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4778,
"referencedDeclaration": 4873,
"src": "930:9:2",
"typeDescriptions": {
"typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$",
......@@ -1088,7 +1088,7 @@
"name": "keccak256",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4778,
"referencedDeclaration": 4873,
"src": "1077:9:2",
"typeDescriptions": {
"typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$",
......@@ -1197,7 +1197,7 @@
"name": "keccak256",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 4778,
"referencedDeclaration": 4873,
"src": "930:9:2",
"typeDescriptions": {
"typeIdentifier": "t_function_sha3_pure$__$returns$_t_bytes32_$",
......@@ -1591,9 +1591,9 @@
},
"compiler": {
"name": "solc",
"version": "0.4.24+commit.e67f0147.Emscripten.clang"
"version": "0.4.23+commit.124ca40d.Emscripten.clang"
},
"networks": {},
"schemaVersion": "2.0.1",
"updatedAt": "2018-08-23T14:35:50.612Z"
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-27T20:45:00.202Z"
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
pragma solidity ^0.4.21;
/**
* @title ERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface ERC165 {
/**
* @notice Query if a contract implements an interface
* @param _interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool);
}
pragma solidity ^0.4.21;
import "./ERC165.sol";
/**
* @title ERC165Support
* @dev Implements ERC165 returning true for ERC165 interface identifier
*/
contract ERC165Support is ERC165 {
bytes4 internal constant InterfaceId_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool)
{
return _supportsInterface(_interfaceId);
}
function _supportsInterface(bytes4 _interfaceId)
internal
view
returns (bool)
{
return _interfaceId == InterfaceId_ERC165;
}
}
......@@ -7,15 +7,22 @@ contract ERC721ReceiverMock is ERC721Receiver {
bytes4 retval;
bool reverts;
event Received(address _address, uint256 _tokenId, bytes _data, uint256 _gas);
event Received(
address _operator,
address _from,
uint256 _tokenId,
bytes _data,
uint256 _gas
);
function ERC721ReceiverMock(bytes4 _retval, bool _reverts) public {
constructor(bytes4 _retval, bool _reverts) public {
retval = _retval;
reverts = _reverts;
}
function onERC721Received(
address _address,
address _operator,
address _from,
uint256 _tokenId,
bytes _data
)
......@@ -24,7 +31,8 @@ contract ERC721ReceiverMock is ERC721Receiver {
{
require(!reverts);
emit Received(
_address,
_operator,
_from,
_tokenId,
_data,
gasleft() // msg.gas was deprecated in solidityv0.4.21
......
......@@ -9,7 +9,7 @@ import "../token/ERC721/ERC721Token.sol";
* and a public setter for metadata URI
*/
contract ERC721TokenMock is ERC721Token {
function ERC721TokenMock(string name, string symbol) public {
constructor(string name, string symbol) public {
ERC721Token.initialize(name, symbol);
}
......
......@@ -9,7 +9,14 @@ import "./ERC721Basic.sol";
*/
contract ERC721Enumerable is ERC721Basic {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId);
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) public view returns (uint256);
}
......@@ -19,8 +26,8 @@ contract ERC721Enumerable is ERC721Basic {
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Metadata is ERC721Basic {
function name() public view returns (string _name);
function symbol() public view returns (string _symbol);
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) public view returns (string);
}
......
pragma solidity ^0.4.21;
import "../../introspection/ERC165.sol";
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Basic {
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);
contract ERC721Basic is ERC165 {
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 exists(uint256 _tokenId) public view returns (bool _exists);
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId) public view returns (address _operator);
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 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)
public;
function safeTransferFrom(
address _from,
address _to,
......
......@@ -4,7 +4,7 @@ import "./ERC721Receiver.sol";
contract ERC721Holder is ERC721Receiver {
function onERC721Received(address, uint256, bytes) public returns(bytes4) {
function onERC721Received(address, address, uint256, bytes) public returns(bytes4) {
return ERC721_RECEIVED;
}
}
......@@ -9,22 +9,30 @@ pragma solidity ^0.4.21;
contract ERC721Receiver {
/**
* @dev Magic value to be returned upon successful reception of an NFT
* Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`,
* Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
* which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
*/
bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;
bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safetransfer`. This function MAY throw to revert and reject the
* transfer. This function MUST use 50,000 gas or less. Return of other
* than the magic value MUST result in the transaction being reverted.
* transfer. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the contract address is always the message sender.
* @param _from The sending address
* @param _operator The address which called `safeTransferFrom` function
* @param _from The address which previously owned the token
* @param _tokenId The NFT identifier which is being transfered
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address _from, uint256 _tokenId, bytes _data) public returns(bytes4);
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes _data
)
public
returns(bytes4);
}
......@@ -2,6 +2,7 @@ pragma solidity ^0.4.21;
import "./ERC721.sol";
import "./ERC721BasicToken.sol";
import "../../introspection/ERC165.sol";
import "zos-lib/contracts/migrations/Migratable.sol";
......@@ -11,7 +12,24 @@ import "zos-lib/contracts/migrations/Migratable.sol";
* 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 Migratable, ERC721, ERC721BasicToken {
contract ERC721Token is Migratable, ERC165Support, ERC721BasicToken, ERC721 {
bytes4 private constant InterfaceId_ERC721Enumerable = 0x780e9d63;
/**
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
* bytes4(keccak256('tokenByIndex(uint256)'))
*/
bytes4 private constant InterfaceId_ERC721Metadata = 0x5b5e139f;
/**
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
* bytes4(keccak256('tokenURI(uint256)'))
*/
// Token name
string internal name_;
......@@ -19,7 +37,7 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
string internal symbol_;
// Mapping from owner to list of owned token IDs
mapping (address => uint256[]) internal ownedTokens;
mapping(address => uint256[]) internal ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) internal ownedTokensIndex;
......@@ -41,11 +59,20 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
symbol_ = _symbol;
}
function _supportsInterface(bytes4 _interfaceId)
internal
view
returns (bool)
{
return super._supportsInterface(_interfaceId) ||
_interfaceId == InterfaceId_ERC721Enumerable || _interfaceId == InterfaceId_ERC721Metadata;
}
/**
* @dev Gets the token name
* @return string representing the token name
*/
function name() public view returns (string) {
function name() external view returns (string) {
return name_;
}
......@@ -53,13 +80,13 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
* @dev Gets the token symbol
* @return string representing the token symbol
*/
function symbol() public view returns (string) {
function symbol() external view returns (string) {
return symbol_;
}
/**
* @dev Returns an URI for a given token ID
* @dev Throws if the token ID does not exist. May return an empty string.
* 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) {
......@@ -73,7 +100,14 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
* @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) {
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256)
{
require(_index < balanceOf(_owner));
return ownedTokens[_owner][_index];
}
......@@ -88,7 +122,7 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* @dev Reverts if the index is greater or equal to the total number of tokens
* 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
*/
......@@ -99,7 +133,7 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
/**
* @dev Internal function to set the token URI for a given token
* @dev Reverts if the token ID does not exist
* 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
*/
......@@ -145,7 +179,7 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
/**
* @dev Internal function to mint a new token
* @dev Reverts if the given token ID already exists
* 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
*/
......@@ -158,7 +192,7 @@ contract ERC721Token is Migratable, ERC721, ERC721BasicToken {
/**
* @dev Internal function to burn a specific token
* @dev Reverts if the token does not exist
* 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
*/
......
import { soliditySha3 } from 'web3-utils';
const INTERFACE_ID_LENGTH = 4;
export default (interfaces = []) => {
const interfaceIdBuffer = interfaces
.map(methodSignature => soliditySha3(methodSignature)) // keccak256
.map(h =>
Buffer
.from(h.substring(2), 'hex')
.slice(0, 4) // bytes4()
)
.reduce((memo, bytes) => {
for (let i = 0; i < INTERFACE_ID_LENGTH; i++) {
memo[i] = memo[i] ^ bytes[i]; // xor
}
return memo;
}, Buffer.alloc(INTERFACE_ID_LENGTH));
return `0x${interfaceIdBuffer.toString('hex')}`;
};
import makeInterfaceId from '../helpers/makeInterfaceId';
const INTERFACE_IDS = {
ERC165: makeInterfaceId([
'supportsInterface(bytes4)',
]),
ERC721: makeInterfaceId([
'balanceOf(address)',
'ownerOf(uint256)',
'approve(address,uint256)',
'getApproved(uint256)',
'setApprovalForAll(address,bool)',
'isApprovedForAll(address,address)',
'transferFrom(address,address,uint256)',
'safeTransferFrom(address,address,uint256)',
'safeTransferFrom(address,address,uint256,bytes)',
]),
ERC721Enumerable: makeInterfaceId([
'totalSupply()',
'tokenOfOwnerByIndex(address,uint256)',
'tokenByIndex(uint256)',
]),
ERC721Metadata: makeInterfaceId([
'name()',
'symbol()',
'tokenURI(uint256)',
]),
ERC721Exists: makeInterfaceId([
'exists(uint256)',
]),
};
export default function (interfaces = []) {
describe('ERC165\'s supportsInterface(bytes4)', function () {
beforeEach(function () {
this.thing = this.mock || this.token;
});
for (let k of interfaces) {
const interfaceId = INTERFACE_IDS[k];
describe(k, function () {
it('should use less than 30k gas', async function () {
const gasEstimate = await this.thing.supportsInterface.estimateGas(interfaceId);
gasEstimate.should.be.lte(30000);
});
it('is supported', async function () {
const isSupported = await this.thing.supportsInterface(interfaceId);
isSupported.should.eq(true);
});
});
}
});
}
......@@ -99,17 +99,6 @@ export default function shouldMintAndBurnERC721Token (accounts) {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(ZERO_ADDRESS);
});
it('emits an approval event', async function () {
logs.length.should.be.equal(2);
logs[0].event.should.be.eq('Approval');
logs[0].args._owner.should.be.equal(sender);
logs[0].args._approved.should.be.equal(ZERO_ADDRESS);
logs[0].args._tokenId.should.be.bignumber.equal(tokenId);
logs[1].event.should.be.eq('Transfer');
});
});
describe('when the given token ID was not tracked by this contract', function () {
......
import assertRevert from '../../helpers/assertRevert';
import shouldBehaveLikeERC721BasicToken from './ERC721BasicToken.behaviour';
import shouldMintAndBurnERC721Token from './ERC721MintBurn.behaviour';
import shouldSupportInterfaces from '../../introspection/SupportsInterface.behavior';
import _ from 'lodash';
const BigNumber = web3.BigNumber;
......@@ -196,4 +197,12 @@ contract('ERC721Token', function (accounts) {
});
});
});
shouldSupportInterfaces([
'ERC165',
'ERC721',
'ERC721Exists',
'ERC721Enumerable',
'ERC721Metadata',
]);
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment