Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 7 from a total of 7 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer Ownersh... | 20609713 | 560 days ago | IN | 0 ETH | 0.00002625 | ||||
| Add Heads | 20584386 | 563 days ago | IN | 0 ETH | 0.00910447 | ||||
| Add Accessories | 20584368 | 563 days ago | IN | 0 ETH | 0.00202529 | ||||
| Add Glasses | 20584368 | 563 days ago | IN | 0 ETH | 0.00057997 | ||||
| Add Bodies | 20584355 | 563 days ago | IN | 0 ETH | 0.00044518 | ||||
| Set Palette | 20584355 | 563 days ago | IN | 0 ETH | 0.00053468 | ||||
| Add Many Backgro... | 20584355 | 563 days ago | IN | 0 ETH | 0.00022466 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
NounsDescriptorV3
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
/// @title The Nouns NFT descriptor
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { Strings } from '@openzeppelin/contracts/utils/Strings.sol';
import { INounsDescriptorV3 } from './interfaces/INounsDescriptorV3.sol';
import { INounsSeeder } from './interfaces/INounsSeeder.sol';
import { NFTDescriptorV2 } from './libs/NFTDescriptorV2.sol';
import { ISVGRenderer } from './interfaces/ISVGRenderer.sol';
import { INounsArt } from './interfaces/INounsArt.sol';
import { IInflator } from './interfaces/IInflator.sol';
contract NounsDescriptorV3 is INounsDescriptorV3, Ownable {
using Strings for uint256;
// prettier-ignore
// https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt
bytes32 constant COPYRIGHT_CC0_1_0_UNIVERSAL_LICENSE = 0xa2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499;
/// @notice The contract responsible for holding compressed Noun art
INounsArt public art;
/// @notice The contract responsible for constructing SVGs
ISVGRenderer public renderer;
/// @notice Whether or not new Noun parts can be added
bool public override arePartsLocked;
/// @notice Whether or not `tokenURI` should be returned as a data URI (Default: true)
bool public override isDataURIEnabled = true;
/// @notice Base URI, used when isDataURIEnabled is false
string public override baseURI;
/**
* @notice Require that the parts have not been locked.
*/
modifier whenPartsNotLocked() {
require(!arePartsLocked, 'Parts are locked');
_;
}
constructor(INounsArt _art, ISVGRenderer _renderer) {
art = _art;
renderer = _renderer;
}
/**
* @notice Set the Noun's art contract.
* @dev Only callable by the owner when not locked.
*/
function setArt(INounsArt _art) external onlyOwner whenPartsNotLocked {
art = _art;
emit ArtUpdated(_art);
}
/**
* @notice Set the SVG renderer.
* @dev Only callable by the owner.
*/
function setRenderer(ISVGRenderer _renderer) external onlyOwner {
renderer = _renderer;
emit RendererUpdated(_renderer);
}
/**
* @notice Set the art contract's `descriptor`.
* @param descriptor the address to set.
* @dev Only callable by the owner.
*/
function setArtDescriptor(address descriptor) external onlyOwner {
art.setDescriptor(descriptor);
}
/**
* @notice Set the art contract's `inflator`.
* @param inflator the address to set.
* @dev Only callable by the owner.
*/
function setArtInflator(IInflator inflator) external onlyOwner {
art.setInflator(inflator);
}
/**
* @notice Get the number of available Noun `backgrounds`.
*/
function backgroundCount() public view override returns (uint256) {
return art.backgroundCount();
}
/**
* @notice Get the number of available Noun `bodies`.
*/
function bodyCount() public view override returns (uint256) {
return art.bodyCount();
}
/**
* @notice Get the number of available Noun `accessories`.
*/
function accessoryCount() public view override returns (uint256) {
return art.accessoryCount();
}
/**
* @notice Get the number of available Noun `heads`.
*/
function headCount() public view override returns (uint256) {
return art.headCount();
}
/**
* @notice Get the number of available Noun `glasses`.
*/
function glassesCount() public view override returns (uint256) {
return art.glassesCount();
}
/**
* @notice Batch add Noun backgrounds.
* @dev This function can only be called by the owner when not locked.
*/
function addManyBackgrounds(string[] calldata _backgrounds) external override onlyOwner whenPartsNotLocked {
art.addManyBackgrounds(_backgrounds);
}
/**
* @notice Add a Noun background.
* @dev This function can only be called by the owner when not locked.
*/
function addBackground(string calldata _background) external override onlyOwner whenPartsNotLocked {
art.addBackground(_background);
}
/**
* @notice Update a single color palette. This function can be used to
* add a new color palette or update an existing palette.
* @param paletteIndex the identifier of this palette
* @param palette byte array of colors. every 3 bytes represent an RGB color. max length: 256 * 3 = 768
* @dev This function can only be called by the owner when not locked.
*/
function setPalette(uint8 paletteIndex, bytes calldata palette) external override onlyOwner whenPartsNotLocked {
art.setPalette(paletteIndex, palette);
}
/**
* @notice Add a batch of body images.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addBodies(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addBodies(encodedCompressed, decompressedLength, imageCount);
}
/**
* @notice Add a batch of accessory images.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addAccessories(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addAccessories(encodedCompressed, decompressedLength, imageCount);
}
/**
* @notice Add a batch of head images.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addHeads(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addHeads(encodedCompressed, decompressedLength, imageCount);
}
/**
* @notice Add a batch of glasses images.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addGlasses(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addGlasses(encodedCompressed, decompressedLength, imageCount);
}
/**
* @notice Update a single color palette. This function can be used to
* add a new color palette or update an existing palette. This function does not check for data length validity
* (len <= 768, len % 3 == 0).
* @param paletteIndex the identifier of this palette
* @param pointer the address of the contract holding the palette bytes. every 3 bytes represent an RGB color.
* max length: 256 * 3 = 768.
* @dev This function can only be called by the owner when not locked.
*/
function setPalettePointer(uint8 paletteIndex, address pointer) external override onlyOwner whenPartsNotLocked {
art.setPalettePointer(paletteIndex, pointer);
}
/**
* @notice Add a batch of body images from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addBodiesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addBodiesFromPointer(pointer, decompressedLength, imageCount);
}
/**
* @notice Add a batch of accessory images from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addAccessoriesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addAccessoriesFromPointer(pointer, decompressedLength, imageCount);
}
/**
* @notice Add a batch of head images from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addHeadsFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addHeadsFromPointer(pointer, decompressedLength, imageCount);
}
/**
* @notice Add a batch of glasses images from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function addGlassesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
art.addGlassesFromPointer(pointer, decompressedLength, imageCount);
}
/**
* @notice Get a background color by ID.
* @param index the index of the background.
* @return string the RGB hex value of the background.
*/
function backgrounds(uint256 index) public view override returns (string memory) {
return art.backgrounds(index);
}
/**
* @notice Get a head image by ID.
* @param index the index of the head.
* @return bytes the RLE-encoded bytes of the image.
*/
function heads(uint256 index) public view override returns (bytes memory) {
return art.heads(index);
}
/**
* @notice Get a body image by ID.
* @param index the index of the body.
* @return bytes the RLE-encoded bytes of the image.
*/
function bodies(uint256 index) public view override returns (bytes memory) {
return art.bodies(index);
}
/**
* @notice Get an accessory image by ID.
* @param index the index of the accessory.
* @return bytes the RLE-encoded bytes of the image.
*/
function accessories(uint256 index) public view override returns (bytes memory) {
return art.accessories(index);
}
/**
* @notice Get a glasses image by ID.
* @param index the index of the glasses.
* @return bytes the RLE-encoded bytes of the image.
*/
function glasses(uint256 index) public view override returns (bytes memory) {
return art.glasses(index);
}
/**
* @notice Get a color palette by ID.
* @param index the index of the palette.
* @return bytes the palette bytes, where every 3 consecutive bytes represent a color in RGB format.
*/
function palettes(uint8 index) public view override returns (bytes memory) {
return art.palettes(index);
}
/**
* @notice Lock all Noun parts.
* @dev This cannot be reversed and can only be called by the owner when not locked.
*/
function lockParts() external override onlyOwner whenPartsNotLocked {
arePartsLocked = true;
emit PartsLocked();
}
/**
* @notice Toggle a boolean value which determines if `tokenURI` returns a data URI
* or an HTTP URL.
* @dev This can only be called by the owner.
*/
function toggleDataURIEnabled() external override onlyOwner {
bool enabled = !isDataURIEnabled;
isDataURIEnabled = enabled;
emit DataURIToggled(enabled);
}
/**
* @notice Set the base URI for all token IDs. It is automatically
* added as a prefix to the value returned in {tokenURI}, or to the
* token ID if {tokenURI} is empty.
* @dev This can only be called by the owner.
*/
function setBaseURI(string calldata _baseURI) external override onlyOwner {
baseURI = _baseURI;
emit BaseURIUpdated(_baseURI);
}
/**
* @notice Given a token ID and seed, construct a token URI for an official Nouns DAO noun.
* @dev The returned value may be a base64 encoded data URI or an API URL.
*/
function tokenURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view override returns (string memory) {
if (isDataURIEnabled) {
return dataURI(tokenId, seed);
}
return string(abi.encodePacked(baseURI, tokenId.toString()));
}
/**
* @notice Given a token ID and seed, construct a base64 encoded data URI for an official Nouns DAO noun.
*/
function dataURI(uint256 tokenId, INounsSeeder.Seed memory seed) public view override returns (string memory) {
string memory nounId = tokenId.toString();
string memory name = string(abi.encodePacked('Noun ', nounId));
string memory description = string(abi.encodePacked('Noun ', nounId, ' is a member of the Nouns DAO'));
return genericDataURI(name, description, seed);
}
/**
* @notice Given a name, description, and seed, construct a base64 encoded data URI.
*/
function genericDataURI(
string memory name,
string memory description,
INounsSeeder.Seed memory seed
) public view override returns (string memory) {
NFTDescriptorV2.TokenURIParams memory params = NFTDescriptorV2.TokenURIParams({
name: name,
description: description,
parts: getPartsForSeed(seed),
background: art.backgrounds(seed.background)
});
return NFTDescriptorV2.constructTokenURI(renderer, params);
}
/**
* @notice Given a seed, construct a base64 encoded SVG image.
*/
function generateSVGImage(INounsSeeder.Seed memory seed) external view override returns (string memory) {
ISVGRenderer.SVGParams memory params = ISVGRenderer.SVGParams({
parts: getPartsForSeed(seed),
background: art.backgrounds(seed.background)
});
return NFTDescriptorV2.generateSVGImage(renderer, params);
}
/**
* @notice Get all Noun parts for the passed `seed`.
*/
function getPartsForSeed(INounsSeeder.Seed memory seed) public view returns (ISVGRenderer.Part[] memory) {
bytes memory body = art.bodies(seed.body);
bytes memory accessory = art.accessories(seed.accessory);
bytes memory head = art.heads(seed.head);
bytes memory glasses_ = art.glasses(seed.glasses);
ISVGRenderer.Part[] memory parts = new ISVGRenderer.Part[](4);
parts[0] = ISVGRenderer.Part({ image: body, palette: _getPalette(body) });
parts[1] = ISVGRenderer.Part({ image: accessory, palette: _getPalette(accessory) });
parts[2] = ISVGRenderer.Part({ image: head, palette: _getPalette(head) });
parts[3] = ISVGRenderer.Part({ image: glasses_, palette: _getPalette(glasses_) });
return parts;
}
/**
* @notice Get the color palette pointer for the passed part.
*/
function _getPalette(bytes memory part) private view returns (bytes memory) {
return art.palettes(uint8(part[0]));
}
/**
* @notice Replace current batch of accessories images with new ones.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateAccessories(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = accessoryCount();
art.updateAccessories(encodedCompressed, decompressedLength, imageCount);
require(originalCount == accessoryCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of body images with new ones.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateBodies(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = bodyCount();
art.updateBodies(encodedCompressed, decompressedLength, imageCount);
require(originalCount == bodyCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of head images with new ones.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateHeads(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = headCount();
art.updateHeads(encodedCompressed, decompressedLength, imageCount);
require(originalCount == headCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of glasses images with new ones.
* @param encodedCompressed bytes created by taking a string array of RLE-encoded images, abi encoding it as a bytes array,
* and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateGlasses(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = glassesCount();
art.updateGlasses(encodedCompressed, decompressedLength, imageCount);
require(originalCount == glassesCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of accessories images with new ones from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateAccessoriesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = accessoryCount();
art.updateAccessoriesFromPointer(pointer, decompressedLength, imageCount);
require(originalCount == accessoryCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of body images with new ones from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateBodiesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = bodyCount();
art.updateBodiesFromPointer(pointer, decompressedLength, imageCount);
require(originalCount == bodyCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of head images with new ones from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateHeadsFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = headCount();
art.updateHeadsFromPointer(pointer, decompressedLength, imageCount);
require(originalCount == headCount(), 'Image count must remain the same');
}
/**
* @notice Replace current batch of glasses images with new ones from an existing storage contract.
* @param pointer the address of a contract where the image batch was stored using SSTORE2. The data
* format is expected to be like {encodedCompressed}: bytes created by taking a string array of
* RLE-encoded images, abi encoding it as a bytes array, and finally compressing it using deflate.
* @param decompressedLength the size in bytes the images bytes were prior to compression; required input for Inflate.
* @param imageCount the number of images in this batch; used when searching for images among batches.
* @dev This function can only be called by the owner when not locked.
*/
function updateGlassesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external override onlyOwner whenPartsNotLocked {
uint256 originalCount = glassesCount();
art.updateGlassesFromPointer(pointer, decompressedLength, imageCount);
require(originalCount == glassesCount(), 'Image count must remain the same');
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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 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.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /// @title Base64 /// @author Brecht Devos - <[email protected]> /// @notice Provides functions for encoding/decoding base64 library Base64 { string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000" hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000" hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000" hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000"; function encode(bytes memory data) internal pure returns (string memory) { if (data.length == 0) return ''; // load the table into memory string memory table = TABLE_ENCODE; // multiply by 4/3 rounded up uint256 encodedLen = 4 * ((data.length + 2) / 3); // add some extra buffer at the end required for the writing string memory result = new string(encodedLen + 32); assembly { // set the actual output length mstore(result, encodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 3 bytes at a time for {} lt(dataPtr, endPtr) {} { // read 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // write 4 characters mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F)))) resultPtr := add(resultPtr, 1) mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F)))) resultPtr := add(resultPtr, 1) } // padding with '=' switch mod(mload(data), 3) case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } } return result; } function decode(string memory _data) internal pure returns (bytes memory) { bytes memory data = bytes(_data); if (data.length == 0) return new bytes(0); require(data.length % 4 == 0, "invalid base64 decoder input"); // load the table into memory bytes memory table = TABLE_DECODE; // every 4 characters represent 3 bytes uint256 decodedLen = (data.length / 4) * 3; // add some extra buffer at the end required for the writing bytes memory result = new bytes(decodedLen + 32); assembly { // padding with '=' let lastBytes := mload(add(data, mload(data))) if eq(and(lastBytes, 0xFF), 0x3d) { decodedLen := sub(decodedLen, 1) if eq(and(lastBytes, 0xFFFF), 0x3d3d) { decodedLen := sub(decodedLen, 1) } } // set the actual output length mstore(result, decodedLen) // prepare the lookup table let tablePtr := add(table, 1) // input ptr let dataPtr := data let endPtr := add(dataPtr, mload(data)) // result ptr, jump over length let resultPtr := add(result, 32) // run over the input, 4 characters at a time for {} lt(dataPtr, endPtr) {} { // read 4 characters dataPtr := add(dataPtr, 4) let input := mload(dataPtr) // write 3 bytes let output := add( add( shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)), shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))), add( shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)), and(mload(add(tablePtr, and( input , 0xFF))), 0xFF) ) ) mstore(resultPtr, shl(232, output)) resultPtr := add(resultPtr, 3) } } return result; } }
// SPDX-License-Identifier: GPL-3.0
/// @title Interface for Inflator
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { Inflate } from '../libs/Inflate.sol';
interface IInflator {
function puff(bytes memory source, uint256 destlen) external pure returns (Inflate.ErrorCode, bytes memory);
}// SPDX-License-Identifier: GPL-3.0
/// @title Interface for NounsArt
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { IInflator } from './IInflator.sol';
interface INounsArt {
error SenderIsNotDescriptor();
error EmptyPalette();
error BadPaletteLength();
error EmptyBytes();
error BadDecompressedLength();
error BadImageCount();
error ImageNotFound();
error PaletteNotFound();
event DescriptorUpdated(address oldDescriptor, address newDescriptor);
event InflatorUpdated(address oldInflator, address newInflator);
event BackgroundsAdded(uint256 count);
event PaletteSet(uint8 paletteIndex);
event BodiesAdded(uint16 count);
event AccessoriesAdded(uint16 count);
event HeadsAdded(uint16 count);
event GlassesAdded(uint16 count);
event BodiesUpdated(uint16 count);
event AccessoriesUpdated(uint16 count);
event HeadsUpdated(uint16 count);
event GlassesUpdated(uint16 count);
struct NounArtStoragePage {
uint16 imageCount;
uint80 decompressedLength;
address pointer;
}
struct Trait {
NounArtStoragePage[] storagePages;
uint256 storedImagesCount;
}
function descriptor() external view returns (address);
function inflator() external view returns (IInflator);
function setDescriptor(address descriptor) external;
function setInflator(IInflator inflator) external;
function addManyBackgrounds(string[] calldata _backgrounds) external;
function addBackground(string calldata _background) external;
function palettes(uint8 paletteIndex) external view returns (bytes memory);
function setPalette(uint8 paletteIndex, bytes calldata palette) external;
function addBodies(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addAccessories(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addHeads(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addGlasses(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addBodiesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function setPalettePointer(uint8 paletteIndex, address pointer) external;
function addAccessoriesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function addHeadsFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function addGlassesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function backgroundCount() external view returns (uint256);
function bodyCount() external view returns (uint256);
function accessoryCount() external view returns (uint256);
function headCount() external view returns (uint256);
function glassesCount() external view returns (uint256);
function backgrounds(uint256 index) external view returns (string memory);
function heads(uint256 index) external view returns (bytes memory);
function bodies(uint256 index) external view returns (bytes memory);
function accessories(uint256 index) external view returns (bytes memory);
function glasses(uint256 index) external view returns (bytes memory);
function getBodiesTrait() external view returns (Trait memory);
function getAccessoriesTrait() external view returns (Trait memory);
function getHeadsTrait() external view returns (Trait memory);
function getGlassesTrait() external view returns (Trait memory);
function updateBodies(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateAccessories(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateHeads(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateGlasses(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateBodiesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateAccessoriesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateHeadsFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateGlassesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
}// SPDX-License-Identifier: GPL-3.0
/// @title Common interface for NounsDescriptor versions, as used by NounsToken and NounsSeeder.
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { INounsSeeder } from './INounsSeeder.sol';
interface INounsDescriptorMinimal {
///
/// USED BY TOKEN
///
function tokenURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view returns (string memory);
function dataURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view returns (string memory);
///
/// USED BY SEEDER
///
function backgroundCount() external view returns (uint256);
function bodyCount() external view returns (uint256);
function accessoryCount() external view returns (uint256);
function headCount() external view returns (uint256);
function glassesCount() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0
/// @title Interface for NounsDescriptorV3
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { INounsSeeder } from './INounsSeeder.sol';
import { ISVGRenderer } from './ISVGRenderer.sol';
import { INounsArt } from './INounsArt.sol';
import { INounsDescriptorMinimal } from './INounsDescriptorMinimal.sol';
interface INounsDescriptorV3 is INounsDescriptorMinimal {
event PartsLocked();
event DataURIToggled(bool enabled);
event BaseURIUpdated(string baseURI);
event ArtUpdated(INounsArt art);
event RendererUpdated(ISVGRenderer renderer);
error EmptyPalette();
error BadPaletteLength();
error IndexNotFound();
function arePartsLocked() external returns (bool);
function isDataURIEnabled() external returns (bool);
function baseURI() external returns (string memory);
function palettes(uint8 paletteIndex) external view returns (bytes memory);
function backgrounds(uint256 index) external view returns (string memory);
function bodies(uint256 index) external view returns (bytes memory);
function accessories(uint256 index) external view returns (bytes memory);
function heads(uint256 index) external view returns (bytes memory);
function glasses(uint256 index) external view returns (bytes memory);
function backgroundCount() external view override returns (uint256);
function bodyCount() external view override returns (uint256);
function accessoryCount() external view override returns (uint256);
function headCount() external view override returns (uint256);
function glassesCount() external view override returns (uint256);
function addManyBackgrounds(string[] calldata backgrounds) external;
function addBackground(string calldata background) external;
function setPalette(uint8 paletteIndex, bytes calldata palette) external;
function addBodies(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addAccessories(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addHeads(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function addGlasses(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function setPalettePointer(uint8 paletteIndex, address pointer) external;
function addBodiesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function addAccessoriesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function addHeadsFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function addGlassesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function lockParts() external;
function toggleDataURIEnabled() external;
function setBaseURI(string calldata baseURI) external;
function tokenURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view override returns (string memory);
function dataURI(uint256 tokenId, INounsSeeder.Seed memory seed) external view override returns (string memory);
function genericDataURI(
string calldata name,
string calldata description,
INounsSeeder.Seed memory seed
) external view returns (string memory);
function generateSVGImage(INounsSeeder.Seed memory seed) external view returns (string memory);
function updateAccessories(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateBodies(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateHeads(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateGlasses(
bytes calldata encodedCompressed,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateAccessoriesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateBodiesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateHeadsFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
function updateGlassesFromPointer(
address pointer,
uint80 decompressedLength,
uint16 imageCount
) external;
}// SPDX-License-Identifier: GPL-3.0
/// @title Interface for NounsSeeder
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { INounsDescriptorMinimal } from './INounsDescriptorMinimal.sol';
interface INounsSeeder {
struct Seed {
uint48 background;
uint48 body;
uint48 accessory;
uint48 head;
uint48 glasses;
}
function generateSeed(uint256 nounId, INounsDescriptorMinimal descriptor) external view returns (Seed memory);
}// SPDX-License-Identifier: GPL-3.0
/// @title Interface for SVGRenderer
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
interface ISVGRenderer {
struct Part {
bytes image;
bytes palette;
}
struct SVGParams {
Part[] parts;
string background;
}
function generateSVG(SVGParams memory params) external view returns (string memory svg);
function generateSVGPart(Part memory part) external view returns (string memory partialSVG);
function generateSVGParts(Part[] memory parts) external view returns (string memory partialSVG);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.0 <0.9.0;
/// @notice Based on https://github.com/madler/zlib/blob/master/contrib/puff
/// @dev Modified the original code for gas optimizations
/// 1. Disable overflow/underflow checks
/// 2. Chunk some loop iterations
library Inflate {
// Maximum bits in a code
uint256 constant MAXBITS = 15;
// Maximum number of literal/length codes
uint256 constant MAXLCODES = 286;
// Maximum number of distance codes
uint256 constant MAXDCODES = 30;
// Maximum codes lengths to read
uint256 constant MAXCODES = (MAXLCODES + MAXDCODES);
// Number of fixed literal/length codes
uint256 constant FIXLCODES = 288;
// Error codes
enum ErrorCode {
ERR_NONE, // 0 successful inflate
ERR_NOT_TERMINATED, // 1 available inflate data did not terminate
ERR_OUTPUT_EXHAUSTED, // 2 output space exhausted before completing inflate
ERR_INVALID_BLOCK_TYPE, // 3 invalid block type (type == 3)
ERR_STORED_LENGTH_NO_MATCH, // 4 stored block length did not match one's complement
ERR_TOO_MANY_LENGTH_OR_DISTANCE_CODES, // 5 dynamic block code description: too many length or distance codes
ERR_CODE_LENGTHS_CODES_INCOMPLETE, // 6 dynamic block code description: code lengths codes incomplete
ERR_REPEAT_NO_FIRST_LENGTH, // 7 dynamic block code description: repeat lengths with no first length
ERR_REPEAT_MORE, // 8 dynamic block code description: repeat more than specified lengths
ERR_INVALID_LITERAL_LENGTH_CODE_LENGTHS, // 9 dynamic block code description: invalid literal/length code lengths
ERR_INVALID_DISTANCE_CODE_LENGTHS, // 10 dynamic block code description: invalid distance code lengths
ERR_MISSING_END_OF_BLOCK, // 11 dynamic block code description: missing end-of-block code
ERR_INVALID_LENGTH_OR_DISTANCE_CODE, // 12 invalid literal/length or distance code in fixed or dynamic block
ERR_DISTANCE_TOO_FAR, // 13 distance is too far back in fixed or dynamic block
ERR_CONSTRUCT // 14 internal: error in construct()
}
// Input and output state
struct State {
//////////////////
// Output state //
//////////////////
// Output buffer
bytes output;
// Bytes written to out so far
uint256 outcnt;
/////////////////
// Input state //
/////////////////
// Input buffer
bytes input;
// Bytes read so far
uint256 incnt;
////////////////
// Temp state //
////////////////
// Bit buffer
uint256 bitbuf;
// Number of bits in bit buffer
uint256 bitcnt;
//////////////////////////
// Static Huffman codes //
//////////////////////////
Huffman lencode;
Huffman distcode;
}
// Huffman code decoding tables
struct Huffman {
uint256[] counts;
uint256[] symbols;
}
function bits(State memory s, uint256 need) private pure returns (ErrorCode, uint256) {
unchecked {
// Bit accumulator (can use up to 20 bits)
uint256 val;
// Load at least need bits into val
val = s.bitbuf;
while (s.bitcnt < need) {
if (s.incnt == s.input.length) {
// Out of input
return (ErrorCode.ERR_NOT_TERMINATED, 0);
}
// Load eight bits
val |= uint256(uint8(s.input[s.incnt++])) << s.bitcnt;
s.bitcnt += 8;
}
// Drop need bits and update buffer, always zero to seven bits left
s.bitbuf = val >> need;
s.bitcnt -= need;
// Return need bits, zeroing the bits above that
uint256 ret = (val & ((1 << need) - 1));
return (ErrorCode.ERR_NONE, ret);
}
}
function _stored(State memory s) private pure returns (ErrorCode) {
unchecked {
// Length of stored block
uint256 len;
// Discard leftover bits from current byte (assumes s.bitcnt < 8)
s.bitbuf = 0;
s.bitcnt = 0;
// Get length and check against its one's complement
if (s.incnt + 4 > s.input.length) {
// Not enough input
return ErrorCode.ERR_NOT_TERMINATED;
}
len = uint256(uint8(s.input[s.incnt++]));
len |= uint256(uint8(s.input[s.incnt++])) << 8;
if (uint8(s.input[s.incnt++]) != (~len & 0xFF) || uint8(s.input[s.incnt++]) != ((~len >> 8) & 0xFF)) {
// Didn't match complement!
return ErrorCode.ERR_STORED_LENGTH_NO_MATCH;
}
// Copy len bytes from in to out
if (s.incnt + len > s.input.length) {
// Not enough input
return ErrorCode.ERR_NOT_TERMINATED;
}
if (s.outcnt + len > s.output.length) {
// Not enough output space
return ErrorCode.ERR_OUTPUT_EXHAUSTED;
}
while (len != 0) {
// Note: Solidity reverts on underflow, so we decrement here
len -= 1;
s.output[s.outcnt++] = s.input[s.incnt++];
}
// Done with a valid stored block
return ErrorCode.ERR_NONE;
}
}
function _decode(State memory s, Huffman memory h) private pure returns (ErrorCode, uint256) {
unchecked {
// Current number of bits in code
uint256 len;
// Len bits being decoded
uint256 code = 0;
// First code of length len
uint256 first = 0;
// Number of codes of length len
uint256 count;
// Index of first code of length len in symbol table
uint256 index = 0;
// Error code
ErrorCode err;
uint256 tempCode;
for (len = 1; len <= MAXBITS; len += 5) {
// Get next bit
(err, tempCode) = bits(s, 1);
if (err != ErrorCode.ERR_NONE) {
return (err, 0);
}
code |= tempCode;
count = h.counts[len];
// If length len, return symbol
if (code < first + count) {
return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
}
// Else update for next length
index += count;
first += count;
first <<= 1;
code <<= 1;
// Get next bit
(err, tempCode) = bits(s, 1);
if (err != ErrorCode.ERR_NONE) {
return (err, 0);
}
code |= tempCode;
count = h.counts[len + 1];
// If length len, return symbol
if (code < first + count) {
return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
}
// Else update for next length
index += count;
first += count;
first <<= 1;
code <<= 1;
// Get next bit
(err, tempCode) = bits(s, 1);
if (err != ErrorCode.ERR_NONE) {
return (err, 0);
}
code |= tempCode;
count = h.counts[len + 2];
// If length len, return symbol
if (code < first + count) {
return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
}
// Else update for next length
index += count;
first += count;
first <<= 1;
code <<= 1;
// Get next bit
(err, tempCode) = bits(s, 1);
if (err != ErrorCode.ERR_NONE) {
return (err, 0);
}
code |= tempCode;
count = h.counts[len + 3];
// If length len, return symbol
if (code < first + count) {
return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
}
// Else update for next length
index += count;
first += count;
first <<= 1;
code <<= 1;
// Get next bit
(err, tempCode) = bits(s, 1);
if (err != ErrorCode.ERR_NONE) {
return (err, 0);
}
code |= tempCode;
count = h.counts[len + 4];
// If length len, return symbol
if (code < first + count) {
return (ErrorCode.ERR_NONE, h.symbols[index + (code - first)]);
}
// Else update for next length
index += count;
first += count;
first <<= 1;
code <<= 1;
}
// Ran out of codes
return (ErrorCode.ERR_INVALID_LENGTH_OR_DISTANCE_CODE, 0);
}
}
function _construct(
Huffman memory h,
uint256[] memory lengths,
uint256 n,
uint256 start
) private pure returns (ErrorCode) {
unchecked {
// Current symbol when stepping through lengths[]
uint256 symbol;
// Current length when stepping through h.counts[]
uint256 len;
// Number of possible codes left of current length
uint256 left;
// Offsets in symbol table for each length
uint256[MAXBITS + 1] memory offs;
// Count number of codes of each length
for (len = 0; len <= MAXBITS; ++len) {
h.counts[len] = 0;
}
for (symbol = 0; symbol < n; ++symbol) {
// Assumes lengths are within bounds
++h.counts[lengths[start + symbol]];
}
// No codes!
if (h.counts[0] == n) {
// Complete, but decode() will fail
return (ErrorCode.ERR_NONE);
}
// Check for an over-subscribed or incomplete set of lengths
// One possible code of zero length
left = 1;
for (len = 1; len <= MAXBITS; len += 5) {
// One more bit, double codes left
left <<= 1;
if (left < h.counts[len]) {
// Over-subscribed--return error
return ErrorCode.ERR_CONSTRUCT;
}
// Deduct count from possible codes
left -= h.counts[len];
// One more bit, double codes left
left <<= 1;
if (left < h.counts[len + 1]) {
// Over-subscribed--return error
return ErrorCode.ERR_CONSTRUCT;
}
// Deduct count from possible codes
left -= h.counts[len + 1];
// One more bit, double codes left
left <<= 1;
if (left < h.counts[len + 2]) {
// Over-subscribed--return error
return ErrorCode.ERR_CONSTRUCT;
}
// Deduct count from possible codes
left -= h.counts[len + 2];
// One more bit, double codes left
left <<= 1;
if (left < h.counts[len + 3]) {
// Over-subscribed--return error
return ErrorCode.ERR_CONSTRUCT;
}
// Deduct count from possible codes
left -= h.counts[len + 3];
// One more bit, double codes left
left <<= 1;
if (left < h.counts[len + 4]) {
// Over-subscribed--return error
return ErrorCode.ERR_CONSTRUCT;
}
// Deduct count from possible codes
left -= h.counts[len + 4];
}
// Generate offsets into symbol table for each length for sorting
offs[1] = 0;
for (len = 1; len < MAXBITS; ++len) {
offs[len + 1] = offs[len] + h.counts[len];
}
// Put symbols in table sorted by length, by symbol order within each length
for (symbol = 0; symbol < n; ++symbol) {
if (lengths[start + symbol] != 0) {
h.symbols[offs[lengths[start + symbol]]++] = symbol;
}
}
// Left > 0 means incomplete
return left > 0 ? ErrorCode.ERR_CONSTRUCT : ErrorCode.ERR_NONE;
}
}
function _codes(
State memory s,
Huffman memory lencode,
Huffman memory distcode
) private pure returns (ErrorCode) {
unchecked {
// Decoded symbol
uint256 symbol;
// Length for copy
uint256 len;
// Distance for copy
uint256 dist;
// TODO Solidity doesn't support constant arrays, but these are fixed at compile-time
// Size base for length codes 257..285
uint16[29] memory lens = [
3,
4,
5,
6,
7,
8,
9,
10,
11,
13,
15,
17,
19,
23,
27,
31,
35,
43,
51,
59,
67,
83,
99,
115,
131,
163,
195,
227,
258
];
// Extra bits for length codes 257..285
uint8[29] memory lext = [
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
1,
1,
2,
2,
2,
2,
3,
3,
3,
3,
4,
4,
4,
4,
5,
5,
5,
5,
0
];
// Offset base for distance codes 0..29
uint16[30] memory dists = [
1,
2,
3,
4,
5,
7,
9,
13,
17,
25,
33,
49,
65,
97,
129,
193,
257,
385,
513,
769,
1025,
1537,
2049,
3073,
4097,
6145,
8193,
12289,
16385,
24577
];
// Extra bits for distance codes 0..29
uint8[30] memory dext = [
0,
0,
0,
0,
1,
1,
2,
2,
3,
3,
4,
4,
5,
5,
6,
6,
7,
7,
8,
8,
9,
9,
10,
10,
11,
11,
12,
12,
13,
13
];
// Error code
ErrorCode err;
// Decode literals and length/distance pairs
while (symbol != 256) {
(err, symbol) = _decode(s, lencode);
if (err != ErrorCode.ERR_NONE) {
// Invalid symbol
return err;
}
if (symbol < 256) {
// Literal: symbol is the byte
// Write out the literal
if (s.outcnt == s.output.length) {
return ErrorCode.ERR_OUTPUT_EXHAUSTED;
}
s.output[s.outcnt] = bytes1(uint8(symbol));
++s.outcnt;
} else if (symbol > 256) {
uint256 tempBits;
// Length
// Get and compute length
symbol -= 257;
if (symbol >= 29) {
// Invalid fixed code
return ErrorCode.ERR_INVALID_LENGTH_OR_DISTANCE_CODE;
}
(err, tempBits) = bits(s, lext[symbol]);
if (err != ErrorCode.ERR_NONE) {
return err;
}
len = lens[symbol] + tempBits;
// Get and check distance
(err, symbol) = _decode(s, distcode);
if (err != ErrorCode.ERR_NONE) {
// Invalid symbol
return err;
}
(err, tempBits) = bits(s, dext[symbol]);
if (err != ErrorCode.ERR_NONE) {
return err;
}
dist = dists[symbol] + tempBits;
if (dist > s.outcnt) {
// Distance too far back
return ErrorCode.ERR_DISTANCE_TOO_FAR;
}
// Copy length bytes from distance bytes back
if (s.outcnt + len > s.output.length) {
return ErrorCode.ERR_OUTPUT_EXHAUSTED;
}
while (len != 0) {
// Note: Solidity reverts on underflow, so we decrement here
len -= 1;
s.output[s.outcnt] = s.output[s.outcnt - dist];
++s.outcnt;
}
} else {
s.outcnt += len;
}
}
// Done with a valid fixed or dynamic block
return ErrorCode.ERR_NONE;
}
}
function _build_fixed(State memory s) private pure returns (ErrorCode) {
unchecked {
// Build fixed Huffman tables
// TODO this is all a compile-time constant
uint256 symbol;
uint256[] memory lengths = new uint256[](FIXLCODES);
// Literal/length table
for (symbol = 0; symbol < 144; ++symbol) {
lengths[symbol] = 8;
}
for (; symbol < 256; ++symbol) {
lengths[symbol] = 9;
}
for (; symbol < 280; ++symbol) {
lengths[symbol] = 7;
}
for (; symbol < FIXLCODES; ++symbol) {
lengths[symbol] = 8;
}
_construct(s.lencode, lengths, FIXLCODES, 0);
// Distance table
for (symbol = 0; symbol < MAXDCODES; ++symbol) {
lengths[symbol] = 5;
}
_construct(s.distcode, lengths, MAXDCODES, 0);
return ErrorCode.ERR_NONE;
}
}
function _fixed(State memory s) private pure returns (ErrorCode) {
unchecked {
// Decode data until end-of-block code
return _codes(s, s.lencode, s.distcode);
}
}
function _build_dynamic_lengths(State memory s) private pure returns (ErrorCode, uint256[] memory) {
unchecked {
uint256 ncode;
// Index of lengths[]
uint256 index;
// Descriptor code lengths
uint256[] memory lengths = new uint256[](MAXCODES);
// Error code
ErrorCode err;
// Permutation of code length codes
uint8[19] memory order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
(err, ncode) = bits(s, 4);
if (err != ErrorCode.ERR_NONE) {
return (err, lengths);
}
ncode += 4;
// Read code length code lengths (really), missing lengths are zero
for (index = 0; index < ncode; ++index) {
(err, lengths[order[index]]) = bits(s, 3);
if (err != ErrorCode.ERR_NONE) {
return (err, lengths);
}
}
for (; index < 19; ++index) {
lengths[order[index]] = 0;
}
return (ErrorCode.ERR_NONE, lengths);
}
}
function _build_dynamic(State memory s)
private
pure
returns (
ErrorCode,
Huffman memory,
Huffman memory
)
{
unchecked {
// Number of lengths in descriptor
uint256 nlen;
uint256 ndist;
// Index of lengths[]
uint256 index;
// Error code
ErrorCode err;
// Descriptor code lengths
uint256[] memory lengths = new uint256[](MAXCODES);
// Length and distance codes
Huffman memory lencode = Huffman(new uint256[](MAXBITS + 1), new uint256[](MAXLCODES));
Huffman memory distcode = Huffman(new uint256[](MAXBITS + 1), new uint256[](MAXDCODES));
uint256 tempBits;
// Get number of lengths in each table, check lengths
(err, nlen) = bits(s, 5);
if (err != ErrorCode.ERR_NONE) {
return (err, lencode, distcode);
}
nlen += 257;
(err, ndist) = bits(s, 5);
if (err != ErrorCode.ERR_NONE) {
return (err, lencode, distcode);
}
ndist += 1;
if (nlen > MAXLCODES || ndist > MAXDCODES) {
// Bad counts
return (ErrorCode.ERR_TOO_MANY_LENGTH_OR_DISTANCE_CODES, lencode, distcode);
}
(err, lengths) = _build_dynamic_lengths(s);
if (err != ErrorCode.ERR_NONE) {
return (err, lencode, distcode);
}
// Build huffman table for code lengths codes (use lencode temporarily)
err = _construct(lencode, lengths, 19, 0);
if (err != ErrorCode.ERR_NONE) {
// Require complete code set here
return (ErrorCode.ERR_CODE_LENGTHS_CODES_INCOMPLETE, lencode, distcode);
}
// Read length/literal and distance code length tables
index = 0;
while (index < nlen + ndist) {
// Decoded value
uint256 symbol;
// Last length to repeat
uint256 len;
(err, symbol) = _decode(s, lencode);
if (err != ErrorCode.ERR_NONE) {
// Invalid symbol
return (err, lencode, distcode);
}
if (symbol < 16) {
// Length in 0..15
lengths[index++] = symbol;
} else {
// Repeat instruction
// Assume repeating zeros
len = 0;
if (symbol == 16) {
// Repeat last length 3..6 times
if (index == 0) {
// No last length!
return (ErrorCode.ERR_REPEAT_NO_FIRST_LENGTH, lencode, distcode);
}
// Last length
len = lengths[index - 1];
(err, tempBits) = bits(s, 2);
if (err != ErrorCode.ERR_NONE) {
return (err, lencode, distcode);
}
symbol = 3 + tempBits;
} else if (symbol == 17) {
// Repeat zero 3..10 times
(err, tempBits) = bits(s, 3);
if (err != ErrorCode.ERR_NONE) {
return (err, lencode, distcode);
}
symbol = 3 + tempBits;
} else {
// == 18, repeat zero 11..138 times
(err, tempBits) = bits(s, 7);
if (err != ErrorCode.ERR_NONE) {
return (err, lencode, distcode);
}
symbol = 11 + tempBits;
}
if (index + symbol > nlen + ndist) {
// Too many lengths!
return (ErrorCode.ERR_REPEAT_MORE, lencode, distcode);
}
while (symbol != 0) {
// Note: Solidity reverts on underflow, so we decrement here
symbol -= 1;
// Repeat last or zero symbol times
lengths[index++] = len;
}
}
}
// Check for end-of-block code -- there better be one!
if (lengths[256] == 0) {
return (ErrorCode.ERR_MISSING_END_OF_BLOCK, lencode, distcode);
}
// Build huffman table for literal/length codes
err = _construct(lencode, lengths, nlen, 0);
if (
err != ErrorCode.ERR_NONE &&
(err == ErrorCode.ERR_NOT_TERMINATED ||
err == ErrorCode.ERR_OUTPUT_EXHAUSTED ||
nlen != lencode.counts[0] + lencode.counts[1])
) {
// Incomplete code ok only for single length 1 code
return (ErrorCode.ERR_INVALID_LITERAL_LENGTH_CODE_LENGTHS, lencode, distcode);
}
// Build huffman table for distance codes
err = _construct(distcode, lengths, ndist, nlen);
if (
err != ErrorCode.ERR_NONE &&
(err == ErrorCode.ERR_NOT_TERMINATED ||
err == ErrorCode.ERR_OUTPUT_EXHAUSTED ||
ndist != distcode.counts[0] + distcode.counts[1])
) {
// Incomplete code ok only for single length 1 code
return (ErrorCode.ERR_INVALID_DISTANCE_CODE_LENGTHS, lencode, distcode);
}
return (ErrorCode.ERR_NONE, lencode, distcode);
}
}
function _dynamic(State memory s) private pure returns (ErrorCode) {
unchecked {
// Length and distance codes
Huffman memory lencode;
Huffman memory distcode;
// Error code
ErrorCode err;
(err, lencode, distcode) = _build_dynamic(s);
if (err != ErrorCode.ERR_NONE) {
return err;
}
// Decode data until end-of-block code
return _codes(s, lencode, distcode);
}
}
function puff(bytes memory source, uint256 destlen) internal pure returns (ErrorCode, bytes memory) {
unchecked {
// Input/output state
State memory s = State(
new bytes(destlen),
0,
source,
0,
0,
0,
Huffman(new uint256[](MAXBITS + 1), new uint256[](FIXLCODES)),
Huffman(new uint256[](MAXBITS + 1), new uint256[](MAXDCODES))
);
// Temp: last bit
uint256 last;
// Temp: block type bit
uint256 t;
// Error code
ErrorCode err;
// Build fixed Huffman tables
err = _build_fixed(s);
if (err != ErrorCode.ERR_NONE) {
return (err, s.output);
}
// Process blocks until last block or error
while (last == 0) {
// One if last block
(err, last) = bits(s, 1);
if (err != ErrorCode.ERR_NONE) {
return (err, s.output);
}
// Block type 0..3
(err, t) = bits(s, 2);
if (err != ErrorCode.ERR_NONE) {
return (err, s.output);
}
err = (
t == 0
? _stored(s)
: (t == 1 ? _fixed(s) : (t == 2 ? _dynamic(s) : ErrorCode.ERR_INVALID_BLOCK_TYPE))
);
// type == 3, invalid
if (err != ErrorCode.ERR_NONE) {
// Return with error
break;
}
}
return (err, s.output);
}
}
}// SPDX-License-Identifier: GPL-3.0
/// @title A library used to construct ERC721 token URIs and SVG images
/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/
pragma solidity ^0.8.6;
import { Base64 } from 'base64-sol/base64.sol';
import { ISVGRenderer } from '../interfaces/ISVGRenderer.sol';
library NFTDescriptorV2 {
struct TokenURIParams {
string name;
string description;
string background;
ISVGRenderer.Part[] parts;
}
/**
* @notice Construct an ERC721 token URI.
*/
function constructTokenURI(ISVGRenderer renderer, TokenURIParams memory params)
public
view
returns (string memory)
{
string memory image = generateSVGImage(
renderer,
ISVGRenderer.SVGParams({ parts: params.parts, background: params.background })
);
// prettier-ignore
return string(
abi.encodePacked(
'data:application/json;base64,',
Base64.encode(
bytes(
abi.encodePacked('{"name":"', params.name, '", "description":"', params.description, '", "image": "', 'data:image/svg+xml;base64,', image, '"}')
)
)
)
);
}
/**
* @notice Generate an SVG image for use in the ERC721 token URI.
*/
function generateSVGImage(ISVGRenderer renderer, ISVGRenderer.SVGParams memory params)
public
view
returns (string memory svg)
{
return Base64.encode(bytes(renderer.generateSVG(params)));
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/libs/NFTDescriptorV2.sol": {
"NFTDescriptorV2": "0xdedd7ec3f440b19c627ae909d020ff037f618336"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract INounsArt","name":"_art","type":"address"},{"internalType":"contract ISVGRenderer","name":"_renderer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadPaletteLength","type":"error"},{"inputs":[],"name":"EmptyPalette","type":"error"},{"inputs":[],"name":"IndexNotFound","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract INounsArt","name":"art","type":"address"}],"name":"ArtUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"DataURIToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"PartsLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISVGRenderer","name":"renderer","type":"address"}],"name":"RendererUpdated","type":"event"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"accessories","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accessoryCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addAccessories","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addAccessoriesFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_background","type":"string"}],"name":"addBackground","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addBodies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addBodiesFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addGlasses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addGlassesFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addHeads","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"addHeadsFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"_backgrounds","type":"string[]"}],"name":"addManyBackgrounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"arePartsLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"art","outputs":[{"internalType":"contract INounsArt","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"backgroundCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"backgrounds","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"bodies","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bodyCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint48","name":"background","type":"uint48"},{"internalType":"uint48","name":"body","type":"uint48"},{"internalType":"uint48","name":"accessory","type":"uint48"},{"internalType":"uint48","name":"head","type":"uint48"},{"internalType":"uint48","name":"glasses","type":"uint48"}],"internalType":"struct INounsSeeder.Seed","name":"seed","type":"tuple"}],"name":"dataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint48","name":"background","type":"uint48"},{"internalType":"uint48","name":"body","type":"uint48"},{"internalType":"uint48","name":"accessory","type":"uint48"},{"internalType":"uint48","name":"head","type":"uint48"},{"internalType":"uint48","name":"glasses","type":"uint48"}],"internalType":"struct INounsSeeder.Seed","name":"seed","type":"tuple"}],"name":"generateSVGImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"},{"components":[{"internalType":"uint48","name":"background","type":"uint48"},{"internalType":"uint48","name":"body","type":"uint48"},{"internalType":"uint48","name":"accessory","type":"uint48"},{"internalType":"uint48","name":"head","type":"uint48"},{"internalType":"uint48","name":"glasses","type":"uint48"}],"internalType":"struct INounsSeeder.Seed","name":"seed","type":"tuple"}],"name":"genericDataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint48","name":"background","type":"uint48"},{"internalType":"uint48","name":"body","type":"uint48"},{"internalType":"uint48","name":"accessory","type":"uint48"},{"internalType":"uint48","name":"head","type":"uint48"},{"internalType":"uint48","name":"glasses","type":"uint48"}],"internalType":"struct INounsSeeder.Seed","name":"seed","type":"tuple"}],"name":"getPartsForSeed","outputs":[{"components":[{"internalType":"bytes","name":"image","type":"bytes"},{"internalType":"bytes","name":"palette","type":"bytes"}],"internalType":"struct ISVGRenderer.Part[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"glasses","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"glassesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"headCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"heads","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDataURIEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockParts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"palettes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"contract ISVGRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract INounsArt","name":"_art","type":"address"}],"name":"setArt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"descriptor","type":"address"}],"name":"setArtDescriptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IInflator","name":"inflator","type":"address"}],"name":"setArtInflator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"paletteIndex","type":"uint8"},{"internalType":"bytes","name":"palette","type":"bytes"}],"name":"setPalette","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"paletteIndex","type":"uint8"},{"internalType":"address","name":"pointer","type":"address"}],"name":"setPalettePointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISVGRenderer","name":"_renderer","type":"address"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleDataURIEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"uint48","name":"background","type":"uint48"},{"internalType":"uint48","name":"body","type":"uint48"},{"internalType":"uint48","name":"accessory","type":"uint48"},{"internalType":"uint48","name":"head","type":"uint48"},{"internalType":"uint48","name":"glasses","type":"uint48"}],"internalType":"struct INounsSeeder.Seed","name":"seed","type":"tuple"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateAccessories","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateAccessoriesFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateBodies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateBodiesFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateGlasses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateGlassesFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedCompressed","type":"bytes"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateHeads","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pointer","type":"address"},{"internalType":"uint80","name":"decompressedLength","type":"uint80"},{"internalType":"uint16","name":"imageCount","type":"uint16"}],"name":"updateHeadsFromPointer","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040526002805460ff60a81b1916600160a81b17905534801562000023575f80fd5b50604051620031c0380380620031c08339810160408190526200004691620000ea565b620000513362000083565b600180546001600160a01b039384166001600160a01b0319918216179091556002805492909316911617905562000127565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381168114620000e7575f80fd5b50565b5f8060408385031215620000fc575f80fd5b82516200010981620000d2565b60208401519092506200011c81620000d2565b809150509250929050565b61308b80620001355f395ff3fe608060405234801561000f575f80fd5b50600436106102e5575f3560e01c806383f7411611610195578063cc2aa091116100e4578063dfe8478b1161009e578063e79c9ea611610079578063e79c9ea614610668578063eba818061461067b578063f2fde38b14610683578063f4513a6a14610696575f80fd5b8063dfe8478b1461063a578063e497305014610642578063e6b1a3ae14610655575f80fd5b8063cc2aa091146105d2578063cd2b8250146105da578063cd5b95c8146105ed578063ce2f4f5314610600578063d6d7f8b614610614578063dbb55d2d14610627575f80fd5b8063925b63a71161014f578063b982d1b91161012a578063b982d1b914610579578063bc2d45fe1461058c578063bf61df1b1461059f578063c0721cd6146105bf575f80fd5b8063925b63a71461054057806394f3df6114610553578063aa5bf7d814610566575f80fd5b806383f74116146104d157806387db11bd146104e45780638ada6b0f146104f75780638bd54c061461050a5780638da5cb5b1461051d57806391b7916a1461052d575f80fd5b80634daebac2116102515780636c0360eb1161020b57806373ac736b116101e657806373ac736b14610474578063773b9771146104875780637b425651146104ab5780637ca94210146104be575f80fd5b80636c0360eb146104515780636e85653114610459578063715018a61461046c575f80fd5b80634daebac2146103ea57806355f804b3146103f257806356d3163d146104055780635a503f13146104185780635e70664c1461042b578063638ac2701461043e575f80fd5b8063353c36a0116102a2578063353c36a0146103805780633cfdafd3146103935780634479cef2146103a657806344cee73c146103bc5780634531c0a8146103cf578063461fc5af146103d7575f80fd5b8063010ecde7146102e957806304bde4dd146102fe5780630ba3db1a146103275780632a1d07691461033a5780632ea0430014610342578063301bd28e14610355575b5f80fd5b6102fc6102f7366004612468565b6106a9565b005b61031161030c366004612483565b610739565b60405161031e91906124e7565b60405180910390f35b6102fc61033536600461256c565b6107ae565b6102fc61086a565b6103116103503660046126b3565b6108fa565b600154610368906001600160a01b031681565b6040516001600160a01b03909116815260200161031e565b6102fc61038e36600461256c565b610a23565b6103116103a13660046126cd565b610aac565b6103ae610b05565b60405190815260200161031e565b6103116103ca366004612483565b610b75565b6103ae610ba7565b6102fc6103e53660046126f8565b610bee565b6103ae610ca7565b6102fc61040036600461273a565b610cee565b6102fc610413366004612468565b610d62565b610311610426366004612483565b610de0565b6102fc61043936600461273a565b610e12565b61031161044c3660046126cd565b610ec8565b610311610f31565b6102fc6104673660046126f8565b610fbd565b6102fc611044565b6102fc6104823660046126f8565b611078565b60025461049b90600160a01b900460ff1681565b604051901515815260200161031e565b6102fc6104b93660046126f8565b6110ff565b6103116104cc366004612483565b611219565b6102fc6104df3660046126f8565b61124b565b6103116104f23660046127f0565b611311565b600254610368906001600160a01b031681565b6102fc610518366004612866565b611448565b5f546001600160a01b0316610368565b6102fc61053b36600461289b565b6114d6565b6102fc61054e3660046126f8565b61155b565b6102fc61056136600461256c565b611621565b6102fc61057436600461256c565b6116aa565b610311610587366004612483565b611733565b61031161059a366004612909565b611765565b6105b26105ad3660046126b3565b611799565b60405161031e9190612922565b6102fc6105cd36600461256c565b611ace565b6103ae611be4565b6102fc6105e83660046126f8565b611c2b565b6102fc6105fb36600461256c565b611cb2565b60025461049b90600160a81b900460ff1681565b6102fc61062236600461256c565b611d7a565b6102fc6106353660046126f8565b611e42565b6102fc611f08565b6102fc61065036600461256c565b611f81565b6102fc610663366004612468565b612049565b6102fc6106763660046129a7565b6120ea565b6103ae612171565b6102fc610691366004612468565b6121b8565b6102fc6106a4366004612468565b612252565b5f546001600160a01b031633146106db5760405162461bcd60e51b81526004016106d2906129f5565b60405180910390fd5b6001546040516301b9a39760e01b81526001600160a01b038381166004830152909116906301b9a397906024015b5f604051808303815f87803b158015610720575f80fd5b505af1158015610732573d5f803e3d5ffd5b5050505050565b6001546040516304bde4dd60e01b8152600481018390526060916001600160a01b0316906304bde4dd906024015b5f60405180830381865afa158015610781573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526107a89190810190612a58565b92915050565b5f546001600160a01b031633146107d75760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156108015760405162461bcd60e51b81526004016106d290612a9c565b6001546040516305d1ed8d60e11b81526001600160a01b0390911690630ba3db1a90610837908790879087908790600401612aee565b5f604051808303815f87803b15801561084e575f80fd5b505af1158015610860573d5f803e3d5ffd5b5050505050505050565b5f546001600160a01b031633146108935760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156108bd5760405162461bcd60e51b81526004016106d290612a9c565b6002805460ff60a01b1916600160a01b1790556040517f1680ee6d421f70ed6030d2fc4fcb50217a5dd617858d56562b119eca59172e57905f90a1565b60605f604051806040016040528061091185611799565b815260015485516040516304bde4dd60e01b815265ffffffffffff90911660048201526020909201916001600160a01b03909116906304bde4dd906024015f60405180830381865afa158015610969573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109909190810190612a58565b90526002546040516311660d6b60e11b815291925073dedd7ec3f440b19c627ae909d020ff037f618336916322cc1ad6916109db916001600160a01b03909116908590600401612ba4565b5f60405180830381865af41580156109f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a1c9190810190612a58565b9392505050565b5f546001600160a01b03163314610a4c5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615610a765760405162461bcd60e51b81526004016106d290612a9c565b6001546040516301a9e1b560e51b81526001600160a01b039091169063353c36a090610837908790879087908790600401612aee565b600254606090600160a81b900460ff1615610ad257610acb8383610ec8565b90506107a8565b6003610add846122ad565b604051602001610aee929190612c21565b604051602081830303815290604052905092915050565b6001546040805163223ce77960e11b815290515f926001600160a01b031691634479cef29160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b709190612ca4565b905090565b600154604051631133b9cf60e21b8152600481018390526060916001600160a01b0316906344cee73c90602401610767565b600154604080516308a6381560e31b815290515f926001600160a01b031691634531c0a89160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b03163314610c175760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615610c415760405162461bcd60e51b81526004016106d290612a9c565b60015460405163461fc5af60e01b81526001600160a01b039091169063461fc5af90610c7590869086908690600401612cbb565b5f604051808303815f87803b158015610c8c575f80fd5b505af1158015610c9e573d5f803e3d5ffd5b50505050505050565b600154604080516326d75d6160e11b815290515f926001600160a01b031691634daebac29160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b03163314610d175760405162461bcd60e51b81526004016106d2906129f5565b6003610d24828483612d35565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8282604051610d56929190612dee565b60405180910390a15050565b5f546001600160a01b03163314610d8b5760405162461bcd60e51b81526004016106d2906129f5565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f482cbbbcf912da3be80deb8503ae1e94c0b7d5d1d0ec0af3d9d6403e06e609ee906020015b60405180910390a150565b600154604051635a503f1360e01b8152600481018390526060916001600160a01b031690635a503f1390602401610767565b5f546001600160a01b03163314610e3b5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615610e655760405162461bcd60e51b81526004016106d290612a9c565b60015460405163179c199360e21b81526001600160a01b0390911690635e70664c90610e979085908590600401612dee565b5f604051808303815f87803b158015610eae575f80fd5b505af1158015610ec0573d5f803e3d5ffd5b505050505050565b60605f610ed4846122ad565b90505f81604051602001610ee89190612e01565b60405160208183030381529060405290505f82604051602001610f0b9190612e2d565b6040516020818303038152906040529050610f27828287611311565b9695505050505050565b60038054610f3e90612be9565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6a90612be9565b8015610fb55780601f10610f8c57610100808354040283529160200191610fb5565b820191905f5260205f20905b815481529060010190602001808311610f9857829003601f168201915b505050505081565b5f546001600160a01b03163314610fe65760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156110105760405162461bcd60e51b81526004016106d290612a9c565b600154604051636e85653160e01b81526001600160a01b0390911690636e85653190610c7590869086908690600401612cbb565b5f546001600160a01b0316331461106d5760405162461bcd60e51b81526004016106d2906129f5565b6110765f6123b1565b565b5f546001600160a01b031633146110a15760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156110cb5760405162461bcd60e51b81526004016106d290612a9c565b6001546040516373ac736b60e01b81526001600160a01b03909116906373ac736b90610c7590869086908690600401612cbb565b5f546001600160a01b031633146111285760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156111525760405162461bcd60e51b81526004016106d290612a9c565b5f61115b612171565b600154604051637b42565160e01b81529192506001600160a01b031690637b4256519061119090879087908790600401612cbb565b5f604051808303815f87803b1580156111a7575f80fd5b505af11580156111b9573d5f803e3d5ffd5b505050506111c5612171565b81146112135760405162461bcd60e51b815260206004820181905260248201527f496d61676520636f756e74206d7573742072656d61696e207468652073616d6560448201526064016106d2565b50505050565b6001546040516307ca942160e41b8152600481018390526060916001600160a01b031690637ca9421090602401610767565b5f546001600160a01b031633146112745760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561129e5760405162461bcd60e51b81526004016106d290612a9c565b5f6112a7610ca7565b6001546040516341fba08b60e11b81529192506001600160a01b0316906383f74116906112dc90879087908790600401612cbb565b5f604051808303815f87803b1580156112f3575f80fd5b505af1158015611305573d5f803e3d5ffd5b505050506111c5610ca7565b6040805160808101825284815260208101849052600154835183516304bde4dd60e01b815265ffffffffffff90911660048201526060935f9392908301916001600160a01b03909116906304bde4dd906024015f60405180830381865afa15801561137e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113a59190810190612a58565b81526020016113b385611799565b905260025460405163092ba0e960e41b815291925073dedd7ec3f440b19c627ae909d020ff037f618336916392ba0e90916113fe916001600160a01b03909116908590600401612e80565b5f60405180830381865af4158015611418573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261143f9190810190612a58565b95945050505050565b5f546001600160a01b031633146114715760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561149b5760405162461bcd60e51b81526004016106d290612a9c565b6001546040516345eaa60360e11b815260ff841660048201526001600160a01b03838116602483015290911690638bd54c0690604401610e97565b5f546001600160a01b031633146114ff5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156115295760405162461bcd60e51b81526004016106d290612a9c565b6001546040516348dbc8b560e11b81526001600160a01b03909116906391b7916a90610e979085908590600401612f02565b5f546001600160a01b031633146115845760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156115ae5760405162461bcd60e51b81526004016106d290612a9c565b5f6115b7611be4565b60015460405163925b63a760e01b81529192506001600160a01b03169063925b63a7906115ec90879087908790600401612cbb565b5f604051808303815f87803b158015611603575f80fd5b505af1158015611615573d5f803e3d5ffd5b505050506111c5611be4565b5f546001600160a01b0316331461164a5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156116745760405162461bcd60e51b81526004016106d290612a9c565b6001546040516394f3df6160e01b81526001600160a01b03909116906394f3df6190610837908790879087908790600401612aee565b5f546001600160a01b031633146116d35760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156116fd5760405162461bcd60e51b81526004016106d290612a9c565b60015460405163154b7efb60e31b81526001600160a01b039091169063aa5bf7d890610837908790879087908790600401612aee565b60015460405163b982d1b960e01b8152600481018390526060916001600160a01b03169063b982d1b990602401610767565b600154604051635e16a2ff60e11b815260ff831660048201526060916001600160a01b03169063bc2d45fe90602401610767565b6001546020820151604051631133b9cf60e21b815265ffffffffffff90911660048201526060915f916001600160a01b03909116906344cee73c906024015f60405180830381865afa1580156117f1573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118189190810190612a58565b60015460408581015190516307ca942160e41b815265ffffffffffff90911660048201529192505f916001600160a01b0390911690637ca94210906024015f60405180830381865afa158015611870573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118979190810190612a58565b6001546060860151604051635a503f1360e01b815265ffffffffffff90911660048201529192505f916001600160a01b0390911690635a503f13906024015f60405180830381865afa1580156118ef573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119169190810190612a58565b600154608087015160405163b982d1b960e01b815265ffffffffffff90911660048201529192505f916001600160a01b039091169063b982d1b9906024015f60405180830381865afa15801561196e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119959190810190612a58565b60408051600480825260a082019092529192505f9190816020015b60408051808201909152606080825260208201528152602001906001900390816119b057905050905060405180604001604052808681526020016119f387612400565b815250815f81518110611a0857611a08612f99565b60200260200101819052506040518060400160405280858152602001611a2d86612400565b81525081600181518110611a4357611a43612f99565b60200260200101819052506040518060400160405280848152602001611a6885612400565b81525081600281518110611a7e57611a7e612f99565b60200260200101819052506040518060400160405280838152602001611aa384612400565b81525081600381518110611ab957611ab9612f99565b60209081029190910101529695505050505050565b5f546001600160a01b03163314611af75760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611b215760405162461bcd60e51b81526004016106d290612a9c565b5f611b2a612171565b6001546040516360390e6b60e11b81529192506001600160a01b03169063c0721cd690611b61908890889088908890600401612aee565b5f604051808303815f87803b158015611b78575f80fd5b505af1158015611b8a573d5f803e3d5ffd5b50505050611b96612171565b81146107325760405162461bcd60e51b815260206004820181905260248201527f496d61676520636f756e74206d7573742072656d61696e207468652073616d6560448201526064016106d2565b6001546040805163cc2aa09160e01b815290515f926001600160a01b03169163cc2aa0919160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b03163314611c545760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611c7e5760405162461bcd60e51b81526004016106d290612a9c565b600154604051630cd2b82560e41b81526001600160a01b039091169063cd2b825090610c7590869086908690600401612cbb565b5f546001600160a01b03163314611cdb5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611d055760405162461bcd60e51b81526004016106d290612a9c565b5f611d0e610b05565b6001546040516319ab72b960e31b81529192506001600160a01b03169063cd5b95c890611d45908890889088908890600401612aee565b5f604051808303815f87803b158015611d5c575f80fd5b505af1158015611d6e573d5f803e3d5ffd5b50505050611b96610b05565b5f546001600160a01b03163314611da35760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611dcd5760405162461bcd60e51b81526004016106d290612a9c565b5f611dd6610ca7565b600154604051636b6bfc5b60e11b81529192506001600160a01b03169063d6d7f8b690611e0d908890889088908890600401612aee565b5f604051808303815f87803b158015611e24575f80fd5b505af1158015611e36573d5f803e3d5ffd5b50505050611b96610ca7565b5f546001600160a01b03163314611e6b5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611e955760405162461bcd60e51b81526004016106d290612a9c565b5f611e9e610b05565b60015460405163dbb55d2d60e01b81529192506001600160a01b03169063dbb55d2d90611ed390879087908790600401612cbb565b5f604051808303815f87803b158015611eea575f80fd5b505af1158015611efc573d5f803e3d5ffd5b505050506111c5610b05565b5f546001600160a01b03163314611f315760405162461bcd60e51b81526004016106d2906129f5565b6002805460ff60a81b198116600160a81b9182900460ff1615918202179091556040518181527f360c3d72ee193226275b842f85231c259c934e85459fed80fa68e502ffa9dbde90602001610dd5565b5f546001600160a01b03163314611faa5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611fd45760405162461bcd60e51b81526004016106d290612a9c565b5f611fdd611be4565b600154604051630e49730560e41b81529192506001600160a01b03169063e497305090612014908890889088908890600401612aee565b5f604051808303815f87803b15801561202b575f80fd5b505af115801561203d573d5f803e3d5ffd5b50505050611b96611be4565b5f546001600160a01b031633146120725760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561209c5760405162461bcd60e51b81526004016106d290612a9c565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f89382d75256b43b6826ad8d6cbd8e517eaf5e10f1ef4c8f123c9a25ac4529b5590602001610dd5565b5f546001600160a01b031633146121135760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561213d5760405162461bcd60e51b81526004016106d290612a9c565b6001546040516373ce4f5360e11b81526001600160a01b039091169063e79c9ea690610c7590869086908690600401612fad565b600154604080516375d40c0360e11b815290515f926001600160a01b03169163eba818069160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b031633146121e15760405162461bcd60e51b81526004016106d2906129f5565b6001600160a01b0381166122465760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106d2565b61224f816123b1565b50565b5f546001600160a01b0316331461227b5760405162461bcd60e51b81526004016106d2906129f5565b600154604051633955254b60e11b81526001600160a01b038381166004830152909116906372aa4a9690602401610709565b6060815f036122d35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156122fc57806122e681612fdd565b91506122f59050600a83613009565b91506122d6565b5f816001600160401b03811115612315576123156125cc565b6040519080825280601f01601f19166020018201604052801561233f576020820181803683370190505b5090505b84156123a95761235460018361301c565b9150612361600a8661302f565b61236c906030613042565b60f81b81838151811061238157612381612f99565b60200101906001600160f81b03191690815f1a9053506123a2600a86613009565b9450612343565b949350505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60015481516060916001600160a01b03169063bc2d45fe9084905f9061242857612428612f99565b01602001516040516001600160e01b031960e084901b16815260f89190911c6004820152602401610767565b6001600160a01b038116811461224f575f80fd5b5f60208284031215612478575f80fd5b8135610a1c81612454565b5f60208284031215612493575f80fd5b5035919050565b5f5b838110156124b457818101518382015260200161249c565b50505f910152565b5f81518084526124d381602086016020860161249a565b601f01601f19169290920160200192915050565b602081525f610a1c60208301846124bc565b5f8083601f840112612509575f80fd5b5081356001600160401b0381111561251f575f80fd5b602083019150836020828501011115612536575f80fd5b9250929050565b803569ffffffffffffffffffff81168114612556575f80fd5b919050565b803561ffff81168114612556575f80fd5b5f805f806060858703121561257f575f80fd5b84356001600160401b03811115612594575f80fd5b6125a0878288016124f9565b90955093506125b390506020860161253d565b91506125c16040860161255b565b905092959194509250565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715612608576126086125cc565b604052919050565b803565ffffffffffff81168114612556575f80fd5b5f60a08284031215612635575f80fd5b60405160a081018181106001600160401b0382111715612657576126576125cc565b60405290508061266683612610565b815261267460208401612610565b602082015261268560408401612610565b604082015261269660608401612610565b60608201526126a760808401612610565b60808201525092915050565b5f60a082840312156126c3575f80fd5b610a1c8383612625565b5f8060c083850312156126de575f80fd5b823591506126ef8460208501612625565b90509250929050565b5f805f6060848603121561270a575f80fd5b833561271581612454565b92506127236020850161253d565b91506127316040850161255b565b90509250925092565b5f806020838503121561274b575f80fd5b82356001600160401b03811115612760575f80fd5b61276c858286016124f9565b90969095509350505050565b5f6001600160401b03821115612790576127906125cc565b50601f01601f191660200190565b5f82601f8301126127ad575f80fd5b81356127c06127bb82612778565b6125e0565b8181528460208386010111156127d4575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f60e08486031215612802575f80fd5b83356001600160401b0380821115612818575f80fd5b6128248783880161279e565b94506020860135915080821115612839575f80fd5b506128468682870161279e565b9250506127318560408601612625565b803560ff81168114612556575f80fd5b5f8060408385031215612877575f80fd5b61288083612856565b9150602083013561289081612454565b809150509250929050565b5f80602083850312156128ac575f80fd5b82356001600160401b03808211156128c2575f80fd5b818501915085601f8301126128d5575f80fd5b8135818111156128e3575f80fd5b8660208260051b85010111156128f7575f80fd5b60209290920196919550909350505050565b5f60208284031215612919575f80fd5b610a1c82612856565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b8381101561299957888303603f190185528151805187855261296d888601826124bc565b91890151858303868b015291905061298581836124bc565b968901969450505090860190600101612949565b509098975050505050505050565b5f805f604084860312156129b9575f80fd5b6129c284612856565b925060208401356001600160401b038111156129dc575f80fd5b6129e8868287016124f9565b9497909650939450505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b5f612a376127bb84612778565b9050828152838383011115612a4a575f80fd5b610a1c83602083018461249a565b5f60208284031215612a68575f80fd5b81516001600160401b03811115612a7d575f80fd5b8201601f81018413612a8d575f80fd5b6123a984825160208401612a2a565b60208082526010908201526f14185c9d1cc8185c99481b1bd8dad95960821b604082015260600190565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b606081525f612b01606083018688612ac6565b905069ffffffffffffffffffff8416602083015261ffff8316604083015295945050505050565b5f82825180855260208086019550808260051b8401018186015f5b84811015612b9757601f19868403018952815160408151818652612b69828701826124bc565b91505085820151915084810386860152612b8381836124bc565b9a86019a9450505090830190600101612b43565b5090979650505050505050565b60018060a01b0383168152604060208201525f8251604080840152612bcc6080840182612b28565b90506020840151603f19848303016060850152610f2782826124bc565b600181811c90821680612bfd57607f821691505b602082108103612c1b57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f808454612c2e81612be9565b60018281168015612c465760018114612c5b57612c87565b60ff1984168752821515830287019450612c87565b885f526020805f205f5b85811015612c7e5781548a820152908401908201612c65565b50505082870194505b505050508351612c9b81836020880161249a565b01949350505050565b5f60208284031215612cb4575f80fd5b5051919050565b6001600160a01b0393909316835269ffffffffffffffffffff91909116602083015261ffff16604082015260600190565b601f821115612d3057805f5260205f20601f840160051c81016020851015612d115750805b601f840160051c820191505b81811015610732575f8155600101612d1d565b505050565b6001600160401b03831115612d4c57612d4c6125cc565b612d6083612d5a8354612be9565b83612cec565b5f601f841160018114612d91575f8515612d7a5750838201355b5f19600387901b1c1916600186901b178355610732565b5f83815260208120601f198716915b82811015612dc05786850135825560209485019460019092019101612da0565b5086821015612ddc575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b602081525f6123a9602083018486612ac6565b6402737bab7160dd1b81525f8251612e2081600585016020870161249a565b9190910160050192915050565b6402737bab7160dd1b81525f8251612e4c81600585016020870161249a565b7f2069732061206d656d626572206f6620746865204e6f756e732044414f0000006005939091019283015250602201919050565b60018060a01b0383168152604060208201525f825160806040840152612ea960c08401826124bc565b90506020840151603f1980858403016060860152612ec783836124bc565b92506040860151915080858403016080860152612ee483836124bc565b925060608601519150808584030160a086015250610f278282612b28565b60208082528181018390525f906040600585901b8401810190840186845b87811015612f8c57868403603f190183528135368a9003601e19018112612f45575f80fd5b890185810190356001600160401b03811115612f5f575f80fd5b803603821315612f6d575f80fd5b612f78868284612ac6565b955050509184019190840190600101612f20565b5091979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b60ff84168152604060208201525f61143f604083018486612ac6565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612fee57612fee612fc9565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f8261301757613017612ff5565b500490565b818103818111156107a8576107a8612fc9565b5f8261303d5761303d612ff5565b500690565b808201808211156107a8576107a8612fc956fea2646970667358221220879b0597cf0e9a2feb89891dd1c1e3dcb53877cf5b86a797baf88e07dd27517f64736f6c634300081700330000000000000000000000006544bc8a0de6ece429f14840ba74611ca5098a92000000000000000000000000535bd6533f165b880066a9b61e9c5001465f398c
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106102e5575f3560e01c806383f7411611610195578063cc2aa091116100e4578063dfe8478b1161009e578063e79c9ea611610079578063e79c9ea614610668578063eba818061461067b578063f2fde38b14610683578063f4513a6a14610696575f80fd5b8063dfe8478b1461063a578063e497305014610642578063e6b1a3ae14610655575f80fd5b8063cc2aa091146105d2578063cd2b8250146105da578063cd5b95c8146105ed578063ce2f4f5314610600578063d6d7f8b614610614578063dbb55d2d14610627575f80fd5b8063925b63a71161014f578063b982d1b91161012a578063b982d1b914610579578063bc2d45fe1461058c578063bf61df1b1461059f578063c0721cd6146105bf575f80fd5b8063925b63a71461054057806394f3df6114610553578063aa5bf7d814610566575f80fd5b806383f74116146104d157806387db11bd146104e45780638ada6b0f146104f75780638bd54c061461050a5780638da5cb5b1461051d57806391b7916a1461052d575f80fd5b80634daebac2116102515780636c0360eb1161020b57806373ac736b116101e657806373ac736b14610474578063773b9771146104875780637b425651146104ab5780637ca94210146104be575f80fd5b80636c0360eb146104515780636e85653114610459578063715018a61461046c575f80fd5b80634daebac2146103ea57806355f804b3146103f257806356d3163d146104055780635a503f13146104185780635e70664c1461042b578063638ac2701461043e575f80fd5b8063353c36a0116102a2578063353c36a0146103805780633cfdafd3146103935780634479cef2146103a657806344cee73c146103bc5780634531c0a8146103cf578063461fc5af146103d7575f80fd5b8063010ecde7146102e957806304bde4dd146102fe5780630ba3db1a146103275780632a1d07691461033a5780632ea0430014610342578063301bd28e14610355575b5f80fd5b6102fc6102f7366004612468565b6106a9565b005b61031161030c366004612483565b610739565b60405161031e91906124e7565b60405180910390f35b6102fc61033536600461256c565b6107ae565b6102fc61086a565b6103116103503660046126b3565b6108fa565b600154610368906001600160a01b031681565b6040516001600160a01b03909116815260200161031e565b6102fc61038e36600461256c565b610a23565b6103116103a13660046126cd565b610aac565b6103ae610b05565b60405190815260200161031e565b6103116103ca366004612483565b610b75565b6103ae610ba7565b6102fc6103e53660046126f8565b610bee565b6103ae610ca7565b6102fc61040036600461273a565b610cee565b6102fc610413366004612468565b610d62565b610311610426366004612483565b610de0565b6102fc61043936600461273a565b610e12565b61031161044c3660046126cd565b610ec8565b610311610f31565b6102fc6104673660046126f8565b610fbd565b6102fc611044565b6102fc6104823660046126f8565b611078565b60025461049b90600160a01b900460ff1681565b604051901515815260200161031e565b6102fc6104b93660046126f8565b6110ff565b6103116104cc366004612483565b611219565b6102fc6104df3660046126f8565b61124b565b6103116104f23660046127f0565b611311565b600254610368906001600160a01b031681565b6102fc610518366004612866565b611448565b5f546001600160a01b0316610368565b6102fc61053b36600461289b565b6114d6565b6102fc61054e3660046126f8565b61155b565b6102fc61056136600461256c565b611621565b6102fc61057436600461256c565b6116aa565b610311610587366004612483565b611733565b61031161059a366004612909565b611765565b6105b26105ad3660046126b3565b611799565b60405161031e9190612922565b6102fc6105cd36600461256c565b611ace565b6103ae611be4565b6102fc6105e83660046126f8565b611c2b565b6102fc6105fb36600461256c565b611cb2565b60025461049b90600160a81b900460ff1681565b6102fc61062236600461256c565b611d7a565b6102fc6106353660046126f8565b611e42565b6102fc611f08565b6102fc61065036600461256c565b611f81565b6102fc610663366004612468565b612049565b6102fc6106763660046129a7565b6120ea565b6103ae612171565b6102fc610691366004612468565b6121b8565b6102fc6106a4366004612468565b612252565b5f546001600160a01b031633146106db5760405162461bcd60e51b81526004016106d2906129f5565b60405180910390fd5b6001546040516301b9a39760e01b81526001600160a01b038381166004830152909116906301b9a397906024015b5f604051808303815f87803b158015610720575f80fd5b505af1158015610732573d5f803e3d5ffd5b5050505050565b6001546040516304bde4dd60e01b8152600481018390526060916001600160a01b0316906304bde4dd906024015b5f60405180830381865afa158015610781573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526107a89190810190612a58565b92915050565b5f546001600160a01b031633146107d75760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156108015760405162461bcd60e51b81526004016106d290612a9c565b6001546040516305d1ed8d60e11b81526001600160a01b0390911690630ba3db1a90610837908790879087908790600401612aee565b5f604051808303815f87803b15801561084e575f80fd5b505af1158015610860573d5f803e3d5ffd5b5050505050505050565b5f546001600160a01b031633146108935760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156108bd5760405162461bcd60e51b81526004016106d290612a9c565b6002805460ff60a01b1916600160a01b1790556040517f1680ee6d421f70ed6030d2fc4fcb50217a5dd617858d56562b119eca59172e57905f90a1565b60605f604051806040016040528061091185611799565b815260015485516040516304bde4dd60e01b815265ffffffffffff90911660048201526020909201916001600160a01b03909116906304bde4dd906024015f60405180830381865afa158015610969573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109909190810190612a58565b90526002546040516311660d6b60e11b815291925073dedd7ec3f440b19c627ae909d020ff037f618336916322cc1ad6916109db916001600160a01b03909116908590600401612ba4565b5f60405180830381865af41580156109f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a1c9190810190612a58565b9392505050565b5f546001600160a01b03163314610a4c5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615610a765760405162461bcd60e51b81526004016106d290612a9c565b6001546040516301a9e1b560e51b81526001600160a01b039091169063353c36a090610837908790879087908790600401612aee565b600254606090600160a81b900460ff1615610ad257610acb8383610ec8565b90506107a8565b6003610add846122ad565b604051602001610aee929190612c21565b604051602081830303815290604052905092915050565b6001546040805163223ce77960e11b815290515f926001600160a01b031691634479cef29160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b709190612ca4565b905090565b600154604051631133b9cf60e21b8152600481018390526060916001600160a01b0316906344cee73c90602401610767565b600154604080516308a6381560e31b815290515f926001600160a01b031691634531c0a89160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b03163314610c175760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615610c415760405162461bcd60e51b81526004016106d290612a9c565b60015460405163461fc5af60e01b81526001600160a01b039091169063461fc5af90610c7590869086908690600401612cbb565b5f604051808303815f87803b158015610c8c575f80fd5b505af1158015610c9e573d5f803e3d5ffd5b50505050505050565b600154604080516326d75d6160e11b815290515f926001600160a01b031691634daebac29160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b03163314610d175760405162461bcd60e51b81526004016106d2906129f5565b6003610d24828483612d35565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8282604051610d56929190612dee565b60405180910390a15050565b5f546001600160a01b03163314610d8b5760405162461bcd60e51b81526004016106d2906129f5565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f482cbbbcf912da3be80deb8503ae1e94c0b7d5d1d0ec0af3d9d6403e06e609ee906020015b60405180910390a150565b600154604051635a503f1360e01b8152600481018390526060916001600160a01b031690635a503f1390602401610767565b5f546001600160a01b03163314610e3b5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615610e655760405162461bcd60e51b81526004016106d290612a9c565b60015460405163179c199360e21b81526001600160a01b0390911690635e70664c90610e979085908590600401612dee565b5f604051808303815f87803b158015610eae575f80fd5b505af1158015610ec0573d5f803e3d5ffd5b505050505050565b60605f610ed4846122ad565b90505f81604051602001610ee89190612e01565b60405160208183030381529060405290505f82604051602001610f0b9190612e2d565b6040516020818303038152906040529050610f27828287611311565b9695505050505050565b60038054610f3e90612be9565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6a90612be9565b8015610fb55780601f10610f8c57610100808354040283529160200191610fb5565b820191905f5260205f20905b815481529060010190602001808311610f9857829003601f168201915b505050505081565b5f546001600160a01b03163314610fe65760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156110105760405162461bcd60e51b81526004016106d290612a9c565b600154604051636e85653160e01b81526001600160a01b0390911690636e85653190610c7590869086908690600401612cbb565b5f546001600160a01b0316331461106d5760405162461bcd60e51b81526004016106d2906129f5565b6110765f6123b1565b565b5f546001600160a01b031633146110a15760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156110cb5760405162461bcd60e51b81526004016106d290612a9c565b6001546040516373ac736b60e01b81526001600160a01b03909116906373ac736b90610c7590869086908690600401612cbb565b5f546001600160a01b031633146111285760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156111525760405162461bcd60e51b81526004016106d290612a9c565b5f61115b612171565b600154604051637b42565160e01b81529192506001600160a01b031690637b4256519061119090879087908790600401612cbb565b5f604051808303815f87803b1580156111a7575f80fd5b505af11580156111b9573d5f803e3d5ffd5b505050506111c5612171565b81146112135760405162461bcd60e51b815260206004820181905260248201527f496d61676520636f756e74206d7573742072656d61696e207468652073616d6560448201526064016106d2565b50505050565b6001546040516307ca942160e41b8152600481018390526060916001600160a01b031690637ca9421090602401610767565b5f546001600160a01b031633146112745760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561129e5760405162461bcd60e51b81526004016106d290612a9c565b5f6112a7610ca7565b6001546040516341fba08b60e11b81529192506001600160a01b0316906383f74116906112dc90879087908790600401612cbb565b5f604051808303815f87803b1580156112f3575f80fd5b505af1158015611305573d5f803e3d5ffd5b505050506111c5610ca7565b6040805160808101825284815260208101849052600154835183516304bde4dd60e01b815265ffffffffffff90911660048201526060935f9392908301916001600160a01b03909116906304bde4dd906024015f60405180830381865afa15801561137e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526113a59190810190612a58565b81526020016113b385611799565b905260025460405163092ba0e960e41b815291925073dedd7ec3f440b19c627ae909d020ff037f618336916392ba0e90916113fe916001600160a01b03909116908590600401612e80565b5f60405180830381865af4158015611418573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261143f9190810190612a58565b95945050505050565b5f546001600160a01b031633146114715760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561149b5760405162461bcd60e51b81526004016106d290612a9c565b6001546040516345eaa60360e11b815260ff841660048201526001600160a01b03838116602483015290911690638bd54c0690604401610e97565b5f546001600160a01b031633146114ff5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156115295760405162461bcd60e51b81526004016106d290612a9c565b6001546040516348dbc8b560e11b81526001600160a01b03909116906391b7916a90610e979085908590600401612f02565b5f546001600160a01b031633146115845760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156115ae5760405162461bcd60e51b81526004016106d290612a9c565b5f6115b7611be4565b60015460405163925b63a760e01b81529192506001600160a01b03169063925b63a7906115ec90879087908790600401612cbb565b5f604051808303815f87803b158015611603575f80fd5b505af1158015611615573d5f803e3d5ffd5b505050506111c5611be4565b5f546001600160a01b0316331461164a5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156116745760405162461bcd60e51b81526004016106d290612a9c565b6001546040516394f3df6160e01b81526001600160a01b03909116906394f3df6190610837908790879087908790600401612aee565b5f546001600160a01b031633146116d35760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff16156116fd5760405162461bcd60e51b81526004016106d290612a9c565b60015460405163154b7efb60e31b81526001600160a01b039091169063aa5bf7d890610837908790879087908790600401612aee565b60015460405163b982d1b960e01b8152600481018390526060916001600160a01b03169063b982d1b990602401610767565b600154604051635e16a2ff60e11b815260ff831660048201526060916001600160a01b03169063bc2d45fe90602401610767565b6001546020820151604051631133b9cf60e21b815265ffffffffffff90911660048201526060915f916001600160a01b03909116906344cee73c906024015f60405180830381865afa1580156117f1573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118189190810190612a58565b60015460408581015190516307ca942160e41b815265ffffffffffff90911660048201529192505f916001600160a01b0390911690637ca94210906024015f60405180830381865afa158015611870573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118979190810190612a58565b6001546060860151604051635a503f1360e01b815265ffffffffffff90911660048201529192505f916001600160a01b0390911690635a503f13906024015f60405180830381865afa1580156118ef573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119169190810190612a58565b600154608087015160405163b982d1b960e01b815265ffffffffffff90911660048201529192505f916001600160a01b039091169063b982d1b9906024015f60405180830381865afa15801561196e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119959190810190612a58565b60408051600480825260a082019092529192505f9190816020015b60408051808201909152606080825260208201528152602001906001900390816119b057905050905060405180604001604052808681526020016119f387612400565b815250815f81518110611a0857611a08612f99565b60200260200101819052506040518060400160405280858152602001611a2d86612400565b81525081600181518110611a4357611a43612f99565b60200260200101819052506040518060400160405280848152602001611a6885612400565b81525081600281518110611a7e57611a7e612f99565b60200260200101819052506040518060400160405280838152602001611aa384612400565b81525081600381518110611ab957611ab9612f99565b60209081029190910101529695505050505050565b5f546001600160a01b03163314611af75760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611b215760405162461bcd60e51b81526004016106d290612a9c565b5f611b2a612171565b6001546040516360390e6b60e11b81529192506001600160a01b03169063c0721cd690611b61908890889088908890600401612aee565b5f604051808303815f87803b158015611b78575f80fd5b505af1158015611b8a573d5f803e3d5ffd5b50505050611b96612171565b81146107325760405162461bcd60e51b815260206004820181905260248201527f496d61676520636f756e74206d7573742072656d61696e207468652073616d6560448201526064016106d2565b6001546040805163cc2aa09160e01b815290515f926001600160a01b03169163cc2aa0919160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b03163314611c545760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611c7e5760405162461bcd60e51b81526004016106d290612a9c565b600154604051630cd2b82560e41b81526001600160a01b039091169063cd2b825090610c7590869086908690600401612cbb565b5f546001600160a01b03163314611cdb5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611d055760405162461bcd60e51b81526004016106d290612a9c565b5f611d0e610b05565b6001546040516319ab72b960e31b81529192506001600160a01b03169063cd5b95c890611d45908890889088908890600401612aee565b5f604051808303815f87803b158015611d5c575f80fd5b505af1158015611d6e573d5f803e3d5ffd5b50505050611b96610b05565b5f546001600160a01b03163314611da35760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611dcd5760405162461bcd60e51b81526004016106d290612a9c565b5f611dd6610ca7565b600154604051636b6bfc5b60e11b81529192506001600160a01b03169063d6d7f8b690611e0d908890889088908890600401612aee565b5f604051808303815f87803b158015611e24575f80fd5b505af1158015611e36573d5f803e3d5ffd5b50505050611b96610ca7565b5f546001600160a01b03163314611e6b5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611e955760405162461bcd60e51b81526004016106d290612a9c565b5f611e9e610b05565b60015460405163dbb55d2d60e01b81529192506001600160a01b03169063dbb55d2d90611ed390879087908790600401612cbb565b5f604051808303815f87803b158015611eea575f80fd5b505af1158015611efc573d5f803e3d5ffd5b505050506111c5610b05565b5f546001600160a01b03163314611f315760405162461bcd60e51b81526004016106d2906129f5565b6002805460ff60a81b198116600160a81b9182900460ff1615918202179091556040518181527f360c3d72ee193226275b842f85231c259c934e85459fed80fa68e502ffa9dbde90602001610dd5565b5f546001600160a01b03163314611faa5760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff1615611fd45760405162461bcd60e51b81526004016106d290612a9c565b5f611fdd611be4565b600154604051630e49730560e41b81529192506001600160a01b03169063e497305090612014908890889088908890600401612aee565b5f604051808303815f87803b15801561202b575f80fd5b505af115801561203d573d5f803e3d5ffd5b50505050611b96611be4565b5f546001600160a01b031633146120725760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561209c5760405162461bcd60e51b81526004016106d290612a9c565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f89382d75256b43b6826ad8d6cbd8e517eaf5e10f1ef4c8f123c9a25ac4529b5590602001610dd5565b5f546001600160a01b031633146121135760405162461bcd60e51b81526004016106d2906129f5565b600254600160a01b900460ff161561213d5760405162461bcd60e51b81526004016106d290612a9c565b6001546040516373ce4f5360e11b81526001600160a01b039091169063e79c9ea690610c7590869086908690600401612fad565b600154604080516375d40c0360e11b815290515f926001600160a01b03169163eba818069160048083019260209291908290030181865afa158015610b4c573d5f803e3d5ffd5b5f546001600160a01b031633146121e15760405162461bcd60e51b81526004016106d2906129f5565b6001600160a01b0381166122465760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106d2565b61224f816123b1565b50565b5f546001600160a01b0316331461227b5760405162461bcd60e51b81526004016106d2906129f5565b600154604051633955254b60e11b81526001600160a01b038381166004830152909116906372aa4a9690602401610709565b6060815f036122d35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156122fc57806122e681612fdd565b91506122f59050600a83613009565b91506122d6565b5f816001600160401b03811115612315576123156125cc565b6040519080825280601f01601f19166020018201604052801561233f576020820181803683370190505b5090505b84156123a95761235460018361301c565b9150612361600a8661302f565b61236c906030613042565b60f81b81838151811061238157612381612f99565b60200101906001600160f81b03191690815f1a9053506123a2600a86613009565b9450612343565b949350505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60015481516060916001600160a01b03169063bc2d45fe9084905f9061242857612428612f99565b01602001516040516001600160e01b031960e084901b16815260f89190911c6004820152602401610767565b6001600160a01b038116811461224f575f80fd5b5f60208284031215612478575f80fd5b8135610a1c81612454565b5f60208284031215612493575f80fd5b5035919050565b5f5b838110156124b457818101518382015260200161249c565b50505f910152565b5f81518084526124d381602086016020860161249a565b601f01601f19169290920160200192915050565b602081525f610a1c60208301846124bc565b5f8083601f840112612509575f80fd5b5081356001600160401b0381111561251f575f80fd5b602083019150836020828501011115612536575f80fd5b9250929050565b803569ffffffffffffffffffff81168114612556575f80fd5b919050565b803561ffff81168114612556575f80fd5b5f805f806060858703121561257f575f80fd5b84356001600160401b03811115612594575f80fd5b6125a0878288016124f9565b90955093506125b390506020860161253d565b91506125c16040860161255b565b905092959194509250565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715612608576126086125cc565b604052919050565b803565ffffffffffff81168114612556575f80fd5b5f60a08284031215612635575f80fd5b60405160a081018181106001600160401b0382111715612657576126576125cc565b60405290508061266683612610565b815261267460208401612610565b602082015261268560408401612610565b604082015261269660608401612610565b60608201526126a760808401612610565b60808201525092915050565b5f60a082840312156126c3575f80fd5b610a1c8383612625565b5f8060c083850312156126de575f80fd5b823591506126ef8460208501612625565b90509250929050565b5f805f6060848603121561270a575f80fd5b833561271581612454565b92506127236020850161253d565b91506127316040850161255b565b90509250925092565b5f806020838503121561274b575f80fd5b82356001600160401b03811115612760575f80fd5b61276c858286016124f9565b90969095509350505050565b5f6001600160401b03821115612790576127906125cc565b50601f01601f191660200190565b5f82601f8301126127ad575f80fd5b81356127c06127bb82612778565b6125e0565b8181528460208386010111156127d4575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f60e08486031215612802575f80fd5b83356001600160401b0380821115612818575f80fd5b6128248783880161279e565b94506020860135915080821115612839575f80fd5b506128468682870161279e565b9250506127318560408601612625565b803560ff81168114612556575f80fd5b5f8060408385031215612877575f80fd5b61288083612856565b9150602083013561289081612454565b809150509250929050565b5f80602083850312156128ac575f80fd5b82356001600160401b03808211156128c2575f80fd5b818501915085601f8301126128d5575f80fd5b8135818111156128e3575f80fd5b8660208260051b85010111156128f7575f80fd5b60209290920196919550909350505050565b5f60208284031215612919575f80fd5b610a1c82612856565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b8381101561299957888303603f190185528151805187855261296d888601826124bc565b91890151858303868b015291905061298581836124bc565b968901969450505090860190600101612949565b509098975050505050505050565b5f805f604084860312156129b9575f80fd5b6129c284612856565b925060208401356001600160401b038111156129dc575f80fd5b6129e8868287016124f9565b9497909650939450505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b5f612a376127bb84612778565b9050828152838383011115612a4a575f80fd5b610a1c83602083018461249a565b5f60208284031215612a68575f80fd5b81516001600160401b03811115612a7d575f80fd5b8201601f81018413612a8d575f80fd5b6123a984825160208401612a2a565b60208082526010908201526f14185c9d1cc8185c99481b1bd8dad95960821b604082015260600190565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b606081525f612b01606083018688612ac6565b905069ffffffffffffffffffff8416602083015261ffff8316604083015295945050505050565b5f82825180855260208086019550808260051b8401018186015f5b84811015612b9757601f19868403018952815160408151818652612b69828701826124bc565b91505085820151915084810386860152612b8381836124bc565b9a86019a9450505090830190600101612b43565b5090979650505050505050565b60018060a01b0383168152604060208201525f8251604080840152612bcc6080840182612b28565b90506020840151603f19848303016060850152610f2782826124bc565b600181811c90821680612bfd57607f821691505b602082108103612c1b57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f808454612c2e81612be9565b60018281168015612c465760018114612c5b57612c87565b60ff1984168752821515830287019450612c87565b885f526020805f205f5b85811015612c7e5781548a820152908401908201612c65565b50505082870194505b505050508351612c9b81836020880161249a565b01949350505050565b5f60208284031215612cb4575f80fd5b5051919050565b6001600160a01b0393909316835269ffffffffffffffffffff91909116602083015261ffff16604082015260600190565b601f821115612d3057805f5260205f20601f840160051c81016020851015612d115750805b601f840160051c820191505b81811015610732575f8155600101612d1d565b505050565b6001600160401b03831115612d4c57612d4c6125cc565b612d6083612d5a8354612be9565b83612cec565b5f601f841160018114612d91575f8515612d7a5750838201355b5f19600387901b1c1916600186901b178355610732565b5f83815260208120601f198716915b82811015612dc05786850135825560209485019460019092019101612da0565b5086821015612ddc575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b602081525f6123a9602083018486612ac6565b6402737bab7160dd1b81525f8251612e2081600585016020870161249a565b9190910160050192915050565b6402737bab7160dd1b81525f8251612e4c81600585016020870161249a565b7f2069732061206d656d626572206f6620746865204e6f756e732044414f0000006005939091019283015250602201919050565b60018060a01b0383168152604060208201525f825160806040840152612ea960c08401826124bc565b90506020840151603f1980858403016060860152612ec783836124bc565b92506040860151915080858403016080860152612ee483836124bc565b925060608601519150808584030160a086015250610f278282612b28565b60208082528181018390525f906040600585901b8401810190840186845b87811015612f8c57868403603f190183528135368a9003601e19018112612f45575f80fd5b890185810190356001600160401b03811115612f5f575f80fd5b803603821315612f6d575f80fd5b612f78868284612ac6565b955050509184019190840190600101612f20565b5091979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b60ff84168152604060208201525f61143f604083018486612ac6565b634e487b7160e01b5f52601160045260245ffd5b5f60018201612fee57612fee612fc9565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f8261301757613017612ff5565b500490565b818103818111156107a8576107a8612fc9565b5f8261303d5761303d612ff5565b500690565b808201808211156107a8576107a8612fc956fea2646970667358221220879b0597cf0e9a2feb89891dd1c1e3dcb53877cf5b86a797baf88e07dd27517f64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006544bc8a0de6ece429f14840ba74611ca5098a92000000000000000000000000535bd6533f165b880066a9b61e9c5001465f398c
-----Decoded View---------------
Arg [0] : _art (address): 0x6544bC8A0dE6ECe429F14840BA74611cA5098A92
Arg [1] : _renderer (address): 0x535BD6533f165B880066A9B61e9C5001465F398C
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006544bc8a0de6ece429f14840ba74611ca5098a92
Arg [1] : 000000000000000000000000535bd6533f165b880066a9b61e9c5001465f398c
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.