Skip to content

Instantly share code, notes, and snippets.

@skyfly200
Created May 13, 2020 16:35
Show Gist options
  • Save skyfly200/7c40518d1dd1ab53d628f78555d2e526 to your computer and use it in GitHub Desktop.
Save skyfly200/7c40518d1dd1ab53d628f78555d2e526 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.4.24+commit.e67f0147.js&optimize=false&gist=
/**
*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);
event Generated(uint indexed index, address indexed a, string value);
/// @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(0x63a9dbCe75413036B2B778E670aaBd4493aAF9F3), "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