first version stickers
This commit is contained in:
parent
eebb8b352b
commit
9054fa4ad1
|
@ -0,0 +1,23 @@
|
|||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
import "../../common/Controlled.sol";
|
||||
import "../../token/UnfungibleToken.sol";
|
||||
|
||||
|
||||
contract Sticker is Controlled, UnfungibleToken {
|
||||
|
||||
uint256 public nextId;
|
||||
mapping (uint256 => bytes32) public dataHash;
|
||||
|
||||
function generateToken(address _owner, bytes32 _dataHash) external onlyController {
|
||||
tokenId = nextId++;
|
||||
dataHash[tokenId] = _dataHash;
|
||||
_mint(_owner, tokenId);
|
||||
}
|
||||
|
||||
function destroyToken(address _owner, uint256 _tokenId) external onlyController {
|
||||
delete dataHash[_tokenId];
|
||||
_burn(_owner, _tokenId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
import "./StickerPack.sol";
|
||||
import "../../token/ERC20Token.sol";
|
||||
import "../../token/ApproveAndCallFallBack.sol";
|
||||
import "../../common/Controlled.sol";
|
||||
|
||||
/**
|
||||
* @dev
|
||||
*/
|
||||
contract StickerMarket is Controlled, ApproveAndCallFallBack {
|
||||
event Register(uint256 packId, bytes32 dataHash, uint256 dataPrice);
|
||||
event Unregister(uint256 packId);
|
||||
event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
|
||||
|
||||
struct Pack {
|
||||
bytes32 dataHash; // merkle tree root of "ipfs://stickerdata-json"
|
||||
uint256 price;
|
||||
address owner;
|
||||
}
|
||||
StickerPack public stickerPack = new StickerPack();
|
||||
ERC20Token public snt;
|
||||
mapping(uint256 => Pack) public packs;
|
||||
uint256 public nextId;
|
||||
|
||||
//TODO: add list of packs available
|
||||
/**
|
||||
* @notice Constructor
|
||||
* @param _owner Authority address
|
||||
* @param _snt SNT token
|
||||
*/
|
||||
constructor(
|
||||
ERC20Token _snt,
|
||||
uint256 _registerPrice
|
||||
)
|
||||
public
|
||||
{
|
||||
snt = _snt;
|
||||
}
|
||||
|
||||
function buy(uint256 _packId) external {
|
||||
_buy(msg.sender, packs[_packId]);
|
||||
}
|
||||
|
||||
function receiveApproval(address _from, uint256 _amount, address _token, bytes calldata _data) external {
|
||||
require(_token == address(snt), "Bad token");
|
||||
require(_token == address(msg.sender), "Bad call");
|
||||
require(_data.length == 36, "Bad data length");
|
||||
uint256 packId = abiDecodeBuy(_data);
|
||||
Pack memory pack = packs[packId];
|
||||
require(pack.price == _amount, "Bad amount");
|
||||
_buy(_from, pack);
|
||||
}
|
||||
|
||||
function register(bytes32 _dataHash, uint256 _price, address _owner) external onlyController {
|
||||
uint256 id = nextId++;
|
||||
packs[id] = Pack(_dataHash, _price, _owner);
|
||||
emit Register(id, _datahash, _price);
|
||||
}
|
||||
|
||||
function unregister(uint256 _packId) external onlyController {
|
||||
delete packs[_packId];
|
||||
emit Unregister(id);
|
||||
}
|
||||
|
||||
function migrateMarket(address _newMarket) external onlyController {
|
||||
stickerPack.changeController(_newMarket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice This method can be used by the controller to extract mistakenly
|
||||
* sent tokens to this contract.
|
||||
* @param _token The address of the token contract that you want to recover
|
||||
* set to 0 in case you want to extract ether.
|
||||
*/
|
||||
function claimTokens(address _token) external onlyController {
|
||||
if (_token == address(0)) {
|
||||
address(controller).transfer(address(this).balance);
|
||||
return;
|
||||
}
|
||||
ERC20Token token = ERC20Token(_token);
|
||||
uint256 balance = token.balanceOf(address(this));
|
||||
token.transfer(controller, balance);
|
||||
emit ClaimedTokens(_token, controller, balance);
|
||||
}
|
||||
|
||||
function _buy(address _buyer, Pack memory _pack) internal {
|
||||
require(_pack.dataHash != bytes32(0), "Bad pack");
|
||||
require(snt.transferFrom(_from, _pack.owner, _pack.price), "Bad payment");
|
||||
stickerPack.generateToken(_from, pack.dataHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decodes abi encoded data with selector for "buy(uint256)".
|
||||
* @param _data Abi encoded data.
|
||||
* @return Decoded registry call.
|
||||
*/
|
||||
function abiDecodeBuy(
|
||||
bytes _data
|
||||
)
|
||||
private
|
||||
pure
|
||||
returns(
|
||||
uint256 packId
|
||||
)
|
||||
{
|
||||
bytes4 sig;
|
||||
assembly {
|
||||
sig := mload(add(_data, add(0x20, 0)))
|
||||
packId := mload(add(_data, 36))
|
||||
}
|
||||
require(sig == bytes4(keccak256("buy(uint256)")), "Bad method sig");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
import "../../common/Controlled.sol";
|
||||
import "../../token/UnfungibleToken.sol";
|
||||
import "./Sticker.sol";
|
||||
|
||||
|
||||
contract StickerPack is Controlled, UnfungibleToken {
|
||||
|
||||
Sticker public sticker = new Sticker();
|
||||
uint256 public nextId;
|
||||
mapping(uint256 => bytes32) public dataHash;
|
||||
mapping(bytes32 => bool) public unpacked;
|
||||
|
||||
function unpack(uint256 _tokenId, bytes32[] memory _proof, bytes32 _stickerData) external {
|
||||
address owner = ownerOf(_tokenId);
|
||||
require(owner == msg.sender, "Unauthorized");
|
||||
require(MerkleProof.verifyProof(_proof, dataHash[_tokenId], _stickerData), "Invalid proof");
|
||||
bytes32 unpackedHash = keccak256(abi.encodePacked(_tokenId, _stickerData));
|
||||
require(!unpacked[unpackedHash], "Duplicate unpacking");
|
||||
unpacked[unpackedHash] = true;
|
||||
sticker.generateToken(owner, _stickerData);
|
||||
|
||||
}
|
||||
|
||||
function repack(uint256 _packId, uint256 _stickerToken) external {
|
||||
address owner = ownerOf(_packToken);
|
||||
require(owner == ownerOf(_stickerToken) && owner == msg.sender, "Unauthorized");
|
||||
bytes32 stickerData = sticker.dataHash(_stickerToken);
|
||||
bytes32 unpackedHash = keccak256(abi.encodePacked(_packId, stickerData));
|
||||
require(unpacked[unpackedHash],"Bad operation");
|
||||
delete unpacked[unpackedHash];
|
||||
sticker.destroyToken(owner, _tokenId2);
|
||||
}
|
||||
|
||||
function generateToken(address _owner, bytes32 _dataHash) external onlyController {
|
||||
tokenId = nextId++;
|
||||
dataHash[tokenId] = _dataHash;
|
||||
_mint(_owner, tokenId);
|
||||
}
|
||||
|
||||
function isStickerInPack(uint256 _packId, bytes32[] _proof, bytes32 _stickerData) public view returns (bool){
|
||||
require(MerkleProof.verifyProof(_proof, dataHash[_tokenId], _stickerData), "Invalid proof");
|
||||
bytes32 unpackedHash = keccak256(abi.encodePacked(_tokenId, _stickerData));
|
||||
return !unpacked[unpackedHash];
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
contract ApproveAndCallFallBack {
|
||||
function receiveApproval(address from, uint256 _amount, address _token, bytes memory _data) public;
|
||||
interface ApproveAndCallFallBack {
|
||||
function receiveApproval(address from, uint256 _amount, address _token, bytes calldata _data) external;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
/**
|
||||
* @title ERC-721 Non-Fungible Token Standard
|
||||
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
|
||||
* Note: the ERC-165 identifier for this interface is 0x80ac58cd
|
||||
*/
|
||||
interface ERC721 /* is ERC165 */ {
|
||||
/**
|
||||
* @dev This emits when ownership of any NFT changes by any mechanism.
|
||||
* This event emits when NFTs are created (`from` == 0) and destroyed
|
||||
* (`to` == 0). Exception: during contract creation, any number of NFTs
|
||||
* may be created and assigned without emitting Transfer. At the time of
|
||||
* any transfer, the approved address for that NFT (if any) is reset to none.
|
||||
*/
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
|
||||
|
||||
/**
|
||||
* @dev This emits when the approved address for an NFT is changed or
|
||||
* reaffirmed. The zero address indicates there is no approved address.
|
||||
* When a Transfer event emits, this also indicates that the approved
|
||||
* address for that NFT (if any) is reset to none.
|
||||
*/
|
||||
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
|
||||
|
||||
/**
|
||||
* @dev This emits when an operator is enabled or disabled for an owner.
|
||||
* The operator can manage all NFTs of the owner.
|
||||
*/
|
||||
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
|
||||
|
||||
/**
|
||||
* @notice Count all NFTs assigned to an owner
|
||||
* @dev NFTs assigned to the zero address are considered invalid, and this
|
||||
* function throws for queries about the zero address.
|
||||
* @param _owner An address for whom to query the balance
|
||||
* @return The number of NFTs owned by `_owner`, possibly zero
|
||||
*/
|
||||
function balanceOf(address _owner) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @notice Find the owner of an NFT
|
||||
* @dev NFTs assigned to zero address are considered invalid, and queries
|
||||
* about them do throw.
|
||||
* @param _tokenId The identifier for an NFT
|
||||
* @return The address of the owner of the NFT
|
||||
*/
|
||||
function ownerOf(uint256 _tokenId) external view returns (address);
|
||||
|
||||
/**
|
||||
* @notice Transfers the ownership of an NFT from one address to another address
|
||||
* @dev Throws unless `msg.sender` is the current owner, an authorized
|
||||
* operator, or the approved address for this NFT. Throws if `_from` is
|
||||
* not the current owner. Throws if `_to` is the zero address. Throws if
|
||||
* `_tokenId` is not a valid NFT. When transfer is complete, this function
|
||||
* checks if `_to` is a smart contract (code size > 0). If so, it calls
|
||||
* `onERC721Received` on `_to` and throws if the return value is not
|
||||
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
|
||||
* @param _from The current owner of the NFT
|
||||
* @param _to The new owner
|
||||
* @param _tokenId The NFT to transfer
|
||||
* @param data Additional data with no specified format, sent in call to `_to`
|
||||
*/
|
||||
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external payable;
|
||||
|
||||
/**
|
||||
* @notice Transfers the ownership of an NFT from one address to another address
|
||||
* @dev This works identically to the other function with an extra data parameter,
|
||||
* except this function just sets data to ""
|
||||
* @param _from The current owner of the NFT
|
||||
* @param _to The new owner
|
||||
* @param _tokenId The NFT to transfer
|
||||
*/
|
||||
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
|
||||
|
||||
/**
|
||||
* @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
|
||||
* TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
|
||||
* THEY MAY BE PERMANENTLY LOST
|
||||
* @dev Throws unless `msg.sender` is the current owner, an authorized
|
||||
* operator, or the approved address for this NFT. Throws if `_from` is
|
||||
* not the current owner. Throws if `_to` is the zero address. Throws if
|
||||
* `_tokenId` is not a valid NFT.
|
||||
* @param _from The current owner of the NFT
|
||||
* @param _to The new owner
|
||||
* @param _tokenId The NFT to transfer
|
||||
*/
|
||||
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
|
||||
|
||||
/**
|
||||
* @notice Set or reaffirm the approved address for an NFT
|
||||
* @dev The zero address indicates there is no approved address.
|
||||
* @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
|
||||
* operator of the current owner.
|
||||
* @param _approved The new approved NFT controller
|
||||
* @param _tokenId The NFT to approve
|
||||
*/
|
||||
function approve(address _approved, uint256 _tokenId) external payable;
|
||||
|
||||
/**
|
||||
* @notice Enable or disable approval for a third party ("operator") to manage
|
||||
* all of `msg.sender`'s assets.
|
||||
* @dev Emits the ApprovalForAll event. The contract MUST allow
|
||||
* multiple operators per owner.
|
||||
* @param _operator Address to add to the set of authorized operators.
|
||||
* @param _approved True if the operator is approved, false to revoke approval
|
||||
*/
|
||||
function setApprovalForAll(address _operator, bool _approved) external;
|
||||
|
||||
/**
|
||||
* @notice Get the approved address for a single NFT
|
||||
* @dev Throws if `_tokenId` is not a valid NFT
|
||||
* @param _tokenId The NFT to find the approved address for
|
||||
* @return The approved address for this NFT, or the zero address if there is none
|
||||
*/
|
||||
function getApproved(uint256 _tokenId) external view returns (address);
|
||||
|
||||
/**
|
||||
* @notice Query if an address is an authorized operator for another address
|
||||
* @param _owner The address that owns the NFTs
|
||||
* @param _operator The address that acts on behalf of the owner
|
||||
* @return True if `_operator` is an approved operator for `_owner`, false otherwise
|
||||
*/
|
||||
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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.
|
||||
* @return `true` if the contract implements `interfaceID` and
|
||||
* `interfaceID` is not 0xffffffff, `false` otherwise
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceID) external view returns (bool);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
interface ERC721TokenReceiver {
|
||||
/**
|
||||
* @notice Handle the receipt of an NFT
|
||||
* @dev The ERC721 smart contract calls this function on the
|
||||
* recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return
|
||||
* of other than the magic value MUST result in the transaction being reverted.
|
||||
* @notice The contract address is always the message sender.
|
||||
* @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 transferred
|
||||
* @param _data Additional data with no specified format
|
||||
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
|
||||
* unless throwing
|
||||
*/
|
||||
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
pragma solidity >=0.5.0 <0.6.0;
|
||||
|
||||
import "./ERC721.sol";
|
||||
import "./ERC721Receiver.sol";
|
||||
import "../common/SafeMath.sol";
|
||||
|
||||
/**
|
||||
* @title ERC721 Non-Fungible Token Standard basic implementation
|
||||
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
|
||||
*/
|
||||
contract UnfungibleToken is ERC165, ERC721 {
|
||||
using SafeMath for uint256;
|
||||
|
||||
|
||||
// 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) private _tokenOwner;
|
||||
|
||||
// Mapping from token ID to approved address
|
||||
mapping (uint256 => address) private _tokenApprovals;
|
||||
|
||||
// Mapping from owner to number of owned token
|
||||
mapping (address => uint256) private _ownedTokensCount;
|
||||
|
||||
// Mapping from owner to operator approvals
|
||||
mapping (address => mapping (address => bool)) private _operatorApprovals;
|
||||
|
||||
bytes4 private 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)'))
|
||||
*/
|
||||
|
||||
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), "Invalid address");
|
||||
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), "Invalid address");
|
||||
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, "Bad operation");
|
||||
require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "Unauthorized");
|
||||
|
||||
_tokenApprovals[tokenId] = to;
|
||||
emit Approval(owner, to, tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the approved address for a token ID, or zero if no address set
|
||||
* Reverts if the token ID does not exist.
|
||||
* @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) {
|
||||
require(_exists(tokenId), "Bad token id");
|
||||
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, "Bad operation");
|
||||
_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), "Unauthorized");
|
||||
|
||||
_transferFrom(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(_checkOnERC721Received(from, to, tokenId, _data), "Unauthorized");
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
function _mint(address to, uint256 tokenId) internal {
|
||||
require(to != address(0), "Invalid address");
|
||||
require(!_exists(tokenId), "Bad operation");
|
||||
|
||||
_tokenOwner[tokenId] = to;
|
||||
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
|
||||
|
||||
emit Transfer(address(0), to, tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to burn a specific token
|
||||
* Reverts if the token does not exist
|
||||
* Deprecated, use _burn(uint256) instead.
|
||||
* @param owner owner of the token to burn
|
||||
* @param tokenId uint256 ID of the token being burned
|
||||
*/
|
||||
function _burn(address owner, uint256 tokenId) internal {
|
||||
require(ownerOf(tokenId) == owner, "Unauthorized");
|
||||
|
||||
_clearApproval(tokenId);
|
||||
|
||||
_ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1);
|
||||
_tokenOwner[tokenId] = address(0);
|
||||
|
||||
emit Transfer(owner, address(0), 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
|
||||
*/
|
||||
function _burn(uint256 tokenId) internal {
|
||||
_burn(ownerOf(tokenId), tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to transfer ownership of a given token ID to another address.
|
||||
* As opposed to transferFrom, this imposes no restrictions on msg.sender.
|
||||
* @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) internal {
|
||||
require(ownerOf(tokenId) == from, "Unauthorized");
|
||||
require(to != address(0), "Invalid address");
|
||||
|
||||
_clearApproval(tokenId);
|
||||
|
||||
_ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
|
||||
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
|
||||
|
||||
_tokenOwner[tokenId] = to;
|
||||
|
||||
emit Transfer(from, to, tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 _checkOnERC721Received(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Private function to clear current approval of a given token ID
|
||||
* @param tokenId uint256 ID of the token to be transferred
|
||||
*/
|
||||
function _clearApproval(uint256 tokenId) private {
|
||||
if (_tokenApprovals[tokenId] != address(0)) {
|
||||
_tokenApprovals[tokenId] = address(0);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue