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 IERC721Receiverpull/1261/head^2
parent
b6943263d2
commit
2e0713becb
@ -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 |
||||
{} |
||||
} |
||||
|
@ -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); |
@ -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); |
@ -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); |
@ -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); |
||||
} |
@ -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 { |
@ -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); |
||||
} |
@ -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 |
||||
{} |
||||
} |
||||
|
@ -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); |
||||
} |
||||
} |
||||
|
@ -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; |
||||
|
@ -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; |
@ -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, |
@ -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 |
||||
); |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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 { |
||||
} |
||||
|
@ -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); |
||||
} |
||||
} |
||||
|
@ -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); |
||||
} |
||||
} |
@ -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 |
@ -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; |
||||
} |
||||
|
||||
} |
@ -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 { |
||||
} |
@ -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; |
||||
} |
@ -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); |
||||
}); |
@ -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); |
||||
}); |
||||
}); |
@ -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); |
||||
}); |
@ -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); |
||||
}); |
||||
}); |
@ -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); |
||||
}); |
@ -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 () { |
@ -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); |
||||
}); |
@ -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); |
||||
}); |
@ -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); |
||||
}); |
Loading…
Reference in new issue