文件 1 的 1:FriendlyFractalsN.sol
pragma solidity 0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
interface 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);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
interface 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 ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.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"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}
interface InterfaceN {
function ownerOf(uint256 tokenId) external view returns (address owner);
function getFirst(uint256 tokenId) external view returns (uint256);
function getSecond(uint256 tokenId) external view returns (uint256);
function getThird(uint256 tokenId) external view returns (uint256);
function getFourth(uint256 tokenId) external view returns (uint256);
function getFifth(uint256 tokenId) external view returns (uint256);
function getSixth(uint256 tokenId) external view returns (uint256);
function getSeventh(uint256 tokenId) external view returns (uint256);
function getEight(uint256 tokenId) external view returns (uint256);
}
contract FriendlyFractalsN is ERC721("Friendly Fractals N", "FRFRACN"), ERC721Enumerable, ReentrancyGuard {
address public addressN;
bytes private uriHead1 = "data:application/json;charset=utf-8,%7B%22name%22%3A%20%22Friendly%20Fractals%20N%20";
bytes private uriHead2 = "%22%2C%22description%22%3A%20%22Fully%20on-chain%20generative%20fractal%20patterns%20based%20on%20the%20your%20n.%22%2C%22image%22%3A%20%22data%3Aimage%2Fsvg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20width%3D'100%25'%20height%3D'100%25'%20viewBox%3D'0%200%20100000%20100000'%20style%3D'stroke-width%3A";
bytes private uriHead3 = "%20background-color%3Argb(0%2C0%2C0)'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E";
bytes private uriTail = "%3C%2Fsvg%3E%22%7D";
constructor(address addressOfN) {
addressN = addressOfN;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function mint(uint256 tokenId) public nonReentrant {
require(tokenId > 0 && tokenId < 8889, "FriendlyFractalsN: Token ID invalid");
require(InterfaceN(addressN).ownerOf(tokenId) == _msgSender(), "FriendlyFractalsN: Must own respective N");
_safeMint(_msgSender(), tokenId);
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return tokenSVGFromSeed(tokenId);
}
function tokenSVGFromSeed(uint256 tokenId) internal view returns (string memory) {
uint256 numIterations = 6;
string[4] memory vars = ["1000000", "1000000", "1000000", "1000000"];
uint256 typea = InterfaceN(addressN).getSixth(tokenId) % 9;
uint256 typeb = InterfaceN(addressN).getSeventh(tokenId) % 9;
uint256 typec = InterfaceN(addressN).getEight(tokenId) % 9;
uint256[] memory data = new uint256[](2**(numIterations+1)-1);
data[0]= compact(35000, 35000, 30000, 30000);
for (uint256 i=0; i<2**numIterations-1; i++) {
if (i < 3) {
data[2*i+1] = getChildData(data[i], true, typea);
data[2*i+2] = getChildData(data[i], false, typea);
} else if (i < 15) {
data[2*i+1] = getChildData(data[i], true, typeb);
data[2*i+2] = getChildData(data[i], false, typeb);
} else {
data[2*i+1] = getChildData(data[i], true, typec);
data[2*i+2] = getChildData(data[i], false, typec);
}
}
bytes memory result = new bytes(84*(2**numIterations)+580);
bytes memory cur;
assembly {
cur := add(result, 32)
}
uint256 totallen = 0;
uint256 linelen;
bytes memory head = getHeadString(tokenId);
(linelen, cur) = copyString(cur, head);
totallen += linelen;
for (uint256 i=2**numIterations-1; i<data.length; i++) {
bytes memory curLine = getCurLine(data, i, vars);
(linelen, cur) = copyString(cur, curLine);
totallen += linelen;
}
(linelen, cur) = copyString(cur, uriTail);
totallen += linelen;
assembly {
mstore(result, totallen)
}
return string(result);
}
function getChildData(uint256 data, bool leftChild, uint256 curtype) internal view returns (uint256) {
int256 x;
int256 y;
int256 dx;
int256 dy;
(x, y, dx, dy) = expand(data);
int256 sqrt2a = 14142;
int256 sqrt2b = 10000;
int256 dx1;
int256 dy1;
int256 dx2;
int256 dy2;
assembly {
dx1 := sdiv(mul(sub(sdiv(mul(dx, sqrt2b), sqrt2a),sdiv(mul(dy, sqrt2b),sqrt2a)),sqrt2b),sqrt2a)
dy1 := sdiv(mul(add(sdiv(mul(dx, sqrt2b), sqrt2a),sdiv(mul(dy, sqrt2b),sqrt2a)),sqrt2b),sqrt2a)
dx2 := sdiv(mul(add(sdiv(mul(dx, sqrt2b), sqrt2a),sdiv(mul(dy, sqrt2b),sqrt2a)),sqrt2b),sqrt2a)
dy2 := sdiv(mul(add(sdiv(mul(add(1,not(dx)), sqrt2b), sqrt2a),sdiv(mul(dy, sqrt2b),sqrt2a)),sqrt2b),sqrt2a)
}
if (leftChild && (curtype == 3) ||
!leftChild && (curtype == 0 || curtype == 4 || curtype == 8)) {
assembly {
x := add(x, dx)
y := add(y, dy)
}
} else if (curtype == 6 ||
!leftChild && (curtype == 1 || curtype == 3)) {
assembly {
x := add(x, dx1)
y := add(y, dy1)
}
} else if (!leftChild && (curtype == 2 || curtype == 5 || curtype == 7)) {
assembly {
x := add(x, dx2)
y := add(y, dy2)
}
}
if (leftChild && (curtype == 0 || curtype == 1 || curtype == 4 || curtype == 5 || curtype == 7) ||
!leftChild && (curtype == 2 || curtype == 5)) {
dx = dx1;
dy = dy1;
} else if (leftChild && (curtype == 6) ||
!leftChild && (curtype == 3 || curtype == 4)) {
assembly {
dx := add(1, not(dx1))
dy := add(1, not(dy1))
}
} else if (leftChild && (curtype == 2 || curtype == 8) ||
!leftChild && (curtype == 1 || curtype == 6)) {
dx = dx2;
dy = dy2;
} else if (leftChild && (curtype == 3) ||
!leftChild && (curtype == 0 || curtype == 7 || curtype == 8)) {
assembly {
dx := add(1, not(dx2))
dy := add(1, not(dy2))
}
}
return compact(x, y, dx, dy);
}
function compact(int256 x, int256 y, int256 dx, int256 dy) internal pure returns (uint256) {
uint256 result = 0;
result |= uint256(dy & 0xffffffff);
result = result << 32;
result |= uint256(dx & 0xffffffff);
result = result << 32;
result |= uint256(y & 0xffffffff);
result = result << 32;
result |= uint256(x & 0xffffffff);
return result;
}
function expand(uint256 vars) internal pure returns (int256 x, int256 y, int256 dx, int256 dy) {
x = int256(int32(uint32(vars)));
vars = vars >> 32;
y = int256(int32(uint32(vars)));
vars = vars >> 32;
dx = int256(int32(uint32(vars)));
vars = vars >> 32;
dy = int256(int32(uint32(vars)));
}
function uintToString(uint v) public pure returns (string memory) {
uint maxlength = 8;
bytes memory reversed = new bytes(maxlength);
uint i = 0;
while (v != 0) {
uint remainder = v % 10;
v = v / 10;
reversed[i++] = bytes1(uint8(48 + remainder));
}
bytes memory s = new bytes(i);
for (uint j = 0; j < i; j++) {
s[j] = reversed[i - j - 1];
}
string memory str = string(s);
return str;
}
function getHeadString(uint256 tokenId) internal view returns (bytes memory) {
uint256 strokeWidth = 100 + 100 * InterfaceN(addressN).getFifth(tokenId);
return abi.encodePacked(uriHead1, "%23", uintToString(tokenId), uriHead2, uintToString(strokeWidth), "%3B%20", getColorString(tokenId), uriHead3);
}
function getColorString(uint256 tokenId) internal view returns (bytes memory) {
uint256 color_h = Math.min(InterfaceN(addressN).getFirst(tokenId), 10) * 33 + Math.min(Math.max(InterfaceN(addressN).getSecond(tokenId), 1), 10) * 3;
uint256 color_s = 30 + Math.min(InterfaceN(addressN).getThird(tokenId), 10) * 7;
uint256 color_l = 20 + Math.min(InterfaceN(addressN).getFourth(tokenId), 10) * 6;
return abi.encodePacked("stroke%3Ahsl(", uintToString(color_h), "%2C", uintToString(color_s), "%25%2C", uintToString(color_l), "%25)%3B");
}
function copyString(bytes memory curPosition, bytes memory strToCopy) internal view returns (uint256 linelen, bytes memory resPosition) {
uint256 numloops = (strToCopy.length + 31) / 32;
linelen = strToCopy.length;
resPosition = curPosition;
assembly {
for { let j := 0 } lt(j, numloops) { j := add(1, j) } { mstore(add(resPosition, mul(32, j)), mload(add(strToCopy, mul(32, add(1, j))))) }
resPosition := add(resPosition, linelen)
}
}
function getCurLine(uint256[] memory data, uint256 index, string[4] memory vars) internal view returns (bytes memory) {
uint256 remainder;
int256 x;
int256 y;
int256 dx;
int256 dy;
(x, y, dx, dy) = expand(data[index]);
uint256 curdigit;
uint256 numdigits;
string memory stringStart;
for (uint256 i=0; i<4; i++) {
curdigit = 0;
numdigits = 0;
uint256 num;
if (i == 0) {
num = uint256(x);
} else if (i == 1) {
num = uint256(y);
} else if (i == 2) {
num = uint256(x+dx);
} else {
num = uint256(y+dy);
}
assembly {
stringStart := mload(add(vars, mul(32, i)))
}
uint256 numcopy = num;
assembly {
for { } gt(numcopy, 0) { numcopy := div(numcopy, 10) } { numdigits := add(numdigits, 1) }
}
assembly {
for {} gt(num, 0) {num := div(num, 10)} {
remainder := add(mod(num, 10), 48)
mstore8(add(stringStart, add(31, sub(numdigits,curdigit))), remainder)
curdigit := add(curdigit, 1)
}
}
assembly {
mstore(stringStart, curdigit)
}
}
return abi.encodePacked("%3Cline%20x1%3D'", vars[0] ,"'%20y1%3D'", vars[1], "'%20x2%3D'", vars[2], "'%20y2%3D'", vars[3], "'%20%2F%3E");
}
}