// File: @0xcert/ethereum-erc721/contracts/tokens/ERC721.sol
pragma solidity ^0.4.24;
/**
* @dev ERC-721 non-fungible token standard. See https://goo.gl/pc9yoS.
*/
interface ERC721 {
/**
* @dev 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
);
/**
* @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
* considered invalid, and this function throws for queries about the zero address.
* @param _owner Address for whom to query the balance.
*/
function balanceOf(
address _owner
)
external
view
returns (uint256);
/**
* @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
* invalid, and queries about them do throw.
* @param _tokenId The identifier for an NFT.
*/
function ownerOf(
uint256 _tokenId
)
external
view
returns (address);
/**
* @dev Transfers the ownership of an NFT from one address to another address.
* @notice 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,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 _data
)
external;
/**
* @dev Transfers the ownership of an NFT from one address to another address.
* @notice 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;
/**
* @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.
* @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
* they mayb be permanently lost.
* @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;
/**
* @dev Set or reaffirm the approved address for an NFT.
* @notice The zero address indicates there is no approved address. 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;
/**
* @dev Enables or disables approval for a third party ("operator") to manage all of
* `msg.sender`'s assets. It also emits the ApprovalForAll event.
* @notice The contract MUST allow multiple operators per owner.
* @param _operator Address to add to the set of authorized operators.
* @param _approved True if the operators is approved, false to revoke approval.
*/
function setApprovalForAll(
address _operator,
bool _approved
)
external;
/**
* @dev Get the approved address for a single NFT.
* @notice Throws if `_tokenId` is not a valid NFT.
* @param _tokenId The NFT to find the approved address for.
*/
function getApproved(
uint256 _tokenId
)
external
view
returns (address);
/**
* @dev Returns true if `_operator` is an approved operator for `_owner`, false otherwise.
* @param _owner The address that owns the NFTs.
* @param _operator The address that acts on behalf of the owner.
*/
function isApprovedForAll(
address _owner,
address _operator
)
external
view
returns (bool);
}
// File: @0xcert/ethereum-erc721/contracts/tokens/ERC721Enumerable.sol
pragma solidity ^0.4.24;
/**
* @dev Optional enumeration extension for ERC-721 non-fungible token standard.
* See https://goo.gl/pc9yoS.
*/
interface ERC721Enumerable {
/**
* @dev Returns a count of valid NFTs tracked by this contract, where each one of them has an
* assigned and queryable owner not equal to the zero address.
*/
function totalSupply()
external
view
returns (uint256);
/**
* @dev Returns the token identifier for the `_index`th NFT. Sort order is not specified.
* @param _index A counter less than `totalSupply()`.
*/
function tokenByIndex(
uint256 _index
)
external
view
returns (uint256);
/**
* @dev Returns the token identifier for the `_index`th NFT assigned to `_owner`. Sort order is
* not specified. It throws if `_index` >= `balanceOf(_owner)` or if `_owner` is the zero address,
* representing invalid NFTs.
* @param _owner An address where we are interested in NFTs owned by them.
* @param _index A counter less than `balanceOf(_owner)`.
*/
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
external
view
returns (uint256);
}
// File: @0xcert/ethereum-erc721/contracts/tokens/ERC721Metadata.sol
pragma solidity ^0.4.24;
/**
* @dev Optional metadata extension for ERC-721 non-fungible token standard.
* See https://goo.gl/pc9yoS.
*/
interface ERC721Metadata {
/**
* @dev Returns a descriptive name for a collection of NFTs in this contract.
*/
function name()
external
view
returns (string _name);
/**
* @dev Returns a abbreviated name for a collection of NFTs in this contract.
*/
function symbol()
external
view
returns (string _symbol);
/**
* @dev Returns a distinct Uniform Resource Identifier (URI) for a given asset. It Throws if
* `_tokenId` is not a valid NFT. URIs are defined in RFC3986. The URI may point to a JSON file
* that conforms to the "ERC721 Metadata JSON Schema".
*/
function tokenURI(uint256 _tokenId)
external
view
returns (string);
}
// File: @0xcert/ethereum-utils/contracts/utils/ERC165.sol
pragma solidity ^0.4.24;
/**
* @dev A standard for detecting smart contract interfaces. See https://goo.gl/cxQCse.
*/
interface ERC165 {
/**
* @dev Checks if the smart contract includes a specific interface.
* @notice This function uses less than 30,000 gas.
* @param _interfaceID The interface identifier, as specified in ERC-165.
*/
function supportsInterface(
bytes4 _interfaceID
)
external
view
returns (bool);
}
// File: @0xcert/ethereum-utils/contracts/utils/SupportsInterface.sol
pragma solidity ^0.4.24;
/**
* @dev Implementation of standard for detect smart contract interfaces.
*/
contract SupportsInterface is
ERC165
{
/**
* @dev Mapping of supported intefraces.
* @notice You must not set element 0xffffffff to true.
*/
mapping(bytes4 => bool) internal supportedInterfaces;
/**
* @dev Contract constructor.
*/
constructor()
public
{
supportedInterfaces[0x01ffc9a7] = true; // ERC165
}
/**
* @dev Function to check which interfaces are suported by this contract.
* @param _interfaceID Id of the interface.
*/
function supportsInterface(
bytes4 _interfaceID
)
external
view
returns (bool)
{
return supportedInterfaces[_interfaceID];
}
}
// File: @0xcert/ethereum-utils/contracts/math/SafeMath.sol
pragma solidity ^0.4.24;
/**
* @dev Math operations with safety checks that throw on error. This contract is based
* on the source code at https://goo.gl/iyQsmU.
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
* @param _a Factor number.
* @param _b Factor number.
*/
function mul(
uint256 _a,
uint256 _b
)
internal
pure
returns (uint256)
{
if (_a == 0) {
return 0;
}
uint256 c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
* @param _a Dividend number.
* @param _b Divisor number.
*/
function div(
uint256 _a,
uint256 _b
)
internal
pure
returns (uint256)
{
uint256 c = _a / _b;
// assert(b > 0); // Solidity automatically throws when dividing by 0
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
* @param _a Minuend number.
* @param _b Subtrahend number.
*/
function sub(
uint256 _a,
uint256 _b
)
internal
pure
returns (uint256)
{
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
* @param _a Number.
* @param _b Number.
*/
function add(
uint256 _a,
uint256 _b
)
internal
pure
returns (uint256)
{
uint256 c = _a + _b;
assert(c >= _a);
return c;
}
}
// File: @0xcert/ethereum-utils/contracts/ownership/Ownable.sol
pragma solidity ^0.4.24;
/**
* @dev The contract has an owner address, and provides basic authorization control whitch
* simplifies the implementation of user permissions. This contract is based on the source code
* at https://goo.gl/n2ZGVt.
*/
contract Ownable {
address public owner;
/**
* @dev An event which is triggered when the owner is changed.
* @param previousOwner The address of the previous owner.
* @param newOwner The address of the new owner.
*/
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The constructor sets the original `owner` of the contract to the sender account.
*/
constructor()
public
{
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(
address _newOwner
)
onlyOwner
public
{
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
// File: @0xcert/ethereum-utils/contracts/ownership/Claimable.sol
pragma solidity ^0.4.24;
/**
* @dev The contract has an owner address, and provides basic authorization control whitch
* simplifies the implementation of user permissions. This contract is based on the source code
* at goo.gl/CfEAkv and upgrades Ownable contracts with additional claim step which makes ownership
* transfers less prone to errors.
*/
contract Claimable is Ownable {
address public pendingOwner;
/**
* @dev An event which is triggered when the owner is changed.
* @param previousOwner The address of the previous owner.
* @param newOwner The address of the new owner.
*/
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Allows the current owner to give new owner ability to claim the ownership of the contract.
* This differs from the Owner's function in that it allows setting pedingOwner address to 0x0,
* which effectively cancels an active claim.
* @param _newOwner The address which can claim ownership of the contract.
*/
function transferOwnership(
address _newOwner
)
onlyOwner
public
{
pendingOwner = _newOwner;
}
/**
* @dev Allows the current pending owner to claim the ownership of the contract. It emits
* OwnershipTransferred event and resets pending owner to 0.
*/
function claimOwnership()
public
{
require(msg.sender == pendingOwner);
address previousOwner = owner;
owner = pendingOwner;
pendingOwner = 0;
emit OwnershipTransferred(previousOwner, owner);
}
}
// File: contracts/Adminable.sol
pragma solidity ^0.4.24;
/**
* @title Adminable
* @dev Allows to manage privilages to special contract functionality.
*/
contract Adminable is Claimable {
mapping(address => uint) public adminsMap;
address[] public adminList;
/**
* @dev Returns true, if provided address has special privilages, otherwise false
* @param adminAddress - address to check
*/
function isAdmin(address adminAddress)
public
view
returns(bool isIndeed)
{
if (adminAddress == owner) return true;
if (adminList.length == 0) return false;
return (adminList[adminsMap[adminAddress]] == adminAddress);
}
/**
* @dev Grants special rights for address holder
* @param adminAddress - address of future admin
*/
function addAdmin(address adminAddress)
public
onlyOwner
returns(uint index)
{
require(!isAdmin(adminAddress), "Address already has admin rights!");
adminsMap[adminAddress] = adminList.push(adminAddress)-1;
return adminList.length-1;
}
/**
* @dev Removes special rights for provided address
* @param adminAddress - address of current admin
*/
function removeAdmin(address adminAddress)
public
onlyOwner
returns(uint index)
{
// we can not remove owner from admin role
require(owner != adminAddress, "Owner can not be removed from admin role!");
require(isAdmin(adminAddress), "Provided address is not admin.");
uint rowToDelete = adminsMap[adminAddress];
address keyToMove = adminList[adminList.length-1];
adminList[rowToDelete] = keyToMove;
adminsMap[keyToMove] = rowToDelete;
adminList.length--;
return rowToDelete;
}
/**
* @dev modifier Throws if called by any account other than the owner.
*/
modifier onlyAdmin() {
require(isAdmin(msg.sender), "Can be executed only by admin accounts!");
_;
}
}
// File: contracts/Pausable.sol
pragma solidity ^0.4.24;
/**
* @title Pausable
* @dev Base contract which allows children to implement an emergency stop mechanism for mainenance purposes
*/
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev modifier to allow actions only when the contract IS paused
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev modifier to allow actions only when the contract IS NOT paused
*/
modifier whenPaused {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause()
external
onlyOwner
whenNotPaused
returns (bool)
{
paused = true;
emit Pause();
return true;
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause()
external
onlyOwner
whenPaused
returns (bool)
{
paused = false;
emit Unpause();
return true;
}
}
// File: contracts/MarbleNFTCandidateInterface.sol
pragma solidity ^0.4.24;
/**
* @title Marble NFT Candidate Contract
* @dev Contracts allows public audiance to create Marble NFT candidates. All our candidates for NFT goes through our services to figure out if they are suitable for Marble NFT.
* once their are picked our other contract will create NFT with same owner as candite and plcae it to minting auction. In minitng auction everyone can buy created NFT until duration period.
* If duration is over, and noone has bought NFT, then creator of candidate can take Marble NFT from minting auction to his collection.
*/
interface MarbleNFTCandidateInterface {
/**
* @dev Sets minimal price for creating Marble NFT Candidate
* @param _minimalMintingPrice Minimal price asked from creator of Marble NFT candidate (weis)
*/
function setMinimalPrice(uint256 _minimalMintingPrice)
external;
/**
* @dev Returns true if URI is already a candidate. Otherwise false.
* @param _uri URI to check
*/
function isCandidate(string _uri)
external
view
returns(bool isIndeed);
/**
* @dev Creates Marble NFT Candidate. This candidate will go through our processing. If it's suitable, then Marble NFT is created.
* @param _uri URI of resource you want to transform to Marble NFT
*/
function createCandidate(string _uri)
external
payable
returns(uint index);
/**
* @dev Removes URI from candidate list.
* @param _uri URI to be removed from candidate list.
*/
function removeCandidate(string _uri)
external;
/**
* @dev Returns total count of candidates.
*/
function getCandidatesCount()
external
view
returns(uint256 count);
/**
* @dev Transforms URI to hash.
* @param _uri URI to be transformed to hash.
*/
function getUriHash(string _uri)
external
view
returns(uint256 hash);
/**
* @dev Returns Candidate model by URI
* @param _uri URI representing candidate
*/
function getCandidate(string _uri)
external
view
returns(
uint256 index,
address owner,
uint256 mintingPrice,
string url,
uint256 created);
}
// File: contracts/MarbleDutchAuctionInterface.sol
pragma solidity ^0.4.24;
/**
* @title Marble Dutch Auction Interface
* @dev describes all externaly accessible functions neccessery to run Marble Auctions
*/
interface MarbleDutchAuctionInterface {
/**
* @dev Sets new auctioneer cut, in case we are to cheap :))
* @param _cut - percent cut the auctioneer takes on each auction, must be between 0-100. Values 0-10,000 map to 0%-100%.
*/
function setAuctioneerCut(
uint256 _cut
)
external;
/**
* @dev Sets new auctioneer delayed cut, in case we are not earning much during creating NFTs initial auctions!
* @param _cut Percent cut the auctioneer takes on each auction, must be between 0-10000. Values 0-10,000 map to 0%-100%.
*/
function setAuctioneerDelayedCancelCut(
uint256 _cut
)
external;
/**
* @dev Sets an addresses of ERC 721 contract owned/admined by same entity.
* @param _nftAddress Address of ERC 721 contract
*/
function setNFTContract(address _nftAddress)
external;
/**
* @dev Creates new auction without special logic. It allows user to sell owned Marble NFTs
* @param _tokenId ID of token to auction, sender must be owner.
* @param _startingPrice Price of item (in wei) at beginning of auction.
* @param _endingPrice Price of item (in wei) at end of auction.
* @param _duration Length of time to move between starting price and ending price (in seconds) - it determines dynamic state of auction
*/
function createAuction(
uint256 _tokenId,
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration
)
external;
/**
* @dev Creates and begins a new minting auction. Minitng auction is initial auction allowing to challenge newly Minted Marble NFT.
* If no-one buy NFT during dynamic state of auction, then seller (original creator of NFT) will be allowed to become owner of NFT. It means during dynamic (duration)
* state of auction, it won't be possible to use cancelAuction function by seller!
* @param _tokenId - ID of token to auction, sender must be owner.
* @param _startingPrice - Price of item (in wei) at beginning of auction.
* @param _endingPrice - Price of item (in wei) at end of auction.
* @param _duration - Length of time to move between starting price and ending price (in seconds).
* @param _seller - Seller, if not the message sender
*/
function createMintingAuction(
uint256 _tokenId,
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration,
address _seller
)
external;
/**
* @dev It allows seller to cancel auction and get back Marble NFT.
* @param _tokenId ID of token on auction
*/
function cancelAuction(
uint256 _tokenId
)
external;
/**
* @dev It allows seller to cancel auction and get back Marble NFT.
* @param _tokenId ID of token on auction
*/
function cancelAuctionWhenPaused(
uint256 _tokenId
)
external;
/**
* @dev Bids on an open auction, completing the auction and transferring ownership of the NFT if enough Ether is supplied.
* @param _tokenId ID of token to bid on.
*/
function bid(
uint256 _tokenId
)
external
payable;
/**
* @dev Returns the current price of an auction.
* @param _tokenId ID of the token price we are checking.
*/
function getCurrentPrice(uint256 _tokenId)
external
view
returns (uint256);
/**
* @dev Returns the count of all existing auctions.
*/
function totalAuctions()
external
view
returns (uint256);
/**
* @dev Returns NFT ID by its index.
* @param _index A counter less than `totalSupply()`.
*/
function tokenInAuctionByIndex(
uint256 _index
)
external
view
returns (uint256);
/**
* @dev Returns the n-th NFT ID from a list of owner's tokens.
* @param _seller Token owner's address.
* @param _index Index number representing n-th token in owner's list of tokens.
*/
function tokenOfSellerByIndex(
address _seller,
uint256 _index
)
external
view
returns (uint256);
/**
* @dev Returns the count of all existing auctions.
*/
function totalAuctionsBySeller(
address _seller
)
external
view
returns (uint256);
/**
* @dev Returns true if the NFT is on auction.
* @param _tokenId ID of the token to be checked.
*/
function isOnAuction(uint256 _tokenId)
external
view
returns (bool isIndeed);
/**
* @dev Returns auction info for an NFT on auction.
* @param _tokenId ID of NFT placed in auction
*/
function getAuction(uint256 _tokenId)
external
view
returns
(
address seller,
uint256 startingPrice,
uint256 endingPrice,
uint256 duration,
uint256 startedAt,
bool canBeCanceled
);
/**
* @dev remove NFT reference from auction conrtact, should be use only when NFT is being burned
* @param _tokenId ID of token on auction
*/
function removeAuction(
uint256 _tokenId
)
external;
}
// File: @0xcert/ethereum-erc721/contracts/tokens/ERC721TokenReceiver.sol
pragma solidity ^0.4.24;
/**
* @dev ERC-721 interface for accepting safe transfers. See https://goo.gl/pc9yoS.
*/
interface ERC721TokenReceiver {
/**
* @dev Handle the receipt of a NFT. 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.
* Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing.
* @notice The contract address is always the message sender. A wallet/broker/auction application
* MUST implement the wallet interface if it will accept safe transfers.
* @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.
*/
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes _data
)
external
returns(bytes4);
}
// File: @0xcert/ethereum-utils/contracts/utils/AddressUtils.sol
pragma solidity ^0.4.24;
/**
* @dev Utility library of inline functions on addresses.
*/
library AddressUtils {
/**
* @dev Returns whether the target address is a contract.
* @param _addr Address to check.
*/
function isContract(
address _addr
)
internal
view
returns (bool)
{
uint256 size;
/**
* XXX Currently there is no better way to check if there is a contract in an address than to
* check the size of the code at that address.
* See https://ethereum.stackexchange.com/a/14016/36603 for more details about how this works.
* TODO: Check this again before the Serenity release, because all addresses will be
* contracts then.
*/
assembly { size := extcodesize(_addr) } // solium-disable-line security/no-inline-assembly
return size > 0;
}
}
// File: @0xcert/ethereum-erc721/contracts/tokens/NFToken.sol
pragma solidity ^0.4.24;
/**
* @dev Implementation of ERC-721 non-fungible token standard.
*/
contract NFToken is
ERC721,
SupportsInterface
{
using SafeMath for uint256;
using AddressUtils for address;
/**
* @dev A mapping from NFT ID to the address that owns it.
*/
mapping (uint256 => address) internal idToOwner;
/**
* @dev Mapping from NFT ID to approved address.
*/
mapping (uint256 => address) internal idToApprovals;
/**
* @dev Mapping from owner address to count of his tokens.
*/
mapping (address => uint256) internal ownerToNFTokenCount;
/**
* @dev Mapping from owner address to mapping of operator addresses.
*/
mapping (address => mapping (address => bool)) internal ownerToOperators;
/**
* @dev Magic value of a smart contract that can recieve NFT.
* Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
*/
bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;
/**
* @dev 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.
* @param _from Sender of NFT (if address is zero address it indicates token creation).
* @param _to Receiver of NFT (if address is zero address it indicates token destruction).
* @param _tokenId The NFT that got transfered.
*/
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.
* @param _owner Owner of NFT.
* @param _approved Address that we are approving.
* @param _tokenId NFT which we are approving.
*/
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.
* @param _owner Owner of NFT.
* @param _operator Address to which we are setting operator rights.
* @param _approved Status of operator rights(true if operator rights are given and false if
* revoked).
*/
event ApprovalForAll(
address indexed _owner,
address indexed _operator,
bool _approved
);
/**
* @dev Guarantees that the msg.sender is an owner or operator of the given NFT.
* @param _tokenId ID of the NFT to validate.
*/
modifier canOperate(
uint256 _tokenId
) {
address tokenOwner = idToOwner[_tokenId];
require(tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender]);
_;
}
/**
* @dev Guarantees that the msg.sender is allowed to transfer NFT.
* @param _tokenId ID of the NFT to transfer.
*/
modifier canTransfer(
uint256 _tokenId
) {
address tokenOwner = idToOwner[_tokenId];
require(
tokenOwner == msg.sender
|| getApproved(_tokenId) == msg.sender
|| ownerToOperators[tokenOwner][msg.sender]
);
_;
}
/**
* @dev Guarantees that _tokenId is a valid Token.
* @param _tokenId ID of the NFT to validate.
*/
modifier validNFToken(
uint256 _tokenId
) {
require(idToOwner[_tokenId] != address(0));
_;
}
/**
* @dev Contract constructor.
*/
constructor()
public
{
supportedInterfaces[0x80ac58cd] = true; // ERC721
}
/**
* @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
* considered invalid, and this function throws for queries about the zero address.
* @param _owner Address for whom to query the balance.
*/
function balanceOf(
address _owner
)
external
view
returns (uint256)
{
require(_owner != address(0));
return ownerToNFTokenCount[_owner];
}
/**
* @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
* invalid, and queries about them do throw.
* @param _tokenId The identifier for an NFT.
*/
function ownerOf(
uint256 _tokenId
)
external
view
returns (address _owner)
{
_owner = idToOwner[_tokenId];
require(_owner != address(0));
}
/**
* @dev Transfers the ownership of an NFT from one address to another address.
* @notice 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,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 _data
)
external
{
_safeTransferFrom(_from, _to, _tokenId, _data);
}
/**
* @dev Transfers the ownership of an NFT from one address to another address.
* @notice 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
{
_safeTransferFrom(_from, _to, _tokenId, "");
}
/**
* @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.
* @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else
* they maybe be permanently lost.
* @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
canTransfer(_tokenId)
validNFToken(_tokenId)
{
address tokenOwner = idToOwner[_tokenId];
require(tokenOwner == _from);
require(_to != address(0));
_transfer(_to, _tokenId);
}
/**
* @dev Set or reaffirm the approved address for an NFT.
* @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
* the current NFT owner, or an authorized operator of the current owner.
* @param _approved Address to be approved for the given NFT ID.
* @param _tokenId ID of the token to be approved.
*/
function approve(
address _approved,
uint256 _tokenId
)
external
canOperate(_tokenId)
validNFToken(_tokenId)
{
address tokenOwner = idToOwner[_tokenId];
require(_approved != tokenOwner);
idToApprovals[_tokenId] = _approved;
emit Approval(tokenOwner, _approved, _tokenId);
}
/**
* @dev Enables or disables approval for a third party ("operator") to manage all of
* `msg.sender`'s assets. It also emits the ApprovalForAll event.
* @notice This works even if sender doesn't own any tokens at the time.
* @param _operator Address to add to the set of authorized operators.
* @param _approved True if the operators is approved, false to revoke approval.
*/
function setApprovalForAll(
address _operator,
bool _approved
)
external
{
require(_operator != address(0));
ownerToOperators[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}
/**
* @dev Get the approved address for a single NFT.
* @notice Throws if `_tokenId` is not a valid NFT.
* @param _tokenId ID of the NFT to query the approval of.
*/
function getApproved(
uint256 _tokenId
)
public
view
validNFToken(_tokenId)
returns (address)
{
return idToApprovals[_tokenId];
}
/**
* @dev Checks if `_operator` is an approved operator for `_owner`.
* @param _owner The address that owns the NFTs.
* @param _operator The address that acts on behalf of the owner.
*/
function isApprovedForAll(
address _owner,
address _operator
)
external
view
returns (bool)
{
require(_owner != address(0));
require(_operator != address(0));
return ownerToOperators[_owner][_operator];
}
/**
* @dev Actually perform the safeTransferFrom.
* @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 _data
)
internal
canTransfer(_tokenId)
validNFToken(_tokenId)
{
address tokenOwner = idToOwner[_tokenId];
require(tokenOwner == _from);
require(_to != address(0));
_transfer(_to, _tokenId);
if (_to.isContract()) {
bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
require(retval == MAGIC_ON_ERC721_RECEIVED);
}
}
/**
* @dev Actually preforms the transfer.
* @notice Does NO checks.
* @param _to Address of a new owner.
* @param _tokenId The NFT that is being transferred.
*/
function _transfer(
address _to,
uint256 _tokenId
)
private
{
address from = idToOwner[_tokenId];
clearApproval(_tokenId);
removeNFToken(from, _tokenId);
addNFToken(_to, _tokenId);
emit Transfer(from, _to, _tokenId);
}
/**
* @dev Mints a new NFT.
* @notice This is a private function which should be called from user-implemented external
* mint function. Its purpose is to show and properly initialize data structures when using this
* implementation.
* @param _to The address that will own the minted NFT.
* @param _tokenId of the NFT to be minted by the msg.sender.
*/
function _mint(
address _to,
uint256 _tokenId
)
internal
{
require(_to != address(0));
require(_tokenId != 0);
require(idToOwner[_tokenId] == address(0));
addNFToken(_to, _tokenId);
emit Transfer(address(0), _to, _tokenId);
}
/**
* @dev Burns a NFT.
* @notice This is a private function which should be called from user-implemented external
* burn function. Its purpose is to show and properly initialize data structures when using this
* implementation.
* @param _owner Address of the NFT owner.
* @param _tokenId ID of the NFT to be burned.
*/
function _burn(
address _owner,
uint256 _tokenId
)
validNFToken(_tokenId)
internal
{
clearApproval(_tokenId);
removeNFToken(_owner, _tokenId);
emit Transfer(_owner, address(0), _tokenId);
}
/**
* @dev Clears the current approval of a given NFT ID.
* @param _tokenId ID of the NFT to be transferred.
*/
function clearApproval(
uint256 _tokenId
)
private
{
if(idToApprovals[_tokenId] != 0)
{
delete idToApprovals[_tokenId];
}
}
/**
* @dev Removes a NFT from owner.
* @notice Use and override this function with caution. Wrong usage can have serious consequences.
* @param _from Address from wich we want to remove the NFT.
* @param _tokenId Which NFT we want to remove.
*/
function removeNFToken(
address _from,
uint256 _tokenId
)
internal
{
require(idToOwner[_tokenId] == _from);
assert(ownerToNFTokenCount[_from] > 0);
ownerToNFTokenCount[_from] = ownerToNFTokenCount[_from].sub(1);
delete idToOwner[_tokenId];
}
/**
* @dev Assignes a new NFT to owner.
* @notice Use and override this function with caution. Wrong usage can have serious consequences.
* @param _to Address to wich we want to add the NFT.
* @param _tokenId Which NFT we want to add.
*/
function addNFToken(
address _to,
uint256 _tokenId
)
internal
{
require(idToOwner[_tokenId] == address(0));
idToOwner[_tokenId] = _to;
ownerToNFTokenCount[_to] = ownerToNFTokenCount[_to].add(1);
}
}
// File: @0xcert/ethereum-erc721/contracts/tokens/NFTokenMetadata.sol
pragma solidity ^0.4.24;
/**
* @dev Optional metadata implementation for ERC-721 non-fungible token standard.
*/
contract NFTokenMetadata is
NFToken,
ERC721Metadata
{
/**
* @dev A descriptive name for a collection of NFTs.
*/
string internal nftName;
/**
* @dev An abbreviated name for NFTokens.
*/
string internal nftSymbol;
/**
* @dev Mapping from NFT ID to metadata uri.
*/
mapping (uint256 => string) internal idToUri;
/**
* @dev Contract constructor.
* @notice When implementing this contract don't forget to set nftName and nftSymbol.
*/
constructor()
public
{
supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
}
/**
* @dev Burns a NFT.
* @notice This is a internal function which should be called from user-implemented external
* burn function. Its purpose is to show and properly initialize data structures when using this
* implementation.
* @param _owner Address of the NFT owner.
* @param _tokenId ID of the NFT to be burned.
*/
function _burn(
address _owner,
uint256 _tokenId
)
internal
{
super._burn(_owner, _tokenId);
if (bytes(idToUri[_tokenId]).length != 0) {
delete idToUri[_tokenId];
}
}
/**
* @dev Set a distinct URI (RFC 3986) for a given NFT ID.
* @notice this is a internal function which should be called from user-implemented external
* function. Its purpose is to show and properly initialize data structures when using this
* implementation.
* @param _tokenId Id for which we want uri.
* @param _uri String representing RFC 3986 URI.
*/
function _setTokenUri(
uint256 _tokenId,
string _uri
)
validNFToken(_tokenId)
internal
{
idToUri[_tokenId] = _uri;
}
/**
* @dev Returns a descriptive name for a collection of NFTokens.
*/
function name()
external
view
returns (string _name)
{
_name = nftName;
}
/**
* @dev Returns an abbreviated name for NFTokens.
*/
function symbol()
external
view
returns (string _symbol)
{
_symbol = nftSymbol;
}
/**
* @dev A distinct URI (RFC 3986) for a given NFT.
* @param _tokenId Id for which we want uri.
*/
function tokenURI(
uint256 _tokenId
)
validNFToken(_tokenId)
external
view
returns (string)
{
return idToUri[_tokenId];
}
}
// File: @0xcert/ethereum-erc721/contracts/tokens/NFTokenEnumerable.sol
pragma solidity ^0.4.24;
/**
* @dev Optional enumeration implementation for ERC-721 non-fungible token standard.
*/
contract NFTokenEnumerable is
NFToken,
ERC721Enumerable
{
/**
* @dev Array of all NFT IDs.
*/
uint256[] internal tokens;
/**
* @dev Mapping from token ID its index in global tokens array.
*/
mapping(uint256 => uint256) internal idToIndex;
/**
* @dev Mapping from owner to list of owned NFT IDs.
*/
mapping(address => uint256[]) internal ownerToIds;
/**
* @dev Mapping from NFT ID to its index in the owner tokens list.
*/
mapping(uint256 => uint256) internal idToOwnerIndex;
/**
* @dev Contract constructor.
*/
constructor()
public
{
supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
}
/**
* @dev Mints a new NFT.
* @notice This is a private function which should be called from user-implemented external
* mint function. Its purpose is to show and properly initialize data structures when using this
* implementation.
* @param _to The address that will own the minted NFT.
* @param _tokenId of the NFT to be minted by the msg.sender.
*/
function _mint(
address _to,
uint256 _tokenId
)
internal
{
super._mint(_to, _tokenId);
tokens.push(_tokenId);
idToIndex[_tokenId] = tokens.length.sub(1);
}
/**
* @dev Burns a NFT.
* @notice This is a private function which should be called from user-implemented external
* burn function. Its purpose is to show and properly initialize data structures when using this
* implementation.
* @param _owner Address of the NFT owner.
* @param _tokenId ID of the NFT to be burned.
*/
function _burn(
address _owner,
uint256 _tokenId
)
internal
{
super._burn(_owner, _tokenId);
assert(tokens.length > 0);
uint256 tokenIndex = idToIndex[_tokenId];
// Sanity check. This could be removed in the future.
assert(tokens[tokenIndex] == _tokenId);
uint256 lastTokenIndex = tokens.length.sub(1);
uint256 lastToken = tokens[lastTokenIndex];
tokens[tokenIndex] = lastToken;
tokens.length--;
// Consider adding a conditional check for the last token in order to save GAS.
idToIndex[lastToken] = tokenIndex;
idToIndex[_tokenId] = 0;
}
/**
* @dev Removes a NFT from an address.
* @notice Use and override this function with caution. Wrong usage can have serious consequences.
* @param _from Address from wich we want to remove the NFT.
* @param _tokenId Which NFT we want to remove.
*/
function removeNFToken(
address _from,
uint256 _tokenId
)
internal
{
super.removeNFToken(_from, _tokenId);
assert(ownerToIds[_from].length > 0);
uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
uint256 lastTokenIndex = ownerToIds[_from].length.sub(1);
uint256 lastToken = ownerToIds[_from][lastTokenIndex];
ownerToIds[_from][tokenToRemoveIndex] = lastToken;
ownerToIds[_from].length--;
// Consider adding a conditional check for the last token in order to save GAS.
idToOwnerIndex[lastToken] = tokenToRemoveIndex;
idToOwnerIndex[_tokenId] = 0;
}
/**
* @dev Assignes a new NFT to an address.
* @notice Use and override this function with caution. Wrong usage can have serious consequences.
* @param _to Address to wich we want to add the NFT.
* @param _tokenId Which NFT we want to add.
*/
function addNFToken(
address _to,
uint256 _tokenId
)
internal
{
super.addNFToken(_to, _tokenId);
uint256 length = ownerToIds[_to].length;
ownerToIds[_to].push(_tokenId);
idToOwnerIndex[_tokenId] = length;
}
/**
* @dev Returns the count of all existing NFTokens.
*/
function totalSupply()
external
view
returns (uint256)
{
return tokens.length;
}
/**
* @dev Returns NFT ID by its index.
* @param _index A counter less than `totalSupply()`.
*/
function tokenByIndex(
uint256 _index
)
external
view
returns (uint256)
{
require(_index < tokens.length);
// Sanity check. This could be removed in the future.
assert(idToIndex[tokens[_index]] == _index);
return tokens[_index];
}
/**
* @dev returns the n-th NFT ID from a list of owner's tokens.
* @param _owner Token owner's address.
* @param _index Index number representing n-th token in owner's list of tokens.
*/
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
external
view
returns (uint256)
{
require(_index < ownerToIds[_owner].length);
return ownerToIds[_owner][_index];
}
}
// File: contracts/MarbleNFTInterface.sol
pragma solidity ^0.4.24;
/**
* @title Marble NFT Interface
* @dev Defines Marbles unique extension of NFT.
* ...It contains methodes returning core properties what describe Marble NFTs and provides management options to create,
* burn NFT or change approvals of it.
*/
interface MarbleNFTInterface {
/**
* @dev Mints Marble NFT.
* @notice This is a external function which should be called just by the owner of contract or any other user who has priviladge of being resposible
* of creating valid Marble NFT. Valid token contains all neccessary information to be able recreate marble card image.
* @param _tokenId The ID of new NFT.
* @param _owner Address of the NFT owner.
* @param _uri Unique URI proccessed by Marble services to be sure it is valid NFTs DNA. Most likely it is URL pointing to some website address.
* @param _metadataUri URI pointing to "ERC721 Metadata JSON Schema"
* @param _tokenId ID of the NFT to be burned.
*/
function mint(
uint256 _tokenId,
address _owner,
address _creator,
string _uri,
string _metadataUri,
uint256 _created
)
external;
/**
* @dev Burns Marble NFT. Should be fired only by address with proper authority as contract owner or etc.
* @param _tokenId ID of the NFT to be burned.
*/
function burn(
uint256 _tokenId
)
external;
/**
* @dev Allowes to change approval for change of ownership even when sender is not NFT holder. Sender has to have special role granted by contract to use this tool.
* @notice Careful with this!!!! :))
* @param _tokenId ID of the NFT to be updated.
* @param _approved ETH address what supposed to gain approval to take ownership of NFT.
*/
function forceApproval(
uint256 _tokenId,
address _approved
)
external;
/**
* @dev Returns properties used for generating NFT metadata image (a.k.a. card).
* @param _tokenId ID of the NFT.
*/
function tokenSource(uint256 _tokenId)
external
view
returns (
string uri,
address creator,
uint256 created
);
/**
* @dev Returns ID of NFT what matches provided source URI.
* @param _uri URI of source website.
*/
function tokenBySourceUri(string _uri)
external
view
returns (uint256 tokenId);
/**
* @dev Returns all properties of Marble NFT. Lets call it Marble NFT Model with properties described below:
* @param _tokenId ID of NFT
* Returned model:
* uint256 id ID of NFT
* string uri URI of source website. Website is used to mine data to crate NFT metadata image.
* string metadataUri URI to NFT metadata assets. In our case to our websevice providing JSON with additional information based on "ERC721 Metadata JSON Schema".
* address owner NFT owner address.
* address creator Address of creator of this NFT. It means that this addres placed sourceURI to candidate contract.
* uint256 created Date and time of creation of NFT candidate.
*
* (id, uri, metadataUri, owner, creator, created)
*/
function getNFT(uint256 _tokenId)
external
view
returns(
uint256 id,
string uri,
string metadataUri,
address owner,
address creator,
uint256 created
);
/**
* @dev Transforms URI to hash.
* @param _uri URI to be transformed to hash.
*/
function getSourceUriHash(string _uri)
external
view
returns(uint256 hash);
}
// File: contracts/MarbleNFT.sol
pragma solidity ^0.4.24;
/**
* @title MARBLE NFT CONTRACT
* @notice We omit a fallback function to prevent accidental sends to this contract.
*/
contract MarbleNFT is
Adminable,
NFTokenMetadata,
NFTokenEnumerable,
MarbleNFTInterface
{
/*
* @dev structure storing additional information about created NFT
* uri: URI used as source/key/representation of NFT, it can be considered as tokens DNA
* creator: address of candidate creator - a.k.a. address of person who initialy provided source URI
* created: date of NFT creation
*/
struct MarbleNFTSource {
// URI used as source/key of NFT, we can consider it as tokens DNA
string uri;
// address of candidate creator - a.k.a. address of person who initialy provided source URI
address creator;
// date of NFT creation
uint256 created;
}
/**
* @dev Mapping from NFT ID to marble NFT source.
*/
mapping (uint256 => MarbleNFTSource) public idToMarbleNFTSource;
/**
* @dev Mapping from marble NFT source uri hash TO NFT ID .
*/
mapping (uint256 => uint256) public sourceUriHashToId;
constructor()
public
{
nftName = "MARBLE-NFT";
nftSymbol = "MRBLNFT";
}
/**
* @dev Mints a new NFT.
* @param _tokenId The unique number representing NFT
* @param _owner Holder of Marble NFT
* @param _creator Creator of Marble NFT
* @param _uri URI representing NFT
* @param _metadataUri URI pointing to "ERC721 Metadata JSON Schema"
* @param _created date of creation of NFT candidate
*/
function mint(
uint256 _tokenId,
address _owner,
address _creator,
string _uri,
string _metadataUri,
uint256 _created
)
external
onlyAdmin
{
uint256 uriHash = _getSourceUriHash(_uri);
require(uriHash != _getSourceUriHash(""), "NFT URI can not be empty!");
require(sourceUriHashToId[uriHash] == 0, "NFT with same URI already exists!");
_mint(_owner, _tokenId);
_setTokenUri(_tokenId, _metadataUri);
idToMarbleNFTSource[_tokenId] = MarbleNFTSource(_uri, _creator, _created);
sourceUriHashToId[uriHash] = _tokenId;
}
/**
* @dev Burns NFT. Sadly, trully.. ...probably someone marbled something ugly!!!! :)
* @param _tokenId ID of ugly NFT
*/
function burn(
uint256 _tokenId
)
external
onlyAdmin
{
address owner = idToOwner[_tokenId];
MarbleNFTSource memory marbleNFTSource = idToMarbleNFTSource[_tokenId];
if (bytes(marbleNFTSource.uri).length != 0) {
uint256 uriHash = _getSourceUriHash(marbleNFTSource.uri);
delete sourceUriHashToId[uriHash];
delete idToMarbleNFTSource[_tokenId];
}
_burn(owner, _tokenId);
}
/**
* @dev Tool to manage misstreated NFTs or to be able to extend our services for new cool stuff like auctions, weird games and so on......
* @param _tokenId ID of the NFT to be update.
* @param _approved Address to replace current approved address on NFT
*/
function forceApproval(
uint256 _tokenId,
address _approved
)
external
onlyAdmin
{
address tokenOwner = idToOwner[_tokenId];
require(_approved != tokenOwner,"Owner can not be become new owner!");
idToApprovals[_tokenId] = _approved;
emit Approval(tokenOwner, _approved, _tokenId);
}
/**
* @dev Returns model of Marble NFT source properties
* @param _tokenId ID of the NFT
*/
function tokenSource(uint256 _tokenId)
external
view
returns (
string uri,
address creator,
uint256 created)
{
MarbleNFTSource memory marbleNFTSource = idToMarbleNFTSource[_tokenId];
return (marbleNFTSource.uri, marbleNFTSource.creator, marbleNFTSource.created);
}
/**
* @dev Returns token ID related to provided source uri
* @param _uri URI representing created NFT
*/
function tokenBySourceUri(string _uri)
external
view
returns (uint256 tokenId)
{
return sourceUriHashToId[_getSourceUriHash(_uri)];
}
/**
* @dev Returns whole Marble NFT model
* --------------------
* MARBLE NFT MODEL
* --------------------
* uint256 id NFT unique identification
* string uri NFT source URI, source is whole site what was proccessed by marble to create this NFT, it is URI representation of NFT (call it DNA)
* string metadataUri URI pointint to token NFT metadata shcema
* address owner Current NFT owner
* address creator First NFT owner
* uint256 created Date of NFT candidate creation
*
* (id, uri, metadataUri, owner, creator, created)
*/
function getNFT(uint256 _tokenId)
external
view
returns(
uint256 id,
string uri,
string metadataUri,
address owner,
address creator,
uint256 created
)
{
MarbleNFTSource memory marbleNFTSource = idToMarbleNFTSource[_tokenId];
return (
_tokenId,
marbleNFTSource.uri,
idToUri[_tokenId],
idToOwner[_tokenId],
marbleNFTSource.creator,
marbleNFTSource.created);
}
/**
* @dev Transforms URI to hash.
* @param _uri URI to be transformed to hash.
*/
function getSourceUriHash(string _uri)
external
view
returns(uint256 hash)
{
return _getSourceUriHash(_uri);
}
/**
* @dev Transforms URI to hash.
* @param _uri URI to be transformed to hash.
*/
function _getSourceUriHash(string _uri)
internal
pure
returns(uint256 hash)
{
return uint256(keccak256(abi.encodePacked(_uri)));
}
}
// File: contracts/MarbleNFTFactory.sol
pragma solidity ^0.4.24;
/**
* @title Marble NFT Factory
* @dev Covers all parts of creating new NFT token. Contains references to all involved contracts and giving possibility of burning NFT corretly.
*/
contract MarbleNFTFactory is
Adminable,
Pausable,
SupportsInterface
{
using SafeMath for uint256;
MarbleNFT public marbleNFTContract;
MarbleNFTCandidateInterface public marbleNFTCandidateContract;
MarbleDutchAuctionInterface public marbleDutchAuctionContract;
/**
* @dev property holding last created NFT ID
* - it's separeted from Marble NFT contract in case that we will want to change NFT id strategy in the future. Currently no idea why we would do it! :)
*/
uint256 public lastMintedNFTId;
constructor(uint256 _lastMintedNFTId)
public
{
lastMintedNFTId = _lastMintedNFTId;
}
/**
* @dev Emits when new marble when is minted
*/
event MarbleNFTCreated(
address indexed _creator,
uint256 indexed _tokenId
);
/**
* @dev Emits when new marble is minted
*/
event MarbleNFTBurned(
uint256 indexed _tokenId,
address indexed _owner,
address indexed _creator
);
/**
* @dev Creates Marble NFT from Candidate and returns NFTs owner. Was created, bc of deep stack error over mint function.
* @param _id ID of Marble NFT
* @param _uri URI determining Marble NFT, lets say this is our DNA...
* @param _metadataUri URI pointing to "ERC721 Metadata JSON Schema"
* @param _candidateUri URI initially provided to user for purposes of creation Marble NFT
*/
function _mint(
uint256 _id,
string _uri,
string _metadataUri,
string _candidateUri
)
internal
returns (address owner)
{
require(marbleNFTCandidateContract.isCandidate(_candidateUri), "There is no candidate with this URL!!");
uint256 created;
(, owner, , , created) = marbleNFTCandidateContract.getCandidate(_candidateUri);
marbleNFTContract.mint(
_id,
owner,
owner,
_uri,
_metadataUri,
now
);
}
/**
* @dev Sets new last minted ID, !! use careful
* @param _lastMintedNFTId New value of last mineted NFT
*/
function setLastMintedNFTId(uint256 _lastMintedNFTId)
external
onlyOwner
whenPaused
{
lastMintedNFTId = _lastMintedNFTId;
}
/**
* @dev Sets auction contract
* @param _address Contract address
*/
function setMarbleDutchAuctionContract(address _address)
external
onlyAdmin
whenNotPaused
{
marbleDutchAuctionContract = MarbleDutchAuctionInterface(_address);
}
/**
* @dev Sets Marble NFT contract
* @param _address Contract address
*/
function setNFTContract(address _address)
external
onlyAdmin
whenNotPaused
{
marbleNFTContract = MarbleNFT(_address);
}
/**
* @dev Sets Candidate contract
* @param _address Contract address
*/
function setCandidateContract(address _address)
external
onlyAdmin
whenNotPaused
{
marbleNFTCandidateContract = MarbleNFTCandidateInterface(_address);
}
/**
* @dev Creates Marble NFT. Then place it over auction in special fashion and remove candidate entry.
* NOTE: we are not removing candidates, should we or should we not??
* @param _uri URI determining Marble NFT, lets say this is our DNA...
* @param _metadataUri URI pointing to "ERC721 Metadata JSON Schema"
* @param _candidateUri URI initially provided to user for purposes of creation Marble NFT
* @param _auctionStartingPrice Starting price of auction.
* @param _auctionMinimalPrice Ending price of auction.
* @param _auctionDuration Duration (in seconds) of auction when price is moving, lets say, it determines dynamic part of auction price creation.
*/
function mint(
string _uri,
string _metadataUri,
string _candidateUri,
uint256 _auctionStartingPrice,
uint256 _auctionMinimalPrice,
uint256 _auctionDuration
)
external
onlyAdmin
whenNotPaused
{
uint256 id = lastMintedNFTId.add(1);
address owner = _mint(
id,
_uri,
_metadataUri,
_candidateUri
);
marbleDutchAuctionContract.createMintingAuction(
id,
_auctionStartingPrice,
_auctionMinimalPrice,
_auctionDuration,
owner
);
lastMintedNFTId = id;
emit MarbleNFTCreated(owner, id);
}
/**
* @dev Creates Marble NFT. Then place it over auction in special fashion and remove candidate entry......hmm removing of candidate is not important and we can remove it from the minting process.
* NOTE: !! rather careful with this stuff, it burns
* @param _tokenId Id of Marble NFT to burn
*/
function burn(
uint256 _tokenId
)
external
onlyAdmin
whenNotPaused
{
require(marbleNFTContract.ownerOf(_tokenId) != address(0) , "Marble NFT doesnt not exists!");
address owner;
address creator;
// get some info about NFT to tell the world whos NFT we are burning!!
(, , , owner, creator, ) = marbleNFTContract.getNFT(_tokenId);
Pausable auctionContractToBePaused = Pausable(address(marbleDutchAuctionContract));
// If NFT is on our auction contract, we have to remove it first
if (marbleDutchAuctionContract.isOnAuction(_tokenId)) {
require(auctionContractToBePaused.paused(), "Auction contract has to be paused!");
marbleDutchAuctionContract.removeAuction(_tokenId);
}
// burn NFT
marbleNFTContract.burn(_tokenId);
// Let's everyone to know that we burn things....! :)
emit MarbleNFTBurned(_tokenId, owner, creator);
}
}
{
"compilationTarget": {
"MarbleNFTFactory.sol": "MarbleNFTFactory"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 0
},
"remappings": []
}
[{"constant":true,"inputs":[{"name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"adminList","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"adminAddress","type":"address"}],"name":"removeAdmin","outputs":[{"name":"index","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"adminAddress","type":"address"}],"name":"isAdmin","outputs":[{"name":"isIndeed","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marbleNFTCandidateContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marbleNFTContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"adminAddress","type":"address"}],"name":"addAdmin","outputs":[{"name":"index","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_lastMintedNFTId","type":"uint256"}],"name":"setLastMintedNFTId","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setCandidateContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setNFTContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_uri","type":"string"},{"name":"_metadataUri","type":"string"},{"name":"_candidateUri","type":"string"},{"name":"_auctionStartingPrice","type":"uint256"},{"name":"_auctionMinimalPrice","type":"uint256"},{"name":"_auctionDuration","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setMarbleDutchAuctionContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"marbleDutchAuctionContract","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastMintedNFTId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"adminsMap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_lastMintedNFTId","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_creator","type":"address"},{"indexed":true,"name":"_tokenId","type":"uint256"}],"name":"MarbleNFTCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_tokenId","type":"uint256"},{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_creator","type":"address"}],"name":"MarbleNFTBurned","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]