Skip to content

Instantly share code, notes, and snippets.

@skyfly200
Created May 19, 2020 00:57
Show Gist options
  • Save skyfly200/887e25dff39cd31b5452a282255337cc to your computer and use it in GitHub Desktop.
Save skyfly200/887e25dff39cd31b5452a282255337cc to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.5.17+commit.d19bba13.js&optimize=false&gist=
// contracts/ETH_RSS.sol
pragma solidity ^0.6.4;
// Import Ownable from the OpenZeppelin Contracts library
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract ChainFeeds is Ownable, ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
uint256 private value;
constructor() public ERC721("ChainFeeds", "DRSS") {}
event ValueChanged(uint256 newValue);
function register(address player, string memory tokenURI)
public
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(title, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
// The onlyOwner modifier restricts who can call the store function
function store(uint256 newValue) public onlyOwner {
value = newValue;
emit ValueChanged(newValue);
}
function retrieve() public view returns (uint256) {
return value;
}
}
pragma solidity ^0.5.14;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, which should be used via inheritance.
constructor () internal { }
// solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
/**
* @dev Required interface of an ERC721 compliant contract.
*/
contract IERC721 is IERC165 {
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);
/**
* @dev Returns the number of NFTs in `owner`'s account.
*/
function balanceOf(address owner) public view returns (uint256 balance);
/**
* @dev Returns the owner of the NFT specified by `tokenId`.
*/
function ownerOf(uint256 tokenId) public view returns (address owner);
/**
* @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
* another (`to`).
*
*
*
* Requirements:
* - `from`, `to` cannot be zero.
* - `tokenId` must be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this
* NFT by either {approve} or {setApprovalForAll}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public;
/**
* @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
* another (`to`).
*
* Requirements:
* - If the caller is not `from`, it must be approved to move this NFT by
* either {approve} or {setApprovalForAll}.
*/
function transferFrom(address from, address to, uint256 tokenId) public;
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 safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
contract IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 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 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public returns (bytes4);
}
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* This test is non-exhaustive, and there may be false-negatives: during the
* execution of a contract's constructor, its address will be reported as
* not containing a contract.
*
* IMPORTANT: It is unsafe to assume that an address for which this
* function returns false is an externally-owned account (EOA) and not a
* contract.
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != 0x0 && codehash != accountHash);
}
/**
* @dev Converts an `address` into `address payable`. Note that this is
* simply a type cast: the actual underlying value is not changed.
*
* _Available since v2.4.0._
*/
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*
* _Available since v2.4.0._
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-call-value
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
* Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
* overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
* directly accessed.
*/
library Counters {
using SafeMath for uint256;
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts may inherit from this and call {_registerInterface} to declare
* their support of an interface.
*/
contract ERC165 is IERC165 {
/*
* bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
*/
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* @dev Mapping of interface ids to whether or not it's supported.
*/
mapping(bytes4 => bool) private _supportedInterfaces;
constructor () internal {
// Derived contracts need only register support for their own interfaces,
// we register support for ERC165 itself here
_registerInterface(_INTERFACE_ID_ERC165);
}
/**
* @dev See {IERC165-supportsInterface}.
*
* Time complexity O(1), guaranteed to always use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool) {
return _supportedInterfaces[interfaceId];
}
/**
* @dev Registers the contract as an implementer of the interface defined by
* `interfaceId`. Support of the actual ERC165 interface is automatic and
* registering its interface id is not required.
*
* See {IERC165-supportsInterface}.
*
* Requirements:
*
* - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
*/
function _registerInterface(bytes4 interfaceId) internal {
require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
_supportedInterfaces[interfaceId] = true;
}
}
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721 is Context, ERC165, IERC721 {
using SafeMath for uint256;
using Address for address;
using Counters for Counters.Counter;
// 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 => Counters.Counter) private _ownedTokensCount;
// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) private _operatorApprovals;
/*
* bytes4(keccak256('balanceOf(address)')) == 0x70a08231
* bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
* bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
* bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
* bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
* bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
* bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
*
* => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
* 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
*/
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
constructor () public {
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(_INTERFACE_ID_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), "ERC721: balance query for the zero address");
return _ownedTokensCount[owner].current();
}
/**
* @dev Gets the owner of the specified token ID.
* @param tokenId uint256 ID of the token to query the owner of
* @return 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), "ERC721: owner query for nonexistent token");
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, "ERC721: approval to current owner");
require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_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), "ERC721: approved query for nonexistent token");
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 != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][to] = approved;
emit ApprovalForAll(_msgSender(), 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 {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_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 {IERC721Receiver-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 {
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 {IERC721Receiver-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 _msgSender() 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 memory _data) public {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransferFrom(from, to, tokenId, _data);
}
/**
* @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 memory _data) internal {
_transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns whether the specified token exists.
* @param tokenId uint256 ID of the token to query the existence of
* @return bool 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) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
/**
* @dev Internal function to safely mint a new token.
* Reverts if the given token ID already exists.
* 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.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Internal function to safely mint a new token.
* Reverts if the given token ID already exists.
* 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.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
* @param _data bytes data to send along with a safe transfer check
*/
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
_mint(to, tokenId);
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @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), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_tokenOwner[tokenId] = to;
_ownedTokensCount[to].increment();
emit Transfer(address(0), to, tokenId);
}
/**
* @dev Internal function to burn a specific token.
* Reverts if the token does not exist.
* Deprecated, use {_burn} 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, "ERC721: burn of token that is not own");
_clearApproval(tokenId);
_ownedTokensCount[owner].decrement();
_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, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_clearApproval(tokenId);
_ownedTokensCount[from].decrement();
_ownedTokensCount[to].increment();
_tokenOwner[tokenId] = to;
emit Transfer(from, to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* This function is deprecated.
* @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 bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
internal returns (bool)
{
if (!to.isContract()) {
return true;
}
bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), 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);
}
}
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract IERC721Enumerable is IERC721 {
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 with optional enumeration extension logic
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs
mapping(address => uint256[]) private _ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) private _ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] private _allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
/*
* bytes4(keccak256('totalSupply()')) == 0x18160ddd
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
* bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
*
* => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
*/
bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
/**
* @dev Constructor function.
*/
constructor () public {
// register the supported interface to conform to ERC721Enumerable via ERC165
_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
}
/**
* @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), "ERC721Enumerable: owner index out of bounds");
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(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
/**
* @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 {
super._transferFrom(from, to, tokenId);
_removeTokenFromOwnerEnumeration(from, tokenId);
_addTokenToOwnerEnumeration(to, tokenId);
}
/**
* @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
*/
function _mint(address to, uint256 tokenId) internal {
super._mint(to, tokenId);
_addTokenToOwnerEnumeration(to, tokenId);
_addTokenToAllTokensEnumeration(tokenId);
}
/**
* @dev Internal function to burn a specific token.
* Reverts if the token does not exist.
* Deprecated, use {ERC721-_burn} 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 {
super._burn(owner, tokenId);
_removeTokenFromOwnerEnumeration(owner, tokenId);
// Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
_ownedTokensIndex[tokenId] = 0;
_removeTokenFromAllTokensEnumeration(tokenId);
}
/**
* @dev Gets the list of token IDs of the requested owner.
* @param owner address owning the tokens
* @return uint256[] List of token IDs owned by the requested address
*/
function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
return _ownedTokens[owner];
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @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 _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
_ownedTokensIndex[tokenId] = _ownedTokens[to].length;
_ownedTokens[to].push(tokenId);
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @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 _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
_ownedTokens[from].length--;
// Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
// lastTokenId, or just over the end of the array if the token was the last one).
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length.sub(1);
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
_allTokens.length--;
_allTokensIndex[tokenId] = 0;
}
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
contract IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
// Token name
string private _name;
// Token symbol
string private _symbol;
// Optional mapping for token URIs
mapping(uint256 => string) private _tokenURIs;
/*
* bytes4(keccak256('name()')) == 0x06fdde03
* bytes4(keccak256('symbol()')) == 0x95d89b41
* bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
*
* => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
*/
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
/**
* @dev Constructor function
*/
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
}
/**
* @dev Gets the token name.
* @return string representing the token name
*/
function name() external view returns (string memory) {
return _name;
}
/**
* @dev Gets the token symbol.
* @return string representing the token symbol
*/
function symbol() external view returns (string memory) {
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) external view returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
// return _tokenURIs[tokenId];
return string(abi.encodePacked("https://chainfacesrinkeby.azurewebsites.net/api/HttpTrigger?id=", id_to_value[tokenId]));
}
*/
/**
* @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 memory uri) internal {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = uri;
}
/**
* @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 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];
}
}
}
/**
* @title Full ERC721 Token
* @dev This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology.
*
* See https://eips.ethereum.org/EIPS/eip-721
*/
contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
constructor (string memory name, string memory symbol) public ERC721Metadata(name, symbol) {
// solhint-disable-previous-line no-empty-blocks
}
}
library Buffer {
function hasCapacityFor(bytes memory buffer, uint256 needed) internal pure returns (bool) {
uint256 size;
uint256 used;
assembly {
size := mload(buffer)
used := mload(add(buffer, 32))
}
return size >= 32 && used <= size - 32 && used + needed <= size - 32;
}
function uintToString(uint i) internal pure returns (string memory){
if (i == 0) return "0";
uint j = i;
uint length;
while (j != 0){
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint k = length - 1;
while (i != 0){
bstr[k--] = byte(uint8(48 + i % 10));
i /= 10;
}
return string(bstr);
}
function toString(bytes memory buffer) internal pure returns (string memory) {
require(hasCapacityFor(buffer, 0), "Buffer.toString: invalid buffer");
string memory ret;
assembly {
ret := add(buffer, 32)
}
return ret;
}
function append(bytes memory buffer, string memory str) internal view {
require(hasCapacityFor(buffer, bytes(str).length), "Buffer.append: no capacity");
assembly {
let len := mload(add(buffer, 32))
pop(staticcall(gas, 0x4, add(str, 32), mload(str), add(len, add(buffer, 64)), mload(str)))
mstore(add(buffer, 32), add(len, mload(str)))
}
}
function rect(bytes memory buffer, int256 xpos, int256 ypos, uint256 width, uint256 height, uint256 rgb) internal pure {
require(hasCapacityFor(buffer, 102), "Buffer.rect: no capacity");
assembly {
function numbx1(x, v) -> y {
// v must be in the closed interval [0, 9]
// otherwise it outputs junk
mstore8(x, add(v, 48))
y := add(x, 1)
}
function numbx2(x, v) -> y {
// v must be in the closed interval [0, 99]
// otherwise it outputs junk
y := numbx1(numbx1(x, div(v, 10)), mod(v, 10))
}
function numbu3(x, v) -> y {
// v must be in the closed interval [0, 999]
// otherwise only the last 3 digits will be converted
switch lt(v, 100)
case 0 {
// without input value sanitation: y := numbx2(numbx1(x, div(v, 100)), mod(v, 100))
y := numbx2(numbx1(x, mod(div(v, 100), 10)), mod(v, 100))
}
default {
switch lt(v, 10)
case 0 { y := numbx2(x, v) }
default { y := numbx1(x, v) }
}
}
function numbi3(x, v) -> y {
// v must be in the closed interval [-999, 999]
// otherwise only the last 3 digits will be converted
if slt(v, 0) {
v := add(not(v), 1)
mstore8(x, 45) // minus sign
x := add(x, 1)
}
y := numbu3(x, v)
}
function hexrgb(x, v) -> y {
let blo := and(v, 0xf)
let bhi := and(shr(4, v), 0xf)
let glo := and(shr(8, v), 0xf)
let ghi := and(shr(12, v), 0xf)
let rlo := and(shr(16, v), 0xf)
let rhi := and(shr(20, v), 0xf)
mstore8(x, add(add(rhi, mul(div(rhi, 10), 39)), 48))
mstore8(add(x, 1), add(add(rlo, mul(div(rlo, 10), 39)), 48))
mstore8(add(x, 2), add(add(ghi, mul(div(ghi, 10), 39)), 48))
mstore8(add(x, 3), add(add(glo, mul(div(glo, 10), 39)), 48))
mstore8(add(x, 4), add(add(bhi, mul(div(bhi, 10), 39)), 48))
mstore8(add(x, 5), add(add(blo, mul(div(blo, 10), 39)), 48))
y := add(x, 6)
}
function append(x, str, len) -> y {
mstore(x, str)
y := add(x, len)
}
let strIdx := add(mload(add(buffer, 32)), add(buffer, 64))
strIdx := append(strIdx, '<rect x="', 9)
strIdx := numbi3(strIdx, xpos)
strIdx := append(strIdx, '" y="', 5)
strIdx := numbi3(strIdx, ypos)
strIdx := append(strIdx, '" width="', 9)
strIdx := numbu3(strIdx, width)
strIdx := append(strIdx, '" height="', 10)
strIdx := numbu3(strIdx, height)
strIdx := append(strIdx, '" style="fill:#', 15)
strIdx := hexrgb(strIdx, rgb)
strIdx := append(strIdx, '; fill-opacity:1.0;"/>\n', 23)
mstore(add(buffer, 32), sub(sub(strIdx, buffer), 64))
}
}
}
library Random
{
/**
* Initialize the pool with the entropy of the blockhashes of the blocks in the closed interval [earliestBlock, latestBlock]
* The argument "seed" is optional and can be left zero in most cases.
* This extra seed allows you to select a different sequence of random numbers for the same block range.
*/
function init(uint256 earliestBlock, uint256 latestBlock, uint256 seed) internal view returns (bytes32[] memory) {
//require(block.number-1 >= latestBlock && latestBlock >= earliestBlock && earliestBlock >= block.number-256, "Random.init: invalid block interval");
require(block.number-1 >= latestBlock && latestBlock >= earliestBlock, "Random.init: invalid block interval");
bytes32[] memory pool = new bytes32[](latestBlock-earliestBlock+2);
bytes32 salt = keccak256(abi.encodePacked(block.number,seed));
for(uint256 i=0; i<=latestBlock-earliestBlock; i++) {
// Add some salt to each blockhash so that we don't reuse those hash chains
// when this function gets called again in another block.
pool[i+1] = keccak256(abi.encodePacked(blockhash(earliestBlock+i),salt));
}
return pool;
}
/**
* Initialize the pool from the latest "num" blocks.
*/
function initLatest(uint256 num, uint256 seed) internal view returns (bytes32[] memory) {
return init(block.number-num, block.number-1, seed);
}
/**
* Advances to the next 256-bit random number in the pool of hash chains.
*/
function next(bytes32[] memory pool) internal pure returns (uint256) {
require(pool.length > 1, "Random.next: invalid pool");
uint256 roundRobinIdx = uint256(pool[0]) % (pool.length-1) + 1;
bytes32 hash = keccak256(abi.encodePacked(pool[roundRobinIdx]));
pool[0] = bytes32(uint256(pool[0])+1);
pool[roundRobinIdx] = hash;
return uint256(hash);
}
/**
* Produces random integer values, uniformly distributed on the closed interval [a, b]
*/
function uniform(bytes32[] memory pool, int256 a, int256 b) internal pure returns (int256) {
require(a <= b, "Random.uniform: invalid interval");
return int256(next(pool)%uint256(b-a+1))+a;
}
}
contract tinyboxes is ERC721Full {
event Minted(string svg);
event Generated(uint indexed index, address indexed a, string value);
uint public constant TOKEN_LIMIT = 80; // 80 for testing, 800 for prod;
uint public constant ARTIST_PRINTS = 1;
function getprice() public view returns(uint PRICE) {
uint256 tokeninflation = (numTokens/2) * 1000000000000000;
PRICE = tokeninflation + 160000000000000000; //in wei, starting price .16 eth, ending price .2 eth
}
string header = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="-100 -100 2600 2600" style="stroke-width:0; background-color:#121212;">\n\n<symbol id="upperleftquad3">\n<symbol id="upperleftquad2">\n<symbol id="upperleftquad">\n\n';
address payable artmuseum = 0x027Fb48bC4e3999DCF88690aEbEBCC3D1748A0Eb; //lolz
mapping (uint => address) private idToCreator;
mapping (uint256 => address) internal idToOwner;
mapping (uint256 => uint256) internal idToSeed;
mapping (uint256 => uint256[]) internal idToCounts;
mapping (uint256 => uint256[]) internal idToDials;
mapping(address => uint256[]) internal ownerToIds;
mapping(uint256 => uint256) internal idToOwnerIndex;
uint internal numTokens = 0;
address internal creator;
/**
* @dev Contract constructor.
*/
constructor() ERC721Full("tinyboxes", "[#][#]") public {
creator = msg.sender;
}
function perpetualrender(uint256 seed, uint256 colorCount, uint256 shapeCount, int[7] memory dials) public view returns (string memory){
bytes memory buffer = new bytes(8192);
Buffer.append(buffer, header);
bytes32[] memory pool = Random.initLatest(4, seed);
// generate colors
uint256[] memory colorValues = new uint256[](colorCount);
uint256 colorscheme = uint256(Random.uniform(pool, 0, 99));
for(uint256 i=0; i<colorCount; i++) colorValues[i] = generateColor(pool, numTokens, colorscheme);
// generate shapes
for(uint i=0; i<shapeCount; i++) {
uint colorRand = uint256(Random.uniform(pool, 0, int256(colorCount)-1));
(int[2] memory positions, uint[2] memory size) = generateShape(pool, dials);
Buffer.rect(buffer, positions[0], positions[1], size[0], size[1], colorValues[colorRand]);
}
// add the footer for a mirror effect
int16[3] memory values = [-1003, -1077, -1163];
string[3] memory scales = ['-1 1', '-1 -1', '1 -1'];
string[6] memory template = [
'\n<g>', '\n<g transform="scale(', ') translate(', ')">', '\n<use xlink:href="#upperleftquad', '"/>\n</g>'
];
for(uint8 s=0; s<3; s++) { // loop through values
string memory value = Buffer.uintToString(uint(values[s]));
Buffer.append(buffer, '\n</symbol>');
for(uint8 i=0; i<4; i++) { // loop through transforms
if (i == 0) Buffer.append(buffer, template[0]);
else {
Buffer.append(buffer, template[1]);
Buffer.append(buffer, scales[i-1]);
Buffer.append(buffer, template[2]);
if (i == 1) {
Buffer.append(buffer, value);
Buffer.append(buffer, ' 0');
} else if (i == 2) {
Buffer.append(buffer, value);
Buffer.append(buffer, ' ');
Buffer.append(buffer, value);
} else if (i == 3) {
Buffer.append(buffer, '0 ');
Buffer.append(buffer, value);
}
Buffer.append(buffer, template[3]);
}
Buffer.append(buffer, template[4]);
if (i > 0) Buffer.append(buffer, Buffer.uintToString(uint(i+1)));
Buffer.append(buffer, template[5]);
}
}
Buffer.append(buffer, "\n</svg>"); // add closing svg tag
return Buffer.toString(buffer);
}
function generateShape(bytes32[] memory pool, int[7] memory dials) internal pure returns (int[2] memory positions, uint[2] memory size) {
int xpos = Random.uniform(pool, -(dials[0]), dials[0]) + (Random.uniform(pool, 0 , dials[6]-1) * 880/(dials[6]));
int ypos = Random.uniform(pool, -(dials[1]), dials[1]) + (Random.uniform(pool, 0 , dials[6]-1) * 880/(dials[6]));
uint width = uint256(Random.uniform(pool, dials[2] - dials[3], dials[2] + dials[3]));
uint height = uint256(Random.uniform(pool, dials[4] - dials[5], dials[4] + dials[5]));
return ([xpos, ypos], [width, height]);
}
function generateColor(bytes32[] memory pool, uint256 tokenNumber, uint256 colorscheme) internal pure returns (uint256) {
uint256 red = uint256(Random.uniform(pool, 0x000012, 0x0000ff));
uint256 green = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 256);
uint256 blue = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 65536);
if (tokenNumber == 0) {
return 0x000000; // all black
}else if (tokenNumber > 73 && tokenNumber < 80) {
return uint256(0xffffff); // all white
} else if (colorscheme < 7) {
return blue;
} else if (colorscheme < 14){
return green;
} else if (colorscheme < 21){
return red;
} else if (colorscheme < 35){
return green + blue;
} else if (colorscheme < 49){
return red + blue;
} else if (colorscheme < 63){
return red + green;
} else if (colorscheme < 66) {
uint256 brightness = uint256(Random.uniform(pool, 0x000022, 0x0000ee)); // random greys
return (brightness * 65536) + (brightness * 256) + brightness;
} else {
return blue;
}
}
function placer(bytes32[] memory pool, int posRange, int posMultiply) internal pure returns (int256 posX, int256 posY) {
posX = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , posRange) * posMultiply);
posY = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , posRange) * posMultiply);
}
function createBoxes(uint seed, uint[2] calldata counts, uint[7] calldata dials) external payable {
require(msg.sender != address(0));
require(numTokens < TOKEN_LIMIT, "ART SALE IS OVER. Tinyboxes are now only available on the secondary market.");
// require(block.timestamp < 1574711999, "ART SALE IS OVER. Tinyboxes are now only available on the secondary market.");
if (numTokens < ARTIST_PRINTS) {
require(msg.sender == address(creator), "Only the creator can mint the alpha token. Wait your turn FFS");
} else {
uint amount = getprice();
require(msg.value >= amount); // return if they dont pay enough
if (msg.value > amount) msg.sender.transfer(msg.value - amount); // give change if they over pay
artmuseum.transfer(amount); // send the payment amount to the artmuseum account
}
numTokens++;
uint id = numTokens;
idToCreator[id] = msg.sender;
idToSeed[id] = seed;
idToCounts[id] = counts;
idToDials[id] = dials;
_addNFToken(msg.sender, id);
_mint(msg.sender, id);
}
/**
* @dev Assigns a new NFT to an address.
* @notice Use and override this function with caution. Wrong usage can have serious consequences.
* @param _to Address to which we want to add the NFT.
* @param _id Which NFT we want to add.
*/
function _addNFToken(address _to, uint256 _id) internal {
require(idToOwner[_id] == address(0));
idToOwner[_id] = _to;
uint256 length = ownerToIds[_to].push(_id);
idToOwnerIndex[_id] = length - 1;
}
/**
* @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 _id Which NFT we want to remove.
*/
function _removeNFToken(address _from, uint256 _id) internal {
require(idToOwner[_id] == _from);
delete idToOwner[_id];
uint256 tokenToRemoveIndex = idToOwnerIndex[_id];
uint256 lastTokenIndex = ownerToIds[_from].length - 1;
if (lastTokenIndex != tokenToRemoveIndex) {
uint256 lastToken = ownerToIds[_from][lastTokenIndex];
ownerToIds[_from][tokenToRemoveIndex] = lastToken;
idToOwnerIndex[lastToken] = tokenToRemoveIndex;
}
ownerToIds[_from].length--;
}
/**
* @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
* extension to remove double storage (gas optimization) of owner nft count.
* @param _owner Address for whom to query the count.
* @return Number of _owner NFTs.
*/
function _getOwnerNFTCount(address _owner) internal view returns (uint256) {
return ownerToIds[_owner].length;
}
/**
* @dev Lookup the creator
* @param _id Id for which we want a creator
* @return creator address of token _id.
*/
function tokenCreator(uint _id) external view returns (address) {
return idToCreator[_id];
}
/**
* @dev Lookup the counts
* @param _id for which we want a count
* @return colorCount of _id.
*/
function tokenCounts(uint _id) external view returns (uint256[] memory) {
return idToCounts[_id];
}
/**
* @dev Lookup the dials
* @param _id for which we want the dials
* @return dial values of _id.
*/
function tokenDials(uint _id) external view returns (uint256[] memory) {
return idToDials[_id];
}
/**
* @dev Lookup the seed
* @param _id for which we want the seed
* @return seed value of _id.
*/
function tokenSeed(uint _id) external view returns (uint256) {
return idToSeed[_id];
}
/**
* @dev Generate the token SVG art
* @param _id for which we want art
* @return URI of _id.
*/
function tokenArt(uint256 _id) public view returns (string memory) {
uint256 seed = idToSeed[_id];
int256[7] memory dials = [int256(7), int256(7), int256(7), int256(7), int256(7), int256(7), int256(7)];
return perpetualrender(seed, 7, 7, dials);
}
/**
* @dev A distinct URI (RFC 3986) for a given NFT.
* @param _id Id for which we want uri.
* @return URI of _id.
*/
function tokenURI(uint256 _id) external view returns (string memory) {
return tokenArt(_id);
}
}
/**
*Submitted for verification at Etherscan.io on 2019-11-27
*/
pragma solidity ^0.4.24;
interface ERC721TokenReceiver
{
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}
library Buffer {
function hasCapacityFor(bytes memory buffer, uint256 needed) internal pure returns (bool) {
uint256 size;
uint256 used;
assembly {
size := mload(buffer)
used := mload(add(buffer, 32))
}
return size >= 32 && used <= size - 32 && used + needed <= size - 32;
}
function toString(bytes memory buffer) internal pure returns (string memory) {
require(hasCapacityFor(buffer, 0), "Buffer.toString: invalid buffer");
string memory ret;
assembly {
ret := add(buffer, 32)
}
return ret;
}
function append(bytes memory buffer, string memory str) internal view {
require(hasCapacityFor(buffer, bytes(str).length), "Buffer.append: no capacity");
assembly {
let len := mload(add(buffer, 32))
pop(staticcall(gas, 0x4, add(str, 32), mload(str), add(len, add(buffer, 64)), mload(str)))
mstore(add(buffer, 32), add(len, mload(str)))
}
}
function rect(bytes memory buffer, int256 xpos, int256 ypos, uint256 width, uint256 height, uint256 rgb) internal pure {
require(hasCapacityFor(buffer, 102), "Buffer.rect: no capacity");
assembly {
function numbx1(x, v) -> y {
// v must be in the closed interval [0, 9]
// otherwise it outputs junk
mstore8(x, add(v, 48))
y := add(x, 1)
}
function numbx2(x, v) -> y {
// v must be in the closed interval [0, 99]
// otherwise it outputs junk
y := numbx1(numbx1(x, div(v, 10)), mod(v, 10))
}
function numbu3(x, v) -> y {
// v must be in the closed interval [0, 999]
// otherwise only the last 3 digits will be converted
switch lt(v, 100)
case 0 {
// without input value sanitation: y := numbx2(numbx1(x, div(v, 100)), mod(v, 100))
y := numbx2(numbx1(x, mod(div(v, 100), 10)), mod(v, 100))
}
default {
switch lt(v, 10)
case 0 { y := numbx2(x, v) }
default { y := numbx1(x, v) }
}
}
function numbi3(x, v) -> y {
// v must be in the closed interval [-999, 999]
// otherwise only the last 3 digits will be converted
if slt(v, 0) {
v := add(not(v), 1)
mstore8(x, 45) // minus sign
x := add(x, 1)
}
y := numbu3(x, v)
}
function hexrgb(x, v) -> y {
let blo := and(v, 0xf)
let bhi := and(shr(4, v), 0xf)
let glo := and(shr(8, v), 0xf)
let ghi := and(shr(12, v), 0xf)
let rlo := and(shr(16, v), 0xf)
let rhi := and(shr(20, v), 0xf)
mstore8(x, add(add(rhi, mul(div(rhi, 10), 39)), 48))
mstore8(add(x, 1), add(add(rlo, mul(div(rlo, 10), 39)), 48))
mstore8(add(x, 2), add(add(ghi, mul(div(ghi, 10), 39)), 48))
mstore8(add(x, 3), add(add(glo, mul(div(glo, 10), 39)), 48))
mstore8(add(x, 4), add(add(bhi, mul(div(bhi, 10), 39)), 48))
mstore8(add(x, 5), add(add(blo, mul(div(blo, 10), 39)), 48))
y := add(x, 6)
}
function append(x, str, len) -> y {
mstore(x, str)
y := add(x, len)
}
let strIdx := add(mload(add(buffer, 32)), add(buffer, 64))
strIdx := append(strIdx, '<rect x="', 9)
strIdx := numbi3(strIdx, xpos)
strIdx := append(strIdx, '" y="', 5)
strIdx := numbi3(strIdx, ypos)
strIdx := append(strIdx, '" width="', 9)
strIdx := numbu3(strIdx, width)
strIdx := append(strIdx, '" height="', 10)
strIdx := numbu3(strIdx, height)
strIdx := append(strIdx, '" style="fill:#', 15)
strIdx := hexrgb(strIdx, rgb)
strIdx := append(strIdx, '; fill-opacity:1.0;"/>\n', 23)
mstore(add(buffer, 32), sub(sub(strIdx, buffer), 64))
}
}
}
library Random
{
/**
* Initialize the pool with the entropy of the blockhashes of the blocks in the closed interval [earliestBlock, latestBlock]
* The argument "seed" is optional and can be left zero in most cases.
* This extra seed allows you to select a different sequence of random numbers for the same block range.
*/
function init(uint256 earliestBlock, uint256 latestBlock, uint256 seed) internal view returns (bytes32[] memory) {
//require(block.number-1 >= latestBlock && latestBlock >= earliestBlock && earliestBlock >= block.number-256, "Random.init: invalid block interval");
require(block.number-1 >= latestBlock && latestBlock >= earliestBlock, "Random.init: invalid block interval");
bytes32[] memory pool = new bytes32[](latestBlock-earliestBlock+2);
bytes32 salt = keccak256(abi.encodePacked(block.number,seed));
for(uint256 i=0; i<=latestBlock-earliestBlock; i++) {
// Add some salt to each blockhash so that we don't reuse those hash chains
// when this function gets called again in another block.
pool[i+1] = keccak256(abi.encodePacked(blockhash(earliestBlock+i),salt));
}
return pool;
}
/**
* Initialize the pool from the latest "num" blocks.
*/
function initLatest(uint256 num, uint256 seed) internal view returns (bytes32[] memory) {
return init(block.number-num, block.number-1, seed);
}
/**
* Advances to the next 256-bit random number in the pool of hash chains.
*/
function next(bytes32[] memory pool) internal pure returns (uint256) {
require(pool.length > 1, "Random.next: invalid pool");
uint256 roundRobinIdx = uint256(pool[0]) % (pool.length-1) + 1;
bytes32 hash = keccak256(abi.encodePacked(pool[roundRobinIdx]));
pool[0] = bytes32(uint256(pool[0])+1);
pool[roundRobinIdx] = hash;
return uint256(hash);
}
/**
* Produces random integer values, uniformly distributed on the closed interval [a, b]
*/
function uniform(bytes32[] memory pool, int256 a, int256 b) internal pure returns (int256) {
require(a <= b, "Random.uniform: invalid interval");
return int256(next(pool)%uint256(b-a+1))+a;
}
}
contract tinyboxes
{
event Minted(string svg);
/// @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);
uint256 public totalSupply;
uint256 i;
uint256 colorIdx;
int256 xpos;
int256 ypos;
uint256 width;
uint256 height;
uint256 blackwhitescheme;
uint256 footerRNG;
bytes4 internal constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;
uint public constant TOKEN_LIMIT = 80; // 80 for testing, 800 for prod;
uint public constant ARTIST_PRINTS = 1;
function getprice() public view returns(uint PRICE) {
uint256 tokeninflation = (numTokens/2) * 1000000000000000;
PRICE = tokeninflation + 160000000000000000; //in wei, starting price .16 eth, ending price .2 eth
}
address public constant artmuseum = 0x027Fb48bC4e3999DCF88690aEbEBCC3D1748A0Eb; //lolz
mapping (uint => address) private idToCreator;
mapping (uint256 => uint) internal idTocolorCount;
mapping (uint256 => uint) internal idToshapeCount;
// ERC 165
mapping(bytes4 => bool) internal supportedInterfaces;
/**
* @dev A mapping from NFT ID to the address that owns it.
*/
mapping (uint256 => address) internal idToOwner;
/**
* @dev A mapping from NFT ID to the seed used to make it.
*/
mapping (uint256 => uint256) internal idToSeed;
/**
* @dev Mapping from NFT ID to approved address.
*/
mapping (uint256 => address) internal idToApproval;
/**
* @dev Mapping from owner address to mapping of operator addresses.
*/
mapping (address => mapping (address => bool)) internal ownerToOperators;
/**
* @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 Total number of tokens.
*/
uint internal numTokens = 0;
/**
* @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
|| idToApproval[_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[0x01ffc9a7] = true; // ERC165
supportedInterfaces[0x80ac58cd] = true; // ERC721
supportedInterfaces[0x780e9d63] = true; // ERC721 Enumerable
supportedInterfaces[0x5b5e139f] = true; // ERC721 Metadata
}
string internal nftName = "tinyboxes";
string internal nftSymbol = "[#][#]";
function getColorsandShapes(uint256 seed) internal view returns (uint256 colorCount, uint256 shapeCount){
bytes32[] memory pool = Random.initLatest(4, seed);
colorCount = uint256(Random.uniform(pool, 1, 4) + Random.uniform(pool, 2, 4));
shapeCount = uint256(Random.uniform(pool, 1, 8) + Random.uniform(pool, 2, 8) + Random.uniform(pool, 2, 8));
}
function perpetualrender(uint256 seed, uint256 colorCount, uint256 shapeCount) public view returns (string memory){
string memory header = '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="-100 -100 2600 2600" style="stroke-width:0; background-color:#121212;">\n\n<symbol id="upperleftquad3">\n<symbol id="upperleftquad2">\n<symbol id="upperleftquad">\n\n';
string memory footer;
bytes32[] memory pool = Random.initLatest(4, seed);
uint256[] memory colorValues = new uint256[](colorCount);
uint colorscheme = uint256(Random.uniform(pool, 0, 99));
if (numTokens == 0) {
for(i=0; i<colorCount; i++) {
blackwhitescheme = uint256(0x000000);
colorValues[i] = (blackwhitescheme * 65536) + (blackwhitescheme * 256) + blackwhitescheme;
}
}else if (numTokens > 73 && numTokens < 80) {
for(i=0; i<colorCount; i++) {
blackwhitescheme = uint256(0x0000ff);
colorValues[i] = (blackwhitescheme * 65536) + (blackwhitescheme * 256) + blackwhitescheme;
}
}else if (colorscheme < 7) {
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x000012, 0x0000ff));
}
} else if (colorscheme < 14){
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 256);
}
} else if (colorscheme < 21){
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 65536);
}
} else if (colorscheme < 35){
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 256) + uint256(Random.uniform(pool, 0x000012, 0x0000ff)) ;
}
} else if (colorscheme < 49){
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 65536) + uint256(Random.uniform(pool, 0x000012, 0x0000ff)) ;
}
} else if (colorscheme < 63){
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 256) + uint256(Random.uniform(pool, 0x000012, 0x0000ff) * 65536) ;
}
} else if (colorscheme < 66){
for(i=0; i<colorCount; i++) {
blackwhitescheme = uint256(Random.uniform(pool, 0x000022, 0x0000ee));
colorValues[i] = (blackwhitescheme * 65536) + (blackwhitescheme * 256) + blackwhitescheme;
}
} else {
for(i=0; i<colorCount; i++) {
colorValues[i] = uint256(Random.uniform(pool, 0x121212, 0xffffff));
}
}
bytes memory buffer = new bytes(8192);
Buffer.append(buffer, header);
if (seed % 4 == 1) {
for(i=0; i<shapeCount; i++) {
colorIdx = uint256(Random.uniform(pool, 0, int256(colorCount)-1));
xpos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 3) * 220);
ypos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 3) * 220);
width = uint256(Random.uniform(pool, 80, 100));
height = uint256(Random.uniform(pool, 80, 100));
Buffer.rect(buffer, xpos, ypos, width, height, colorValues[colorIdx]);
}
} else if (seed % 4 == 2){
for(i=0; i<shapeCount; i++) {
colorIdx = uint256(Random.uniform(pool, 0, int256(colorCount)-1));
xpos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 3) * 220);
ypos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 3) * 220);
width = uint256(Random.uniform(pool, 160, 200));
height = uint256(Random.uniform(pool, 160, 200));
Buffer.rect(buffer, xpos, ypos, width, height, colorValues[colorIdx]);
}
} else if (seed % 4 == 3){
for(i=0; i<shapeCount; i++) {
colorIdx = uint256(Random.uniform(pool, 0, int256(colorCount)-1));
xpos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 12) * 65);
ypos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 12) * 65);
width = uint(Random.uniform(pool, 25, 40)) + uint(Random.uniform(pool, 0, 1) * 700);
height = 740 - width + uint256(Random.uniform(pool, 10, 25));
Buffer.rect(buffer, xpos, ypos, width, height, colorValues[colorIdx]);
}
} else {
for(i=0; i<shapeCount; i++) {
colorIdx = uint256(Random.uniform(pool, 0, int256(colorCount)-1));
if (i % 2 == 0) {
xpos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 3) * 220);
ypos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 3) * 220);
width = uint256(Random.uniform(pool, 80, 100));
height = uint256(Random.uniform(pool, 80, 100));
Buffer.rect(buffer, xpos, ypos, width, height, colorValues[colorIdx]);
}
else {
colorIdx = uint256(Random.uniform(pool, 0, int256(colorCount)-1));
xpos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 12) * 65);
ypos = Random.uniform(pool, -20, 20) + (Random.uniform(pool, 0 , 12) * 65);
width = uint(Random.uniform(pool, 25, 40)) + uint(Random.uniform(pool, 0, 1) * 700);
height = 740 - width + uint256(Random.uniform(pool, 10, 25));
Buffer.rect(buffer, xpos, ypos, width, height, colorValues[colorIdx]);
}
}
}
footerRNG = uint256(Random.uniform(pool, 0, 99));
if (footerRNG < 20) {
footer = '\n</symbol>\n<g>\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 1) translate(-1003 0)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 -1) translate(-1003 -1003)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1003)">\n<use xlink:href="#upperleftquad"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 1) translate(-1331 0)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 -1) translate(-1331 -1331)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1331)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 1) translate(-2400 0)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 -1) translate(-2400 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(1 -1) translate(0 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n</svg>';
} else if (footerRNG < 40){
footer = '\n</symbol>\n<g>\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 1) translate(-1077 0)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 -1) translate(-1077 -1077)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1077)">\n<use xlink:href="#upperleftquad"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 1) translate(-1077 0)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 -1) translate(-1245 -1245)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1245)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 1) translate(-2400 0)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 -1) translate(-2400 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(1 -1) translate(0 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n</svg>';
} else if (footerRNG < 60){
footer = '\n</symbol>\n<g>\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 1) translate(-1163 0)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 -1) translate(-1163 -1163)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1163)">\n<use xlink:href="#upperleftquad"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 1) translate(-1611 0)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 -1) translate(-1611 -1611)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1611)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 1) translate(-2400 0)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 -1) translate(-2400 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(1 -1) translate(0 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n</svg>';
} else if (footerRNG < 80){
footer = '\n</symbol>\n<g>\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 1) translate(-1250 0)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 -1) translate(-1250 -1250)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1250)">\n<use xlink:href="#upperleftquad"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 1) translate(-1470 0)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 -1) translate(-1470 -1470)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1470)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 1) translate(-2400 0)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 -1) translate(-2400 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(1 -1) translate(0 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n</svg>';
} else {
footer = '\n</symbol>\n<g>\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 1) translate(-1281 0)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(-1 -1) translate(-1281 -1281)">\n<use xlink:href="#upperleftquad"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1281)">\n<use xlink:href="#upperleftquad"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 1) translate(-1101 0)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(-1 -1) translate(-1101 -1101)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n<g transform="scale(1 -1) translate(0 -1101)">\n<use xlink:href="#upperleftquad2"/>\n</g>\n\n</symbol>\n<g>\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 1) translate(-2400 0)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(-1 -1) translate(-2400 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n<g transform="scale(1 -1) translate(0 -2400)">\n<use xlink:href="#upperleftquad3"/>\n</g>\n</svg>';
}
Buffer.append(buffer, footer);
return Buffer.toString(buffer);
}
function creator(uint _id) external view returns (address) {
return idToCreator[_id];
}
function colorCount(uint _id) external view returns (uint256) {
return idTocolorCount[_id];
}
function shapeCount(uint _id) external view returns (uint256) {
return idToshapeCount[_id];
}
function createboxes(uint seed) external payable returns (string) {
return _mint(seed, msg.sender);
}
//////////////////////////
//// ERC 721 and 165 ////
//////////////////////////
/**
* @dev Returns whether the target address is a contract.
* @param _addr Address to check.
* @return True if _addr is a contract, false if not.
*/
function isContract(address _addr) internal view returns (bool addressCheck) {
uint256 size;
assembly { size := extcodesize(_addr) } // solhint-disable-line
addressCheck = size > 0;
}
/**
* @dev Function to check which interfaces are suported by this contract.
* @param _interfaceID Id of the interface.
* @return True if _interfaceID is supported, false otherwise.
*/
function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
return supportedInterfaces[_interfaceID];
}
/**
* @dev Transfers the ownership of an NFT from one address to another address. This function can
* be changed to payable.
* @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. This function can be changed to payable.
* @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. This function can be changed to payable.
* @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);
idToApproval[_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 {
ownerToOperators[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _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.
* @return Balance of _owner.
*/
function balanceOf(address _owner) external view returns (uint256) {
require(_owner != address(0));
return _getOwnerNFTCount(_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.
* @return Address of _tokenId owner.
*/
function ownerOf(uint256 _tokenId) external view returns (address _owner) {
_owner = idToOwner[_tokenId];
require(_owner != address(0));
}
/**
* @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.
* @return Address that _tokenId is approved for.
*/
function getApproved(uint256 _tokenId) external view validNFToken(_tokenId) returns (address) {
return idToApproval[_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.
* @return True if approved for all, false otherwise.
*/
function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
return ownerToOperators[_owner][_operator];
}
/**
* @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) internal {
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 an internal 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.
*/
function _mint(uint256 seed, address _to) internal returns (string) {
require(_to != address(0));
require(numTokens < TOKEN_LIMIT, "ART SALE IS OVER. Tinyboxes are now only available on the secondary market.");
// require(block.timestamp < 1574711999, "ART SALE IS OVER. Tinyboxes are now only available on the secondary market.");
if (numTokens < ARTIST_PRINTS) {
require(_to == address(0xDbB15FCe33304EFC95A9fA7d6bED51431e16Aa2b), "Only the creator can mint the alpha token. Wait your turn FFS");
} else {
uint amount = getprice();
require(msg.value >= amount);
if (msg.value > amount) msg.sender.transfer(msg.value - amount);
artmuseum.transfer(amount);
}
uint id = numTokens + 1;
idToSeed[id] = seed;
(uint256 cc, uint256 sc) = getColorsandShapes(seed);
idTocolorCount[id] = cc;
idToshapeCount[id] = sc;
idToCreator[id] = _to;
numTokens = id;
_addNFToken(_to, numTokens);
emit Transfer(address(0), _to, id);
return perpetualrender(seed, cc, sc);
}
/**
* @dev Assigns a new NFT to an address.
* @notice Use and override this function with caution. Wrong usage can have serious consequences.
* @param _to Address to which 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;
uint256 length = ownerToIds[_to].push(_tokenId);
idToOwnerIndex[_tokenId] = length - 1;
}
/**
* @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 {
require(idToOwner[_tokenId] == _from);
delete idToOwner[_tokenId];
uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId];
uint256 lastTokenIndex = ownerToIds[_from].length - 1;
if (lastTokenIndex != tokenToRemoveIndex) {
uint256 lastToken = ownerToIds[_from][lastTokenIndex];
ownerToIds[_from][tokenToRemoveIndex] = lastToken;
idToOwnerIndex[lastToken] = tokenToRemoveIndex;
}
ownerToIds[_from].length--;
}
/**
* @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
* extension to remove double storage (gas optimization) of owner nft count.
* @param _owner Address for whom to query the count.
* @return Number of _owner NFTs.
*/
function _getOwnerNFTCount(address _owner) internal view returns (uint256) {
return ownerToIds[_owner].length;
}
/**
* @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 memory _data) private canTransfer(_tokenId) validNFToken(_tokenId) {
address tokenOwner = idToOwner[_tokenId];
require(tokenOwner == _from);
require(_to != address(0));
_transfer(_to, _tokenId);
if (isContract(_to)) {
bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
require(retval == MAGIC_ON_ERC721_RECEIVED);
}
}
/**
* @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 (idToApproval[_tokenId] != address(0)) {
delete idToApproval[_tokenId];
}
}
//// Enumerable
function totalSupply() public view returns (uint256) {
return numTokens;
}
//// Metadata
/**
* @dev Returns a descriptive name for a collection of NFTokens.
* @return Representing name.
*/
function name() external view returns (string memory _name) {
_name = nftName;
}
/**
* @dev Returns an abbreviated name for NFTokens.
* @return Representing symbol.
*/
function symbol() external view returns (string memory _symbol) {
_symbol = nftSymbol;
}
/**
* @dev A distinct URI (RFC 3986) for a given NFT.
* @param _tokenId Id for which we want uri.
* @return URI of _tokenId.
*/
function tokenURI(uint256 _tokenId) external view validNFToken(_tokenId) returns (string memory) {
return perpetualrender(idToSeed[_tokenId], idTocolorCount[_tokenId], idToshapeCount[_tokenId]);
}
/**
* @dev Generate the token SVG art
* @param _tokenId Id for which we want art
* @return URI of _tokenId.
*/
function tokenArt(uint256 _tokenId) external view validNFToken(_tokenId) returns (string memory) {
return perpetualrender(idToSeed[_tokenId], idTocolorCount[_tokenId], idToshapeCount[_tokenId]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment