Latest 25 from a total of 14,708 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Create With Sign... | 140903898 | 137 days ago | IN | 0.00069 ETH | 0.000000067738 | ||||
| Create With Sign... | 139804071 | 163 days ago | IN | 0.00269 ETH | 0.000000110512 | ||||
| Create With Sign... | 139804063 | 163 days ago | IN | 0.00169 ETH | 0.000000102959 | ||||
| Create With Sign... | 137864146 | 208 days ago | IN | 0.00069 ETH | 0.000000098138 | ||||
| Create With Sign... | 137753900 | 210 days ago | IN | 0.00169 ETH | 0.000000076898 | ||||
| Create With Sign... | 136466809 | 240 days ago | IN | 0.00069 ETH | 0.000000335165 | ||||
| Create With Sign... | 136035588 | 250 days ago | IN | 0.00069 ETH | 0.000000184245 | ||||
| Create With Sign... | 135468372 | 263 days ago | IN | 0.00069 ETH | 0.000000957635 | ||||
| Create With Sign... | 135468354 | 263 days ago | IN | 0.00069 ETH | 0.000001647216 | ||||
| Create With Sign... | 135468320 | 263 days ago | IN | 0.00069 ETH | 0.000001893144 | ||||
| Create With Sign... | 135468301 | 263 days ago | IN | 0.00069 ETH | 0.000002301784 | ||||
| Create With Sign... | 135468277 | 263 days ago | IN | 0.00069 ETH | 0.000002727486 | ||||
| Create With Sign... | 135468258 | 263 days ago | IN | 0.00069 ETH | 0.00000271483 | ||||
| Create With Sign... | 135468228 | 263 days ago | IN | 0.00069 ETH | 0.000002645462 | ||||
| Create With Sign... | 135468207 | 263 days ago | IN | 0.00069 ETH | 0.000002730808 | ||||
| Create With Sign... | 135468186 | 263 days ago | IN | 0.00069 ETH | 0.000002905066 | ||||
| Create With Sign... | 133517994 | 308 days ago | IN | 0.00069 ETH | 0.000000190776 | ||||
| Create With Sign... | 133517991 | 308 days ago | IN | 0.00069 ETH | 0.000000210696 | ||||
| Create With Sign... | 133517987 | 308 days ago | IN | 0.00069 ETH | 0.000000204616 | ||||
| Create With Sign... | 132952554 | 322 days ago | IN | 0.00069 ETH | 0.000000085699 | ||||
| Create With Sign... | 132048519 | 342 days ago | IN | 0.00069 ETH | 0.000000719379 | ||||
| Create With Sign... | 131510154 | 355 days ago | IN | 0.00169 ETH | 0.00000083817 | ||||
| Create With Sign... | 131223989 | 362 days ago | IN | 0.00069 ETH | 0.000000422671 | ||||
| Create With Sign... | 131223973 | 362 days ago | IN | 0.00069 ETH | 0.000000389258 | ||||
| Create With Sign... | 131223930 | 362 days ago | IN | 0.00069 ETH | 0.000000391031 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 140903898 | 137 days ago | 0.00069 ETH | ||||
| 140903898 | 137 days ago | Contract Creation | 0 ETH | |||
| 139804071 | 163 days ago | 0.00269 ETH | ||||
| 139804071 | 163 days ago | Contract Creation | 0 ETH | |||
| 139804063 | 163 days ago | 0.00169 ETH | ||||
| 139804063 | 163 days ago | Contract Creation | 0 ETH | |||
| 137864146 | 208 days ago | 0.00069 ETH | ||||
| 137864146 | 208 days ago | Contract Creation | 0 ETH | |||
| 137753900 | 210 days ago | 0.00169 ETH | ||||
| 137753900 | 210 days ago | Contract Creation | 0 ETH | |||
| 136466809 | 240 days ago | 0.00069 ETH | ||||
| 136466809 | 240 days ago | Contract Creation | 0 ETH | |||
| 136035588 | 250 days ago | 0.00069 ETH | ||||
| 136035588 | 250 days ago | Contract Creation | 0 ETH | |||
| 135468372 | 263 days ago | 0.00069 ETH | ||||
| 135468372 | 263 days ago | Contract Creation | 0 ETH | |||
| 135468354 | 263 days ago | 0.00069 ETH | ||||
| 135468354 | 263 days ago | Contract Creation | 0 ETH | |||
| 135468320 | 263 days ago | 0.00069 ETH | ||||
| 135468320 | 263 days ago | Contract Creation | 0 ETH | |||
| 135468301 | 263 days ago | 0.00069 ETH | ||||
| 135468301 | 263 days ago | Contract Creation | 0 ETH | |||
| 135468277 | 263 days ago | 0.00069 ETH | ||||
| 135468277 | 263 days ago | Contract Creation | 0 ETH | |||
| 135468258 | 263 days ago | 0.00069 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
WritingEditionsFactory
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.0; /// > [[[[[[[[[[[ Imports ]]]]]]]]]]] import "./WritingEditions.sol"; import "./interface/IWritingEditionsFactory.sol"; import "../observability/Observability.sol"; import "../lib/ERC1271/interface/IERC1271.sol"; import "../lib/Ownable.sol"; /// > [[[[[[[[[[[ External Library Imports ]]]]]]]]]]] import "openzeppelin-contracts/contracts/proxy/Clones.sol"; import "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; import "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol"; /** * @title WritingEditionsFactory * @notice The WritingEditionsFactory contract deploys WritingEdition clones. * A WritingEdition is a token that supports ERC721: Non-Fungible Token Standard. * The factory supports deploying clones with account signatures for counterfactual * contract deployments when minting a token, otherwise colloquially known as "lazy minting". * @author MirrorXYZ * @custom:security-contact [email protected] */ contract WritingEditionsFactory is Ownable, ReentrancyGuard, IWritingEditionsFactoryEvents, IWritingEditionsFactory, IObservabilityEvents { /// @notice Version. uint8 public immutable override VERSION = 2; /// @notice Observability contract for data processing. address public immutable override o11y; /// @notice Treasury configuration. address public immutable override treasuryConfiguration; /// @notice Transaction Reentrancy Guard. bool public override guardOn; /// > [[[[[[[[[[[ Deployments ]]]]]]]]]]] /// @notice Writing edition implementation. address public override implementation; /// @dev Store when a salt is used. mapping(bytes32 => bool) public override salts; /// @dev Contract/domain separator for generating a salt. bytes32 public immutable override DOMAIN_SEPARATOR; /// @dev Create function separator for generating a salt. bytes32 public constant override CREATE_TYPEHASH = keccak256( "Create(address owner,bytes32 salt,uint256 limit,uint256 price,address fundingRecipient,address renderer,uint256 nonce)" ); /// @dev Max limit. uint256 public override maxLimit; /// > [[[[[[[[[[[ Signature Verification ]]]]]]]]]]] /// @dev Used to verify smart contract signatures (ERC1271). bytes4 internal constant MAGIC_VALUE = bytes4(keccak256("isValidSignature(bytes32,bytes)")); /// > [[[[[[[[[[[ Description ]]]]]]]]]]] /// @notice Base URI for clone description. string public constant override baseDescriptionURI = "https://mirror.xyz/"; /// > [[[[[[[[[[[ Constructor ]]]]]]]]]]] /// @notice Stores treasury, generates domain-separator, and deploys /// observability and implementation contracts. /// @param _treasuryConfiguration Mirror treasury configuration. /// @param _o11y Observability contract. /// @param _maxLimit Max edition limit. /// @param _guardOn Guard status. constructor( address _owner, address _treasuryConfiguration, address _o11y, uint256 _maxLimit, bool _guardOn ) Ownable(_owner) { require( _treasuryConfiguration != address(0), "must set treasury config" ); // Store treasury configuration. treasuryConfiguration = _treasuryConfiguration; // Generate domain separator. DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256( "EIP712Domain(string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes("1")), block.chainid, address(this) ) ); // Set implementation contract. implementation = address( new WritingEditions(address(this), _treasuryConfiguration, _o11y) ); // Set observability contract. o11y = _o11y; // slither-disable-next-line reentrancy-no-eth IObservability(_o11y).emitFactoryImplementationSet( // oldImplementation address(0), // newImplementation implementation ); // Store guard status. guardOn = _guardOn; // Store max limit. maxLimit = _maxLimit; } /// > [[[[[[[[[[[ View functions ]]]]]]]]]]] /// @notice Generates the address that a clone will be deployed to. /// @param _implementation the WritingEditions address. /// @param salt the entropy used by create2 for generatating a deterministic address. function predictDeterministicAddress( address _implementation, bytes32 salt ) external view override returns (address) { return Clones.predictDeterministicAddress( _implementation, salt, address(this) ); } /// @notice Generates the salt parameter for `owner` to sign. The signature /// and parameters can be used to deploy a clone through `createWithSignature`. /// @param owner owner of the clone. /// @param edition edition parameters used to deploy the clone. function getSalt( address owner, WritingEditions.WritingEdition memory edition ) external view returns (bytes32) { return _getSalt(owner, edition); } /// @notice validate that a `salt` was signed by `owner`. /// @param owner owner of the clone. /// @param v signature value. /// @param r signature value. /// @param s signature value. function isValid( address owner, bytes32 salt, uint8 v, bytes32 r, bytes32 s ) external view override returns (bool) { return _isValid(owner, salt, v, r, s); } /// > [[[[[[[[[[[ Limit ]]]]]]]]]]] function setLimit(uint256 _maxLimit) external override onlyOwner { // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitFactoryLimitSet( // oldLimit maxLimit, // newLimit _maxLimit ); // Store max limit. maxLimit = _maxLimit; } /// > [[[[[[[[[[[ Guard ]]]]]]]]]]] function setGuard(bool _guardOn) external override onlyOwner { // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitFactoryGuardSet(_guardOn); // Store guard status. guardOn = _guardOn; } /// > [[[[[[[[[[[ Implementation ]]]]]]]]]]] function setImplementation( address _implementation ) external override onlyOwner { // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitFactoryImplementationSet( // oldImplementation implementation, // newImplementation _implementation ); // Store implementation. implementation = _implementation; } /// > [[[[[[[[[[[ Deployment functions ]]]]]]]]]]] /// @notice Deploy a new writing edition clone with the sender as the owner. /// @param edition edition parameters used to deploy the clone. function create( WritingEditions.WritingEdition memory edition ) external override returns (address clone) { clone = _deployCloneAndInitialize(msg.sender, edition, address(0), ""); } /// @dev Deploy a new writing edition clone with a signature provided by `owner`. /// @param owner owner of the clone. /// @param edition edition parameters used to deploy the clone. /// @param v signature value. /// @param r signature value. /// @param s signature value. /// @param tokenRecipient account that will receive the first minted token. /// @param message message sent with the token purchase, not stored. function createWithSignature( address owner, WritingEditions.WritingEdition memory edition, uint8 v, bytes32 r, bytes32 s, address tokenRecipient, string memory message ) external payable override nonReentrant returns (address clone) { // Generate salt from parameters. bytes32 salt = _getSalt(owner, edition); // If the clone has been deployed, purchase instead of deploying. if (salts[salt]) { clone = Clones.predictDeterministicAddress( implementation, keccak256( abi.encode( owner, edition.name, edition.symbol, edition.nonce ) ), address(this) ); require(clone.code.length > 0, "invalid clone address"); // slither-disable-next-line unused-return WritingEditions(clone).purchase{value: msg.value}( tokenRecipient, message ); } else { salts[salt] = true; // Assert the signature is valid. require( _isValid(owner, salt, v, r, s), "invalid or unable to verify signature" ); clone = _deployCloneAndInitialize( owner, edition, tokenRecipient, message ); } } /// > [[[[[[[[[[[ Tributary ]]]]]]]]]]] /// @notice Set a new tributary. /// @param _tributary new tributary. function setTributary(address clone, address _tributary) external override { require(msg.sender == Ownable(clone).owner(), "unauthorized"); address tributaryRegistry = _getTributaryRegistry(); // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitTributarySet( // clone clone, // oldTributary ITributaryRegistry(tributaryRegistry).producerToTributary(clone), // newTributary _tributary ); ITributaryRegistry(tributaryRegistry).setTributary(clone, _tributary); } /// > [[[[[[[[[[[ Internal functions ]]]]]]]]]]] function _isValid( address owner, bytes32 salt, uint8 v, bytes32 r, bytes32 s ) internal view returns (bool) { require(owner != address(0), "cannot validate"); // If the owner is a contract, attempt to validate the // signature using EIP-1271. if (owner.code.length != 0) { bytes memory signature = abi.encodePacked(r, s, v); // slither-disable-next-line unused-return try IERC1271(owner).isValidSignature(salt, signature) returns ( // slither-disable-next-line uninitialized-local bytes4 magicValue ) { return MAGIC_VALUE == magicValue; } catch { return false; } } address recoveredAddress = ECDSA.recover(salt, v, r, s); return recoveredAddress == owner; } function _getSalt( address owner, WritingEditions.WritingEdition memory edition ) internal view returns (bytes32) { return ECDSA.toTypedDataHash( DOMAIN_SEPARATOR, keccak256( abi.encode( CREATE_TYPEHASH, owner, keccak256( abi.encodePacked( edition.name, edition.symbol, edition.imageURI, edition.contentURI ) ), edition.limit, edition.price, edition.fundingRecipient, edition.renderer, edition.nonce ) ) ); } /// @dev Deploys a clone and calls the initialize function. Additionally, /// this function calls `registerTributary` on the tributary registry, if /// one is set. function _deployCloneAndInitialize( address owner, WritingEditions.WritingEdition memory edition, address tokenRecipient, string memory message ) internal returns (address clone) { require( edition.fundingRecipient != address(0), "must specify recipient" ); // Assert limit is valid. If maxLimit is zero allow any limit. require( maxLimit == 0 || (edition.limit > 0 && edition.limit <= maxLimit), "invalid limit" ); clone = Clones.cloneDeterministic( implementation, keccak256( abi.encode(owner, edition.name, edition.symbol, edition.nonce) ) ); // Register clones _before_ initializing. address tributaryRegistry = _getTributaryRegistry(); if (tributaryRegistry != address(0)) { IObservability(o11y).emitTributarySet( // clone clone, // oldTributary address(0), // newTributary edition.fundingRecipient ); ITributaryRegistry(tributaryRegistry).setTributary( clone, edition.fundingRecipient ); } // Initialize clone. WritingEditions(clone).initialize{value: msg.value}( owner, edition, tokenRecipient, message, guardOn ); IObservability(o11y).emitDeploymentEvent(owner, clone); } function _getTributaryRegistry() internal returns (address) { return ITreasuryConfiguration(treasuryConfiguration).tributaryRegistry(); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.0; /// > [[[[[[[[[[[ Imports ]]]]]]]]]]] import "./interface/IWritingEditions.sol"; import "./interface/IWritingEditionsFactory.sol"; import "../observability/interface/IObservability.sol"; import "../fee-configuration/interface/IFeeConfiguration.sol"; import "../renderer/interface/IRenderer.sol"; import "../treasury/interface/ITreasuryConfiguration.sol"; import "../treasury/interface/ITreasury.sol"; import "../treasury/interface/ITributaryRegistry.sol"; import "../lib/Ownable.sol"; import "../lib/ERC721/ERC721.sol"; import "../lib/ERC165/ERC165.sol"; import "../lib/ERC721/interface/IERC721.sol"; import "../lib/ERC2981/interface/IERC2981.sol"; import "../lib/transaction-reentrancy-guard/TransactionReentrancyGuard.sol"; /// > [[[[[[[[[[[ External Library Imports ]]]]]]]]]]] import "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol"; import "openzeppelin-contracts/contracts/utils/Base64.sol"; import "openzeppelin-contracts/contracts/utils/Strings.sol"; /** * @title WritingEditions * @author MirrorXYZ * @custom:security-contact [email protected] */ contract WritingEditions is Ownable, TransactionReentrancyGuard, ReentrancyGuard, ERC721, IERC721Metadata, IERC2981, IWritingEditions, IWritingEditionEvents, IObservabilityEvents { /// > [[[[[[[[[[[ Version ]]]]]]]]]]] /// @notice Version. uint8 public immutable override VERSION = 200; /// > [[[[[[[[[[[ Authorization ]]]]]]]]]]] /// @notice Address that deploys and initializes clones. address public immutable override factory; /// > [[[[[[[[[[[ Configuration ]]]]]]]]]]] /// @notice Address for Mirror treasury configuration. address public immutable override treasuryConfiguration; /// @notice Address for Mirror's observability contract. address public immutable override o11y; /// > [[[[[[[[[[[ ERC721 Metadata ]]]]]]]]]]] /// @notice Token name. string public override name; /// @notice Token symbol. string public override symbol; /// @notice Base URI for description. string internal _baseDescriptionURI; /// > [[[[[[[[[[[ Token Data ]]]]]]]]]]] /// @notice Total supply of editions. Used to calculate next tokenId. uint256 public override totalSupply; /// @notice Token text content, stored in Arweave. string public override contentURI; /// @notice Token image content, stored in IPFS. string public override imageURI; /// @notice Token price, set by the owner. uint256 public override price; /// @notice Token limit, set by the owner. uint256 public override limit; /// @notice Account that will receive funds from sales. address public override fundingRecipient; /// > [[[[[[[[[[[ Royalty Info (ERC2981) ]]]]]]]]]]] /// @notice Account that will receive royalties. address public override royaltyRecipient; /// @notice Royalty basis points. uint256 public override royaltyBPS; /// > [[[[[[[[[[[ Rendering ]]]]]]]]]]] /// @notice Address for a rendering contract, if set, calls to /// `tokenURI(uint256)` are forwarded to this address. address public override renderer; /// > [[[[[[[[[[[ Constructor ]]]]]]]]]]] /// @notice Implementation logic for clones. /// @param _factory the factory contract deploying clones with this implementation. /// @param _treasuryConfiguration Mirror treasury configuration. /// @param _o11y contract for observability. constructor( address _factory, address _treasuryConfiguration, address _o11y ) Ownable(address(0)) TransactionReentrancyGuard(true) { // Assert not the zero-address. require(_factory != address(0), "must set factory"); // Store factory. factory = _factory; // Assert not the zero-address. require( _treasuryConfiguration != address(0), "must set treasury configuration" ); // Store treasury configuration. treasuryConfiguration = _treasuryConfiguration; // Assert not the zero-address. require(_o11y != address(0), "must set observability"); // Store observability. o11y = _o11y; } /// > [[[[[[[[[[[ Initializing ]]]]]]]]]]] /// @notice Initialize a clone by storing edition parameters. Called only /// by the factory. Mints the first edition to `tokenRecipient`. /// @param _owner owner of the clone. /// @param edition edition parameters used to deploy the clone. /// @param tokenRecipient account that will receive the first minted token. /// @param message message sent with the token purchase, not stored. function initialize( address _owner, WritingEdition memory edition, address tokenRecipient, string memory message, bool _guardOn ) external payable override nonReentrant { // Only factory can call this function. require(msg.sender == factory, "unauthorized caller"); // Store ERC721 metadata. name = edition.name; symbol = edition.symbol; // Store edition data. imageURI = edition.imageURI; contentURI = edition.contentURI; price = edition.price; limit = edition.limit; fundingRecipient = edition.fundingRecipient; renderer = edition.renderer; // Store owner. _setInitialOwner(_owner); // Store guard status. _setGuard(_guardOn); // Mint initial token to recipient if (tokenRecipient != address(0)) { _purchase(tokenRecipient, message); } } /// @notice Base description URI. function baseDescriptionURI() external view override returns (string memory) { return _getBaseDescriptionURI(); } /// @notice Token description. function description() public view override returns (string memory) { return string( abi.encodePacked( _getBaseDescriptionURI(), Strings.toString(block.chainid), "/", _addressToString(address(this)) ) ); } /// > [[[[[[[[[[[ View Functions ]]]]]]]]]]] /// @notice Helper function to get owners for a list of tokenIds. /// @dev Could revert if `tokenIds` is too long. /// @param tokenIds a list of token-ids to check ownership of. /// @return owners a list of token-id owners, address(0) if token is not minted function ownerOf( uint256[] memory tokenIds ) external view override returns (address[] memory owners) { owners = new address[](tokenIds.length); for (uint256 i = 0; i < tokenIds.length; i++) { owners[i] = _owners[tokenIds[i]]; } } /// > [[[[[[[[[[[ Funding Recipient ]]]]]]]]]]] /// @notice Set a new funding recipient. /// @param _fundingRecipient new funding recipient. function setFundingRecipient( address _fundingRecipient ) external override onlyOwner { // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitFundingRecipientSet( // oldFundingRecipient fundingRecipient, // newFundingRecipient _fundingRecipient ); fundingRecipient = _fundingRecipient; } /// > [[[[[[[[[[[ Price ]]]]]]]]]]] /// @notice Set a new price. /// @param _price new price. function setPrice(uint256 _price) external override onlyOwner { // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitPriceSet( // oldPrice price, // newPrice _price ); price = _price; } /// @notice Set a new base description URI. /// @param newBaseDescriptionURI new base description URI function setBaseDescriptionURI( string memory newBaseDescriptionURI ) external override onlyOwner { // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitBaseDescriptionURISet( // oldDescriptionURI _getBaseDescriptionURI(), // oldDescriptionURI newBaseDescriptionURI ); _baseDescriptionURI = newBaseDescriptionURI; } /// @notice Turn Transaction Level Reentrancy Guard on/off. function toggleGuard() external override onlyOwner { _toggleGuard(); } /// > [[[[[[[[[[[ Purchase ]]]]]]]]]]] /// @notice Purchase a token. /// @param tokenRecipient the account to receive the token. /// @param message an optional message during purchase, not stored. /// @return tokenId the id of the minted token. function purchase( address tokenRecipient, string memory message ) external payable override guard nonReentrant returns (uint256 tokenId) { return _purchase(tokenRecipient, message); } /// > [[[[[[[[[[[ Mint ]]]]]]]]]]] /// @notice Mint an edition /// @dev throws if called by a non-owner /// @param tokenRecipient the account to receive the edition function mint( address tokenRecipient ) external override onlyOwner returns (uint256 tokenId) { tokenId = _getTokenIdAndMint(tokenRecipient); } /// > [[[[[[[[[[[ Limit ]]]]]]]]]]] /// @notice Allows the owner to set a global limit on the total supply /// @dev throws if attempting to increase the limit /// @param newLimit new mint limit. function setLimit(uint256 newLimit) external override onlyOwner { // Enforce that the limit should only ever decrease once set. require( newLimit >= totalSupply && (limit == 0 || newLimit < limit), "limit must be < than current limit" ); // Announce the change in limit. // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitWritingEditionLimitSet( // oldLimit limit, // newLimit newLimit ); // Update the limit. limit = newLimit; } /// @notice Set the limit to the last minted tokenId. function setMaxLimit() external override onlyOwner { // Announce the change in limit. // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitWritingEditionLimitSet( // oldLimit limit, // newLimit totalSupply ); // Update the limit. limit = totalSupply; } /// > [[[[[[[[[[[ ERC2981 Methods ]]]]]]]]]]] /// @notice Called with the sale price to determine how much royalty // is owed and to whom /// @param _tokenId - the NFT asset queried for royalty information /// @param _salePrice - the sale price of the NFT asset specified by _tokenId /// @return receiver - address of who should be sent the royalty payment /// @return royaltyAmount - the royalty payment amount for _salePrice function royaltyInfo( uint256 _tokenId, uint256 _salePrice ) external view override returns (address receiver, uint256 royaltyAmount) { receiver = royaltyRecipient; royaltyAmount = (_salePrice * royaltyBPS) / 10_000; } /// @notice Get royalties information. /// @param royaltyRecipient_ the address that will receive royalties /// @param royaltyBPS_ the royalty amount in basis points (bps) function setRoyaltyInfo( address royaltyRecipient_, uint256 royaltyBPS_ ) external override onlyOwner { require( royaltyBPS_ <= 10_000, "bps must be less than or equal to 10,000" ); // slither-disable-next-line reentrancy-no-eth IObservability(o11y).emitRoyaltyChange( // oldRoyaltyRecipient royaltyRecipient, // oldRoyaltyBPS royaltyBPS, // newRoyaltyRecipient royaltyRecipient_, // newRoyaltyBPS royaltyBPS_ ); royaltyRecipient = royaltyRecipient_; royaltyBPS = royaltyBPS_; } /// > [[[[[[[[[[[ Rendering Methods ]]]]]]]]]]] /// @notice Set the renderer address /// @dev Throws if renderer is not the zero address /// @param _renderer contract responsible for rendering tokens. function setRenderer(address _renderer) external override onlyOwner { require(renderer == address(0), "renderer already set"); renderer = _renderer; IObservability(o11y).emitRendererSet( // renderer _renderer ); } /// @notice Get contract metadata /// @dev If a renderer is set, attempt return the renderer's metadata. function contractURI() external view override returns (string memory) { if (renderer != address(0)) { // slither-disable-next-line unused-return try IRenderer(renderer).contractURI() returns ( // slither-disable-next-line uninitialized-local string memory result ) { return result; } catch { // Fallback if the renderer does not implement contractURI return _generateContractURI(); } } return _generateContractURI(); } /// @notice Get `tokenId` URI or data /// @dev If a renderer is set, call renderer's tokenURI /// @param tokenId The tokenId used to request data function tokenURI( uint256 tokenId ) external view override returns (string memory) { require(_exists(tokenId), "ERC721: query for nonexistent token"); if (renderer != address(0)) { return IRenderer(renderer).tokenURI(tokenId); } // slither-disable-next-line uninitialized-local bytes memory editionNumber; if (limit != 0) { editionNumber = abi.encodePacked("/", Strings.toString(limit)); } string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "', _escapeQuotes(name), " ", Strings.toString(tokenId), editionNumber, '", "description": "', _escapeQuotes(description()), '", "content": "ar://', contentURI, '", "image": "ipfs://', imageURI, '", "attributes":[{ "trait_type": "Serial", "value": ', Strings.toString(tokenId), "}] }" ) ) ) ); return string(abi.encodePacked("data:application/json;base64,", json)); } /// > [[[[[[[[[[[ IERC165 Method ]]]]]]]]]]] /// @param interfaceId The interface identifier, as specified in ERC-165 function supportsInterface( bytes4 interfaceId ) public pure override returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || interfaceId == type(IERC165).interfaceId || interfaceId == type(IERC2981).interfaceId; } /// > [[[[[[[[[[[ Internal Functions ]]]]]]]]]]] function _generateContractURI() internal view returns (string memory) { string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "', _escapeQuotes(name), '", "description": "', _escapeQuotes(description()), '", "content": "ar://', contentURI, '", "image": "ipfs://', imageURI, '", "seller_fee_basis_points": ', Strings.toString(royaltyBPS), ', "fee_recipient": "', _addressToString(royaltyRecipient), '", "external_link": "', _getBaseDescriptionURI(), '"}' ) ) ) ); return string(abi.encodePacked("data:application/json;base64,", json)); } /// @dev Emit a transfer event from observability contract. function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override { IObservability(o11y).emitTransferEvent(from, to, tokenId); } function _purchase( address tokenRecipient, string memory message ) internal returns (uint256 tokenId) { // Mint token, and get a tokenId. tokenId = _getTokenIdAndMint(tokenRecipient); // Get fee. uint256 flatFeeAmount = 0; address feeConfiguration = _getFeeConfiguration(); if ( feeConfiguration != address(0) && IFeeConfiguration(feeConfiguration).flatFeeOn() ) { // Calculate the fee on the current balance flatFeeAmount = IFeeConfiguration(feeConfiguration).flatFeeAmount(); } // Emit event through observability contract. IObservability(o11y).emitWritingEditionPurchased( // tokenId tokenId, // recipient tokenRecipient, // price price, // message message, // flatFeeAmount flatFeeAmount ); _withdraw(fundingRecipient, msg.value, flatFeeAmount); } function _getFeeConfiguration() internal returns (address) { return ITreasuryConfiguration(treasuryConfiguration).feeConfiguration(); } function _getTributaryRegistry() internal returns (address) { return ITreasuryConfiguration(treasuryConfiguration).tributaryRegistry(); } /// @dev Withdraws `amount` to `fundsRecipient`. Sends fee to treasury // if fees are on. function _withdraw( address fundsRecipient, uint256 amount, uint256 flatFeeAmount ) internal { // If the fee is not zero, attempt to send it to the treasury. // If the treasury is not set, do not pay the fee. address treasury = ITreasuryConfiguration(treasuryConfiguration) .treasury(); if (flatFeeAmount != 0 && treasury != address(0)) { require(amount == price + flatFeeAmount, "invalid amount"); _sendEther(payable(treasury), flatFeeAmount); // Transfer the remaining amount to the recipient. _sendEther(payable(fundsRecipient), price); } else { require(amount == price, "invalid amount"); _sendEther(payable(fundsRecipient), amount); } } function _sendEther(address payable recipient, uint256 amount) internal { // Ensure sufficient balance. require(address(this).balance >= amount, "insufficient balance"); // Send the value. // slither-disable-next-line low-level-calls (bool success, ) = recipient.call{value: amount, gas: gasleft()}(""); require(success, "recipient reverted"); } /// @dev Mints and returns tokenId function _getTokenIdAndMint( address tokenRecipient ) internal returns (uint256 tokenId) { // Increment totalSupply to get next id and store tokenId. tokenId = ++totalSupply; // check that there are still tokens available to purchase // zero and max uint256 represent infinite minting require( limit == 0 || limit == type(uint256).max || tokenId < limit + 1, "sold out" ); // mint a new token for the tokenRecipient, using the `tokenId`. _mint(tokenRecipient, tokenId); } function _getBaseDescriptionURI() internal view returns (string memory) { return bytes(_baseDescriptionURI).length == 0 ? IWritingEditionsFactory(factory).baseDescriptionURI() : _baseDescriptionURI; } // https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447 function _addressToString(address x) internal pure returns (string memory) { bytes memory s = new bytes(40); for (uint256 i = 0; i < 20; i++) { bytes1 b = bytes1( uint8(uint256(uint160(x)) / (2 ** (8 * (19 - i)))) ); bytes1 hi = bytes1(uint8(b) / 16); bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi)); s[2 * i] = _char(hi); s[2 * i + 1] = _char(lo); } return string(abi.encodePacked("0x", s)); } function _char(bytes1 b) internal pure returns (bytes1 c) { if (uint8(b) < 10) return bytes1(uint8(b) + 0x30); else return bytes1(uint8(b) + 0x57); } function _escapeQuotes( string memory str ) internal pure returns (string memory) { bytes memory strBytes = bytes(str); uint8 quotesCount = 0; for (uint8 i = 0; i < strBytes.length; i++) { if (strBytes[i] == '"') { quotesCount++; } } if (quotesCount > 0) { bytes memory escapedBytes = new bytes( strBytes.length + (quotesCount) ); uint256 index; for (uint8 i = 0; i < strBytes.length; i++) { if (strBytes[i] == '"') { escapedBytes[index++] = "\\"; } escapedBytes[index++] = strBytes[i]; } return string(escapedBytes); } return str; } }
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
/// > [[[[[[[[[[[ Imports ]]]]]]]]]]]
import "./IWritingEditions.sol";
interface IWritingEditionsFactoryEvents {
event NewImplementation(
address indexed oldImplementation,
address indexed newImplementation
);
event EditionsDeployed(
address indexed owner,
address indexed clone,
address indexed implementation
);
}
interface IWritingEditionsFactory {
function VERSION() external view returns (uint8);
function implementation() external view returns (address);
function o11y() external view returns (address);
function treasuryConfiguration() external view returns (address);
function guardOn() external view returns (bool);
function salts(bytes32 salt) external view returns (bool);
function maxLimit() external view returns (uint256);
function DOMAIN_SEPARATOR() external returns (bytes32);
function CREATE_TYPEHASH() external returns (bytes32);
function baseDescriptionURI() external view returns (string memory);
function predictDeterministicAddress(
address implementation_,
bytes32 salt
) external view returns (address);
function getSalt(
address owner_,
IWritingEditions.WritingEdition memory edition_
) external view returns (bytes32);
function isValid(
address owner_,
bytes32 salt,
uint8 v,
bytes32 r,
bytes32 s
) external view returns (bool);
function setLimit(uint256 _maxLimit) external;
function setGuard(bool _guardOn) external;
function setImplementation(address _implementation) external;
function create(
IWritingEditions.WritingEdition memory edition_
) external returns (address clone);
function createWithSignature(
address owner_,
IWritingEditions.WritingEdition memory edition_,
uint8 v,
bytes32 r,
bytes32 s,
address recipient,
string memory message
) external payable returns (address clone);
function setTributary(address clone, address _tributary) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "./interface/IObservability.sol";
/**
* @title Observability
* @author MirrorXYZ
*/
contract Observability is IObservability, IObservabilityEvents {
/// > [[[[[[[[[[[ Factory functions ]]]]]]]]]]]
function emitDeploymentEvent(
address owner,
address clone
) external override {
emit CloneDeployed(msg.sender, owner, clone);
}
function emitTributarySet(
address clone,
address oldTributary,
address newTributary
) external override {
emit TributarySet(msg.sender, clone, oldTributary, newTributary);
}
function emitFactoryLimitSet(
uint256 oldLimit,
uint256 newLimit
) external override {
emit FactoryLimitSet(msg.sender, oldLimit, newLimit);
}
function emitFactoryGuardSet(bool guard) external override {
emit FactoryGuardSet(guard);
}
function emitFactoryImplementationSet(
address oldImplementation,
address newImplementation
) external override {
emit FactoryImplementationSet(
msg.sender,
oldImplementation,
newImplementation
);
}
/// > [[[[[[[[[[[ Clone functions ]]]]]]]]]]]
function emitWritingEditionPurchased(
uint256 tokenId,
address recipient,
uint256 price,
string memory message,
uint256 flatFeeAmount
) external override {
emit WritingEditionPurchased(
msg.sender,
tokenId,
recipient,
price,
message,
flatFeeAmount
);
}
function emitTransferEvent(
address from,
address to,
uint256 tokenId
) external override {
emit Transfer(msg.sender, from, to, tokenId);
}
function emitRoyaltyChange(
address oldRoyaltyRecipient,
uint256 oldRoyaltyBPS,
address newRoyaltyRecipient,
uint256 newRoyaltyBPS
) external override {
emit RoyaltyChange(
msg.sender,
oldRoyaltyRecipient,
oldRoyaltyBPS,
newRoyaltyRecipient,
newRoyaltyBPS
);
}
function emitRendererSet(address renderer) external override {
emit RendererSet(msg.sender, renderer);
}
function emitWritingEditionLimitSet(
uint256 oldLimit,
uint256 newLimit
) external override {
emit WritingEditionLimitSet(msg.sender, oldLimit, newLimit);
}
function emitPriceSet(
uint256 oldPrice,
uint256 newPrice
) external override {
emit PriceSet(msg.sender, oldPrice, newPrice);
}
function emitFundingRecipientSet(
address oldFundingRecipient,
address newFundingRecipient
) external override {
emit FundingRecipientSet(
msg.sender,
oldFundingRecipient,
newFundingRecipient
);
}
function emitBaseDescriptionURISet(
string memory oldBaseDescriptionURI,
string memory newBaseDescriptionURI
) external override {
emit BaseDescriptionURISet(
msg.sender,
oldBaseDescriptionURI,
newBaseDescriptionURI
);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
/// @dev Interafce for EIP-1271: Standard Signature Validation Method for Contracts.
interface IERC1271 {
/// @dev Should return whether the signature provided is valid for the provided hash
/// @param salt Hash of the data to be signed
/// @param signature Signature byte array associated with _hash
/// MUST return the bytes4 magic value 0x1626ba7e when function passes.
/// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
/// MUST allow external calls
function isValidSignature(bytes32 salt, bytes memory signature)
external
view
returns (bytes4 magicValue);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IOwnableEvents {
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
}
interface IOwnable {
function transferOwnership(address nextOwner_) external;
function cancelOwnershipTransfer() external;
function acceptOwnership() external;
function renounceOwnership() external;
function isOwner() external view returns (bool);
function isNextOwner() external view returns (bool);
}
contract Ownable is IOwnable, IOwnableEvents {
address public owner;
address private nextOwner;
/// > [[[[[[[[[[[ Modifiers ]]]]]]]]]]]
modifier onlyOwner() {
require(isOwner(), "caller is not the owner.");
_;
}
modifier onlyNextOwner() {
require(isNextOwner(), "current owner must set caller as next owner.");
_;
}
/// @notice Initialize contract by setting the initial owner.
constructor(address owner_) {
_setInitialOwner(owner_);
}
/// @notice Initiate ownership transfer by setting nextOwner.
function transferOwnership(address nextOwner_) external override onlyOwner {
require(nextOwner_ != address(0), "Next owner is the zero address.");
nextOwner = nextOwner_;
}
/// @notice Cancel ownership transfer by deleting nextOwner.
function cancelOwnershipTransfer() external override onlyOwner {
delete nextOwner;
}
/// @notice Accepts ownership transfer by setting owner.
function acceptOwnership() external override onlyNextOwner {
delete nextOwner;
owner = msg.sender;
emit OwnershipTransferred(owner, msg.sender);
}
/// @notice Renounce ownership by setting owner to zero address.
function renounceOwnership() external override onlyOwner {
_renounceOwnership();
}
/// @notice Returns true if the caller is the current owner.
function isOwner() public view override returns (bool) {
return msg.sender == owner;
}
/// @notice Returns true if the caller is the next owner.
function isNextOwner() public view override returns (bool) {
return msg.sender == nextOwner;
}
/// > [[[[[[[[[[[ Internal Functions ]]]]]]]]]]]
function _setOwner(address previousOwner, address newOwner) internal {
owner = newOwner;
emit OwnershipTransferred(previousOwner, owner);
}
function _setInitialOwner(address newOwner) internal {
owner = newOwner;
emit OwnershipTransferred(address(0), newOwner);
}
function _renounceOwnership() internal {
emit OwnershipTransferred(owner, address(0));
owner = address(0);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create2(0, ptr, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address implementation, bytes32 salt)
internal
view
returns (address predicted)
{
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IWritingEditionEvents {
event RoyaltyChange(
address indexed oldRoyaltyRecipient,
uint256 oldRoyaltyBPS,
address indexed newRoyaltyRecipient,
uint256 newRoyaltyBPS
);
event RendererSet(address indexed renderer);
event WritingEditionLimitSet(uint256 oldLimit, uint256 newLimit);
event PriceSet(uint256 price);
}
interface IWritingEditions {
struct WritingEdition {
string name;
string symbol;
string description;
string imageURI;
string contentURI;
uint256 price;
uint256 limit;
address fundingRecipient;
address renderer;
uint256 nonce;
}
function VERSION() external view returns (uint8);
function factory() external returns (address);
function treasuryConfiguration() external returns (address);
function o11y() external returns (address);
function baseDescriptionURI() external view returns (string memory);
function description() external view returns (string memory);
function totalSupply() external view returns (uint256);
function price() external view returns (uint256);
function limit() external view returns (uint256);
function contentURI() external view returns (string memory);
function imageURI() external view returns (string memory);
function fundingRecipient() external returns (address);
function royaltyRecipient() external returns (address);
function royaltyBPS() external returns (uint256);
function renderer() external view returns (address);
function ownerOf(
uint256[] memory tokenIds
) external view returns (address[] memory owners);
function initialize(
address owner_,
WritingEdition memory edition,
address recipient,
string memory message,
bool _guard
) external payable;
function setFundingRecipient(address fundingRecipient_) external;
function setPrice(uint256 price_) external;
function setBaseDescriptionURI(string memory _baseDescriptionURI) external;
function setLimit(uint256 limit_) external;
function setMaxLimit() external;
function setRoyaltyInfo(
address royaltyRecipient_,
uint256 royaltyPercentage_
) external;
function toggleGuard() external;
function purchase(
address tokenRecipient,
string memory message
) external payable returns (uint256 tokenId);
function mint(address tokenRecipient) external returns (uint256 tokenId);
function setRenderer(address renderer_) external;
function contractURI() external view returns (string memory);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IObservabilityEvents {
/// > [[[[[[[[[[[ Factory events ]]]]]]]]]]]
event CloneDeployed(
address indexed factory,
address indexed owner,
address indexed clone
);
event TributarySet(
address indexed factory,
address indexed clone,
address oldTributary,
address indexed newTributary
);
event FactoryLimitSet(
address indexed factory,
uint256 oldLimit,
uint256 newLimit
);
event FactoryGuardSet(bool guard);
event FactoryImplementationSet(
address indexed factory,
address indexed oldImplementation,
address indexed newImplementation
);
/// > [[[[[[[[[[[ Clone events ]]]]]]]]]]]
event WritingEditionPurchased(
address indexed clone,
uint256 tokenId,
address indexed recipient,
uint256 price,
string message,
uint256 flatFeeAmount
);
event Transfer(
address indexed clone,
address indexed from,
address indexed to,
uint256 tokenId
);
event RoyaltyChange(
address indexed clone,
address indexed oldRoyaltyRecipient,
uint256 oldRoyaltyBPS,
address indexed newRoyaltyRecipient,
uint256 newRoyaltyBPS
);
event RendererSet(address indexed clone, address indexed renderer);
event WritingEditionLimitSet(
address indexed clone,
uint256 oldLimit,
uint256 newLimit
);
event PriceSet(address indexed clone, uint256 oldLimit, uint256 newLimit);
event FundingRecipientSet(
address indexed clone,
address indexed oldFundingRecipient,
address indexed newFundingRecipient
);
event BaseDescriptionURISet(
address indexed clone,
string oldBaseDescriptionURI,
string newBaseDescriptionURI
);
}
interface IObservability {
function emitDeploymentEvent(address owner, address clone) external;
function emitTributarySet(
address clone,
address oldTributary,
address newTributary
) external;
function emitFactoryGuardSet(bool guard) external;
function emitFactoryImplementationSet(
address oldImplementation,
address newImplementation
) external;
function emitFactoryLimitSet(uint256 oldLimit, uint256 newLimit) external;
function emitTransferEvent(
address from,
address to,
uint256 tokenId
) external;
function emitWritingEditionPurchased(
uint256 tokenId,
address recipient,
uint256 price,
string memory message,
uint256 flatFeeAmount
) external;
function emitRoyaltyChange(
address oldRoyaltyRecipient,
uint256 oldRoyaltyBPS,
address newRoyaltyRecipient,
uint256 newRoyaltyBPS
) external;
function emitRendererSet(address renderer) external;
function emitWritingEditionLimitSet(
uint256 oldLimit,
uint256 newLimit
) external;
function emitFundingRecipientSet(
address oldFundingRecipient,
address newFundingRecipient
) external;
function emitPriceSet(uint256 oldPrice, uint256 newPrice) external;
function emitBaseDescriptionURISet(
string memory oldBaseDescriptionURI,
string memory newBaseDescriptionURI
) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IFeeConfigurationEvents {
event FeeSwitch(bool on);
event FlatFeeSwitch(bool on);
event MinimumFee(uint16 fee);
event MaximumFee(uint16 fee);
event FlatFeeAmount(uint256 fee);
}
interface IFeeConfiguration {
function on() external returns (bool);
function flatFeeOn() external returns (bool);
function flatFeeAmount() external returns (uint256);
function maximumFee() external returns (uint16);
function minimumFee() external returns (uint16);
function switchFee() external;
function setMinimumFee(uint16 newFee) external;
function setMaximumFee(uint16 newFe) external;
function valid(uint16 feeBPS) external view returns (bool);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IRenderer {
function tokenURI(uint256 tokenId) external view returns (string calldata);
function contractURI() external view returns (string calldata);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface ITreasuryConfigurationEvents {
event TreasurySet(address indexed treasury, address indexed newTreasury);
event TributaryRegistrySet(
address indexed tributaryRegistry,
address indexed newTributaryRegistry
);
event DistributionSet(
address indexed distribution,
address indexed newDistribution
);
event FeeConfigurationSet(
address indexed feeConfiguration,
address indexed newFeeConfiguration
);
}
interface ITreasuryConfiguration {
function treasury() external returns (address payable);
function tributaryRegistry() external returns (address);
function distribution() external returns (address);
function feeConfiguration() external returns (address);
function setTreasury(address payable newTreasury) external;
function setTributaryRegistry(address newTributaryRegistry) external;
function setDistribution(address newDistribution) external;
function setFeeConfiguration(address newFeeConfiguration) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface ITreasuryEvents {
event Transfer(address indexed from, address indexed to, uint256 value);
event ERC20Transfer(
address indexed token,
address indexed from,
address indexed to,
uint256 amount
);
event ERC721Transfer(
address indexed token,
address indexed from,
address indexed to,
uint256 tokenId
);
}
interface ITreasury {
struct Call {
// The target of the transaction.
address target;
// The value passed into the transaction.
uint96 value;
// Any data passed with the call.
bytes data;
}
function treasuryConfiguration() external view returns (address);
function transferFunds(address payable to, uint256 value) external;
function transferERC20(
address token,
address to,
uint256 value
) external;
function transferERC721(
address token,
address from,
address to,
uint256 tokenId
) external;
function contributeWithTributary(address tributary) external payable;
function contribute(uint256 amount) external payable;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface ITributaryRegistry {
function allowedRegistrar(address account) external view returns (bool);
function producerToTributary(address producer)
external
view
returns (address tributary);
function singletonProducer(address producer) external view returns (bool);
function addRegistrar(address registrar) external;
function removeRegistrar(address registrar) external;
function addSingletonProducer(address producer) external;
function removeSingletonProducer(address producer) external;
function setTributary(address producer, address newTributary) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "./interface/IERC721.sol";
import "../ERC165/ERC165.sol";
/**
* Based on: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol
*/
contract ERC721 is ERC165, IERC721, IERC721Events {
mapping(uint256 => address) internal _owners;
mapping(address => uint256) internal _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner)
external
view
virtual
override
returns (uint256)
{
require(
owner != address(0),
"ERC721: balance query for the zero address"
);
return _balances[owner];
}
function ownerOf(uint256 tokenId) external view virtual returns (address) {
return _ownerOf(tokenId);
}
function _ownerOf(uint256 tokenId) internal view returns (address) {
address owner = _owners[tokenId];
require(
owner != address(0),
"ERC721: owner query for nonexistent token"
);
return owner;
}
function approve(address to, uint256 tokenId) external virtual override {
address owner = _ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
msg.sender == owner || isApprovedForAll(owner, msg.sender),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId)
public
view
virtual
override
returns (address)
{
require(
_exists(tokenId),
"ERC721: approved query for nonexistent token"
);
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved)
external
virtual
override
{
require(operator != msg.sender, "ERC721: approve to caller");
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address owner, address operator)
public
view
virtual
override
returns (bool)
{
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) external virtual override {
//solhint-disable-next-line max-line-length
require(
_isApprovedOrOwner(msg.sender, tokenId),
"ERC721: transfer caller is not owner nor approved"
);
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external virtual override {
_safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) external virtual override {
_safeTransferFrom(from, to, tokenId, _data);
}
function _safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
require(
_isApprovedOrOwner(msg.sender, tokenId),
"ERC721: transfer caller is not owner nor approved"
);
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(
_checkOnERC721Received(from, to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId)
internal
view
virtual
returns (bool)
{
require(
_exists(tokenId),
"ERC721: operator query for nonexistent token"
);
address owner = _ownerOf(tokenId);
return (spender == owner ||
getApproved(tokenId) == spender ||
isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = _ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(
_ownerOf(tokenId) == from,
"ERC721: transfer of token that is not own"
);
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(_ownerOf(tokenId), to, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.code.length > 0) {
// slither-disable-next-line unused-return
try
IERC721Receiver(to).onERC721Received(
msg.sender,
from,
tokenId,
_data
)
returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert(
"ERC721: transfer to non ERC721Receiver implementer"
);
} else {
// solhint-disable-next-line no-inline-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IERC721 {
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId)
external
view
returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator)
external
view
returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
interface IERC721Events {
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Approval(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
}
interface IERC721Metadata {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
interface IERC721Burnable is IERC721 {
function burn(uint256 tokenId) external;
}
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
interface IERC721Royalties {
function getFeeRecipients(uint256 id)
external
view
returns (address payable[] memory);
function getFeeBps(uint256 id) external view returns (uint256[] memory);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
/**
* @title IERC2981
* @notice Interface for the NFT Royalty Standard
*/
interface IERC2981 {
// / bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
/**
* @notice Called with the sale price to determine how much royalty
* is owed and to whom.
* @param _tokenId - the NFT asset queried for royalty information
* @param _salePrice - the sale price of the NFT asset specified by _tokenId
* @return receiver - address of who should be sent the royalty payment
* @return royaltyAmount - the royalty payment amount for _salePrice
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
/**
* @title TransactionReentrancyGuard
* @notice Transaction level reentrancy guard, used to prevent calling a
* function multiple times in the same transaction, e.g. minting a token
* using a multicall contract. The guard accesses a storage variable twice
* and compares the gas used, taking advantage of EIP-2929 cold/warm storage
* read costs.
*
* From EIP-2929: Gas cost increases for state access opcodes:
* "For SLOAD, if the (address, storage_key) pair (where address
* is the address of the contract whose storage is being read) is not yet
* in accessed_storage_keys, charge COLD_SLOAD_COST gas and add the pair
* to accessed_storage_keys. If the pair is already in accessed_storage_keys,
* charge WARM_STORAGE_READ_COST gas."
*
* Implementation was forked from bertani.eth, after a thread involving these
* anon solidity giga-brains: [at]rage_pit, [at]transmissions11, 0age.eth.
*/
contract TransactionReentrancyGuard {
bool public guardOn;
uint256 internal GUARD = 1;
/// > [[[[[[[[[[[ Modifiers ]]]]]]]]]]]
modifier guard() {
// If guard is on, run guard.
if (guardOn) {
_guard();
}
_;
}
constructor(bool _guardOn) {
_setGuard(_guardOn);
}
function _guard() internal view {
// Store current gas left.
uint256 t0 = gasleft();
// Load GUARD from storage.
uint256 g = GUARD;
// Store current gas left.
uint256 t1 = gasleft();
// Load GUARD from storage.
uint256 m = GUARD;
// Assert the cost of acessing `g` is greater than the
// cost of accessing `m`, which implies the first SLOAD
// was charged COLD_SLOAD_COST and the second SLOAD was
// charged WARM_STORAGE_READ_COST. Hence this is the first
// time the function has been called.
require(t1 - gasleft() < t0 - t1);
}
function _toggleGuard() internal {
_setGuard(!guardOn);
}
function _setGuard(bool _guardOn) internal {
guardOn = _guardOn;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*
* _Available since v4.5._
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
string memory result = new string(4 * ((data.length + 2) / 3));
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 32)
// Run over the input, 3 bytes at a time
for {
let dataPtr := data
let endPtr := add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 bytes (18 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F which is the number of
// the previous character in the ASCII table prior to the Base64 Table
// The result is then added to the table to get the character to write,
// and finally write it in the result pointer but with a left shift
// of 256 (1 byte) - 8 (1 ASCII char) = 248 bits
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @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);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}{
"remappings": [
"@ds/=lib/multicall/lib/ds-test/src/",
"@std/=lib/multicall/lib/forge-std/src/",
"ds-test/=lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"multicall/=lib/multicall/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_treasuryConfiguration","type":"address"},{"internalType":"address","name":"_o11y","type":"address"},{"internalType":"uint256","name":"_maxLimit","type":"uint256"},{"internalType":"bool","name":"_guardOn","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":false,"internalType":"string","name":"oldBaseDescriptionURI","type":"string"},{"indexed":false,"internalType":"string","name":"newBaseDescriptionURI","type":"string"}],"name":"BaseDescriptionURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"factory","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"clone","type":"address"}],"name":"CloneDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"EditionsDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"guard","type":"bool"}],"name":"FactoryGuardSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"factory","type":"address"},{"indexed":true,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"FactoryImplementationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"factory","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"FactoryLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":true,"internalType":"address","name":"oldFundingRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newFundingRecipient","type":"address"}],"name":"FundingRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewImplementation","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":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"PriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":true,"internalType":"address","name":"renderer","type":"address"}],"name":"RendererSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":true,"internalType":"address","name":"oldRoyaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldRoyaltyBPS","type":"uint256"},{"indexed":true,"internalType":"address","name":"newRoyaltyRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"newRoyaltyBPS","type":"uint256"}],"name":"RoyaltyChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"factory","type":"address"},{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":false,"internalType":"address","name":"oldTributary","type":"address"},{"indexed":true,"internalType":"address","name":"newTributary","type":"address"}],"name":"TributarySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"WritingEditionLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"},{"indexed":false,"internalType":"uint256","name":"flatFeeAmount","type":"uint256"}],"name":"WritingEditionPurchased","type":"event"},{"inputs":[],"name":"CREATE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseDescriptionURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"imageURI","type":"string"},{"internalType":"string","name":"contentURI","type":"string"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"address","name":"fundingRecipient","type":"address"},{"internalType":"address","name":"renderer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IWritingEditions.WritingEdition","name":"edition","type":"tuple"}],"name":"create","outputs":[{"internalType":"address","name":"clone","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"imageURI","type":"string"},{"internalType":"string","name":"contentURI","type":"string"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"address","name":"fundingRecipient","type":"address"},{"internalType":"address","name":"renderer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IWritingEditions.WritingEdition","name":"edition","type":"tuple"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address","name":"tokenRecipient","type":"address"},{"internalType":"string","name":"message","type":"string"}],"name":"createWithSignature","outputs":[{"internalType":"address","name":"clone","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"imageURI","type":"string"},{"internalType":"string","name":"contentURI","type":"string"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"address","name":"fundingRecipient","type":"address"},{"internalType":"address","name":"renderer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IWritingEditions.WritingEdition","name":"edition","type":"tuple"}],"name":"getSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardOn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isNextOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"isValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"o11y","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_implementation","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"predictDeterministicAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"salts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_guardOn","type":"bool"}],"name":"setGuard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_implementation","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLimit","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"clone","type":"address"},{"internalType":"address","name":"_tributary","type":"address"}],"name":"setTributary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nextOwner_","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryConfiguration","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61010060405260026080523480156200001757600080fd5b506040516200687e3803806200687e8339810160408190526200003a91620002b4565b8462000046816200023e565b5060016002556001600160a01b038416620000a75760405162461bcd60e51b815260206004820152601860248201527f6d7573742073657420747265617375727920636f6e6669670000000000000000604482015260640160405180910390fd5b6001600160a01b03841660c05260408051808201825260018152603160f81b60209182015281517f2aef22f9d7df5f9d21c56d14029233f3fdaa91917727e1eb68e504d27072d6cd818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6818401524660608201523060808281018290528451808403909101815260a0909201938490528151919092012060e0529085908590620001549062000289565b6001600160a01b03938416815291831660208301529091166040820152606001604051809103906000f08015801562000191573d6000803e3d6000fd5b5060038054610100600160a81b0319166101006001600160a01b039384168102919091179182905585831660a08190526040516322fd9ed760e01b815260006004820152919092049092166024830152906322fd9ed790604401600060405180830381600087803b1580156200020657600080fd5b505af11580156200021b573d6000803e3d6000fd5b50506003805460ff19169315159390931790925550506005555062000323915050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350565b61446c806200241283390190565b80516001600160a01b0381168114620002af57600080fd5b919050565b600080600080600060a08688031215620002cd57600080fd5b620002d88662000297565b9450620002e86020870162000297565b9350620002f86040870162000297565b925060608601519150608086015180151581146200031557600080fd5b809150509295509295909350565b60805160a05160c05160e05161207d62000395600039600081816102c701526112df01526000818161048401526114c80152600081816103a60152818161064b0152818161090701528181610b5301528181610cf501528181610f7401526110cf01526000610548015261207d6000f3fe6080604052600436106101815760003560e01c8063705bf368116100d1578063a56600631161008a578063e6d283a611610064578063e6d283a6146104c6578063ed459df2146104f6578063f2fde38b14610516578063ffa1ad741461053657600080fd5b8063a566006314610452578063bee0ec0b14610472578063d784d426146104a657600080fd5b8063705bf36814610394578063715018a6146103c857806379ba5097146103dd5780638da5cb5b146103f25780638f32d59b14610412578063949da7921461043257600080fd5b806330b844541161013e5780633cb70c2d116101185780633cb70c2d146102e95780635c60da1b1461033557806364d44b1e1461035a5780636f19d0b61461037a57600080fd5b806330b8445414610282578063360d0fad146102955780633644e515146102b557600080fd5b8063089dc13b1461018657806311ba1741146101c35780631552a369146102055780631a861d261461023557806323452b9c1461024b57806327ea6f2b14610262575b600080fd5b34801561019257600080fd5b506101a66101a1366004611ad2565b61057c565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101cf57600080fd5b506101f77f49679996e28ae3d719dbc33eac28d7aebde3d77d1283ed79b042f8ad99e1fecc81565b6040519081526020016101ba565b34801561021157600080fd5b50610225610220366004611b20565b6105a0565b60405190151581526020016101ba565b34801561024157600080fd5b506101f760055481565b34801561025757600080fd5b506102606105bb565b005b34801561026e57600080fd5b5061026061027d366004611b70565b610600565b6101a6610290366004611b89565b6106b7565b3480156102a157600080fd5b506101a66102b0366004611c38565b6108b2565b3480156102c157600080fd5b506101f77f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f557600080fd5b506103286040518060400160405280601381526020017268747470733a2f2f6d6972726f722e78797a2f60681b81525081565b6040516101ba9190611cb4565b34801561034157600080fd5b506003546101a69061010090046001600160a01b031681565b34801561036657600080fd5b50610260610375366004611cc7565b6108c6565b34801561038657600080fd5b506003546102259060ff1681565b3480156103a057600080fd5b506101a67f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d457600080fd5b5061026061097f565b3480156103e957600080fd5b506102606109b3565b3480156103fe57600080fd5b506000546101a6906001600160a01b031681565b34801561041e57600080fd5b506000546001600160a01b03163314610225565b34801561043e57600080fd5b506101f761044d366004611ce9565b610a6a565b34801561045e57600080fd5b5061026061046d366004611d39565b610a76565b34801561047e57600080fd5b506101a67f000000000000000000000000000000000000000000000000000000000000000081565b3480156104b257600080fd5b506102606104c1366004611d72565b610c9b565b3480156104d257600080fd5b506102256104e1366004611b70565b60046020526000908152604090205460ff1681565b34801561050257600080fd5b506001546001600160a01b03163314610225565b34801561052257600080fd5b50610260610531366004611d72565b610d7a565b34801561054257600080fd5b5061056a7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101ba565b600061059a3383600060405180602001604052806000815250610e1c565b92915050565b60006105af8686868686611138565b90505b95945050505050565b6000546001600160a01b031633146105ee5760405162461bcd60e51b81526004016105e590611d8f565b60405180910390fd5b600180546001600160a01b0319169055565b6000546001600160a01b0316331461062a5760405162461bcd60e51b81526004016105e590611d8f565b600554604051639ea75f2760e01b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639ea75f2790604401600060405180830381600087803b15801561069757600080fd5b505af11580156106ab573d6000803e3d6000fd5b50505060059190915550565b60006106c1611281565b60006106cd89896112d8565b60008181526004602052604090205490915060ff161561080d57610740600360019054906101000a90046001600160a01b03168a8a600001518b602001518c61012001516040516020016107249493929190611dc6565b604051602081830303815290604052805190602001203061141c565b91506000826001600160a01b03163b116107945760405162461bcd60e51b8152602060048201526015602482015274696e76616c696420636c6f6e65206164647265737360581b60448201526064016105e5565b604051633a1b1d5760e01b81526001600160a01b03831690633a1b1d579034906107c49088908890600401611e0e565b60206040518083038185885af11580156107e2573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108079190611e32565b5061089c565b6000818152600460205260409020805460ff191660011790556108338982898989611138565b61088d5760405162461bcd60e51b815260206004820152602560248201527f696e76616c6964206f7220756e61626c6520746f20766572696679207369676e604482015264617475726560d81b60648201526084016105e5565b61089989898686610e1c565b91505b506108a76001600255565b979650505050505050565b60006108bf83833061141c565b9392505050565b6000546001600160a01b031633146108f05760405162461bcd60e51b81526004016105e590611d8f565b6040516302f848e760e11b815281151560048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906305f091ce90602401600060405180830381600087803b15801561095357600080fd5b505af1158015610967573d6000803e3d6000fd5b50506003805460ff1916931515939093179092555050565b6000546001600160a01b031633146109a95760405162461bcd60e51b81526004016105e590611d8f565b6109b161147a565b565b6001546001600160a01b03163314610a225760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201526b103732bc3a1037bbb732b91760a11b60648201526084016105e5565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b60006108bf83836112d8565b816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ab4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad89190611e4b565b6001600160a01b0316336001600160a01b031614610b275760405162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b60448201526064016105e5565b6000610b316114c4565b6040516352ba8c2b60e11b81526001600160a01b0385811660048301529192507f00000000000000000000000000000000000000000000000000000000000000008216916332c7791691869185169063a575185690602401602060405180830381865afa158015610ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bca9190611e4b565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015290821660248201529085166044820152606401600060405180830381600087803b158015610c1b57600080fd5b505af1158015610c2f573d6000803e3d6000fd5b505060405163a566006360e01b81526001600160a01b03868116600483015285811660248301528416925063a56600639150604401600060405180830381600087803b158015610c7e57600080fd5b505af1158015610c92573d6000803e3d6000fd5b50505050505050565b6000546001600160a01b03163314610cc55760405162461bcd60e51b81526004016105e590611d8f565b6003546040516322fd9ed760e01b81526101009091046001600160a01b03908116600483015282811660248301527f000000000000000000000000000000000000000000000000000000000000000016906322fd9ed790604401600060405180830381600087803b158015610d3957600080fd5b505af1158015610d4d573d6000803e3d6000fd5b5050600380546001600160a01b0390941661010002610100600160a81b0319909416939093179092555050565b6000546001600160a01b03163314610da45760405162461bcd60e51b81526004016105e590611d8f565b6001600160a01b038116610dfa5760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e0060448201526064016105e5565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60e08301516000906001600160a01b0316610e725760405162461bcd60e51b81526020600482015260166024820152751b5d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b60448201526064016105e5565b6005541580610e96575060008460c00151118015610e9657506005548460c0015111155b610ed25760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081b1a5b5a5d609a1b60448201526064016105e5565b6003548451602080870151610120880151604051610f249561010090046001600160a01b031694610f09948c949193919201611dc6565b6040516020818303038152906040528051906020012061154f565b90506000610f306114c4565b90506001600160a01b0381161561103c5760e0850151604051631963bc8b60e11b81526001600160a01b0384811660048301526000602483015291821660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906332c7791690606401600060405180830381600087803b158015610fba57600080fd5b505af1158015610fce573d6000803e3d6000fd5b5050505060e085015160405163a566006360e01b81526001600160a01b03848116600483015291821660248201529082169063a566006390604401600060405180830381600087803b15801561102357600080fd5b505af1158015611037573d6000803e3d6000fd5b505050505b600354604051630d09de2d60e41b81526001600160a01b0384169163d09de2d0913491611079918b918b918b918b9160ff90911690600401611e68565b6000604051808303818588803b15801561109257600080fd5b505af11580156110a6573d6000803e3d6000fd5b50506040516306e9fe9960e41b81526001600160a01b038a8116600483015286811660248301527f0000000000000000000000000000000000000000000000000000000000000000169350636e9fe99092506044019050600060405180830381600087803b15801561111757600080fd5b505af115801561112b573d6000803e3d6000fd5b5050505050949350505050565b60006001600160a01b0386166111825760405162461bcd60e51b815260206004820152600f60248201526e63616e6e6f742076616c696461746560881b60448201526064016105e5565b6001600160a01b0386163b1561125857604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b03881690631626ba7e906111f59089908590606501611f97565b602060405180830381865afa92505050801561122e575060408051601f3d908101601f1916820190925261122b91810190611fb0565b60015b61123c5760009150506105b2565b6001600160e01b031916630b135d3f60e11b1491506105b29050565b6000611266868686866115ef565b6001600160a01b039081169088161491505095945050505050565b60028054036112d25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105e5565b60028055565b60006108bf7f00000000000000000000000000000000000000000000000000000000000000007f49679996e28ae3d719dbc33eac28d7aebde3d77d1283ed79b042f8ad99e1fecc8585600001518660200151876060015188608001516040516020016113479493929190611fda565b604051602081830303815290604052805190602001208660c001518760a001518860e001518961010001518a61012001516040516020016113d09897969594939291909788526001600160a01b039687166020890152604088019590955260608701939093526080860191909152831660a085015290911660c083015260e08201526101000190565b60408051601f19818403018152828252805160209182012061190160f01b8483015260228401949094526042808401949094528151808403909401845260629092019052815191012090565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d6811b6f6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611526573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154a9190611e4b565b905090565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661059a5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c656400000000000000000060448201526064016105e5565b600080600061160087878787611617565b9150915061160d81611704565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561164e57506000905060036116fb565b8460ff16601b1415801561166657508460ff16601c14155b1561167757506000905060046116fb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156116cb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116f4576000600192509250506116fb565b9150600090505b94509492505050565b600081600481111561171857611718612031565b036117205750565b600181600481111561173457611734612031565b036117815760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105e5565b600281600481111561179557611795612031565b036117e25760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105e5565b60038160048111156117f6576117f6612031565b0361184e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105e5565b600481600481111561186257611862612031565b036118ba5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105e5565b50565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156118f7576118f76118bd565b60405290565b600082601f83011261190e57600080fd5b813567ffffffffffffffff80821115611929576119296118bd565b604051601f8301601f19908116603f01168101908282118183101715611951576119516118bd565b8160405283815286602085880101111561196a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6001600160a01b03811681146118ba57600080fd5b80356119aa8161198a565b919050565b600061014082840312156119c257600080fd5b6119ca6118d3565b9050813567ffffffffffffffff808211156119e457600080fd5b6119f0858386016118fd565b83526020840135915080821115611a0657600080fd5b611a12858386016118fd565b60208401526040840135915080821115611a2b57600080fd5b611a37858386016118fd565b60408401526060840135915080821115611a5057600080fd5b611a5c858386016118fd565b60608401526080840135915080821115611a7557600080fd5b50611a82848285016118fd565b60808301525060a082013560a082015260c082013560c0820152611aa860e0830161199f565b60e0820152610100611abb81840161199f565b818301525061012080830135818301525092915050565b600060208284031215611ae457600080fd5b813567ffffffffffffffff811115611afb57600080fd5b611b07848285016119af565b949350505050565b803560ff811681146119aa57600080fd5b600080600080600060a08688031215611b3857600080fd5b8535611b438161198a565b945060208601359350611b5860408701611b0f565b94979396509394606081013594506080013592915050565b600060208284031215611b8257600080fd5b5035919050565b600080600080600080600060e0888a031215611ba457600080fd5b8735611baf8161198a565b9650602088013567ffffffffffffffff80821115611bcc57600080fd5b611bd88b838c016119af565b9750611be660408b01611b0f565b965060608a0135955060808a0135945060a08a01359150611c068261198a565b90925060c08901359080821115611c1c57600080fd5b50611c298a828b016118fd565b91505092959891949750929550565b60008060408385031215611c4b57600080fd5b8235611c568161198a565b946020939093013593505050565b60005b83811015611c7f578181015183820152602001611c67565b50506000910152565b60008151808452611ca0816020860160208601611c64565b601f01601f19169290920160200192915050565b6020815260006108bf6020830184611c88565b600060208284031215611cd957600080fd5b813580151581146108bf57600080fd5b60008060408385031215611cfc57600080fd5b8235611d078161198a565b9150602083013567ffffffffffffffff811115611d2357600080fd5b611d2f858286016119af565b9150509250929050565b60008060408385031215611d4c57600080fd5b8235611d578161198a565b91506020830135611d678161198a565b809150509250929050565b600060208284031215611d8457600080fd5b81356108bf8161198a565b60208082526018908201527f63616c6c6572206973206e6f7420746865206f776e65722e0000000000000000604082015260600190565b6001600160a01b0385168152608060208201819052600090611dea90830186611c88565b8281036040840152611dfc8186611c88565b91505082606083015295945050505050565b6001600160a01b0383168152604060208201819052600090611b0790830184611c88565b600060208284031215611e4457600080fd5b5051919050565b600060208284031215611e5d57600080fd5b81516108bf8161198a565b60018060a01b038616815260a06020820152600085516101408060a0850152611e956101e0850183611c88565b91506020880151609f19808685030160c0870152611eb38483611c88565b935060408a01519150808685030160e0870152611ed08483611c88565b935060608a01519150610100818786030181880152611eef8584611c88565b945060808b01519250610120828887030181890152611f0e8685611c88565b955060a08c01518589015260c08c015161016089015260e08c01519450611f416101808901866001600160a01b03169052565b908b01516001600160a01b039081166101a0890152908b01516101c0880152891660408701525050508281036060840152611f7c8186611c88565b915050611f8d608083018415159052565b9695505050505050565b828152604060208201526000611b076040830184611c88565b600060208284031215611fc257600080fd5b81516001600160e01b0319811681146108bf57600080fd5b60008551611fec818460208a01611c64565b855190830190612000818360208a01611c64565b8551910190612013818360208901611c64565b8451910190612026818360208801611c64565b019695505050505050565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220efb303927abd81e930f0222dd93758055b0b004795461d5cd2535e81f987f49064736f6c63430008110033610100604052600160025560c86080523480156200001c57600080fd5b506040516200446c3803806200446c8339810160408190526200003f91620001f4565b600160006200004e816200018c565b506001805460ff60a01b1916600160a01b831515021790555060016003556001600160a01b038316620000bb5760405162461bcd60e51b815260206004820152601060248201526f6d7573742073657420666163746f727960801b60448201526064015b60405180910390fd5b6001600160a01b0380841660a0528216620001195760405162461bcd60e51b815260206004820152601f60248201527f6d7573742073657420747265617375727920636f6e66696775726174696f6e006044820152606401620000b2565b6001600160a01b0380831660c0528116620001775760405162461bcd60e51b815260206004820152601660248201527f6d75737420736574206f62736572766162696c697479000000000000000000006044820152606401620000b2565b6001600160a01b031660e052506200023e9050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350565b80516001600160a01b0381168114620001ef57600080fd5b919050565b6000806000606084860312156200020a57600080fd5b6200021584620001d7565b92506200022560208501620001d7565b91506200023560408501620001d7565b90509250925092565b60805160a05160c05160e051614199620002d3600039600081816105c901528181610c9901528181610dd90152818161107201528181611311015281816113b60152818161159d01528181611a5b015281816121580152612abc0152600081816107a801528181612b210152612ba70152600081816107dc01528181611868015261228e015260006108ed01526141996000f3fe6080604052600436106102c95760003560e01c80637284e41611610175578063b88d4fde116100dc578063d09de2d011610095578063e985e9c51161006f578063e985e9c51461087b578063ed459df21461089b578063f2fde38b146108bb578063ffa1ad74146108db57600080fd5b8063d09de2d014610833578063e2e784d514610846578063e8a3d4851461086657600080fd5b8063b88d4fde14610760578063b9c9d93a14610780578063bee0ec0b14610796578063c45a0155146107ca578063c7381da3146107fe578063c87b56dd1461081357600080fd5b806395d89b411161012e57806395d89b41146106ca5780639c1fd6e0146106df578063a035b1fe146106ff578063a22cb46514610715578063a4d66daf14610735578063a8d13a291461074b57600080fd5b80637284e4161461062057806379ba5097146106355780638ada6b0f1461064a5780638da5cb5b1461066a5780638f32d59b1461068a57806391b7f5ed146106aa57600080fd5b80633a1b1d571161023457806356d3163d116101ed5780636f19d0b6116101c75780636f19d0b614610596578063705bf368146105b757806370a08231146105eb578063715018a61461060b57600080fd5b806356d3163d146105365780636352211e146105565780636a6278421461057657600080fd5b80633a1b1d571461048c5780633cb70c2d1461049f57806342842e0e146104b457806347591135146104d45780634c00de82146105015780634dcd14b21461052157600080fd5b80631bb534ba116102865780631bb534ba146103b857806323452b9c146103d857806323b872dd146103ed578063241d96511461040d57806327ea6f2b1461042d5780632a55205a1461044d57600080fd5b806301ffc9a7146102ce57806306fdde0314610303578063081812fc14610325578063095ea7b31461035d578063135d088d1461037f57806318160ddd14610394575b600080fd5b3480156102da57600080fd5b506102ee6102e93660046130ac565b610921565b60405190151581526020015b60405180910390f35b34801561030f57600080fd5b5061031861098e565b6040516102fa9190613120565b34801561033157600080fd5b50610345610340366004613133565b610a1c565b6040516001600160a01b0390911681526020016102fa565b34801561036957600080fd5b5061037d61037836600461316c565b610ab6565b005b34801561038b57600080fd5b50610318610bcb565b3480156103a057600080fd5b506103aa600b5481565b6040519081526020016102fa565b3480156103c457600080fd5b50601054610345906001600160a01b031681565b3480156103e457600080fd5b5061037d610bd8565b3480156103f957600080fd5b5061037d610408366004613198565b610c14565b34801561041957600080fd5b5061037d6104283660046131d9565b610c45565b34801561043957600080fd5b5061037d610448366004613133565b610d1a565b34801561045957600080fd5b5061046d6104683660046131f6565b610e45565b604080516001600160a01b0390931683526020830191909152016102fa565b6103aa61049a36600461330c565b610e7b565b3480156104ab57600080fd5b50610318610eb6565b3480156104c057600080fd5b5061037d6104cf366004613198565b610ec5565b3480156104e057600080fd5b506104f46104ef36600461335b565b610ee0565b6040516102fa9190613400565b34801561050d57600080fd5b50601154610345906001600160a01b031681565b34801561052d57600080fd5b50610318610fb5565b34801561054257600080fd5b5061037d6105513660046131d9565b610fc2565b34801561056257600080fd5b50610345610571366004613133565b6110d3565b34801561058257600080fd5b506103aa6105913660046131d9565b6110de565b3480156105a257600080fd5b506001546102ee90600160a01b900460ff1681565b3480156105c357600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b3480156105f757600080fd5b506103aa6106063660046131d9565b611112565b34801561061757600080fd5b5061037d611199565b34801561062c57600080fd5b506103186111cd565b34801561064157600080fd5b5061037d61120f565b34801561065657600080fd5b50601354610345906001600160a01b031681565b34801561067657600080fd5b50600054610345906001600160a01b031681565b34801561069657600080fd5b506000546001600160a01b031633146102ee565b3480156106b657600080fd5b5061037d6106c5366004613133565b6112c6565b3480156106d657600080fd5b5061031861137d565b3480156106eb57600080fd5b5061037d6106fa36600461344d565b61138a565b34801561070b57600080fd5b506103aa600e5481565b34801561072157600080fd5b5061037d61073036600461349a565b61144e565b34801561074157600080fd5b506103aa600f5481565b34801561075757600080fd5b5061037d611512565b34801561076c57600080fd5b5061037d61077b3660046134d3565b611544565b34801561078c57600080fd5b506103aa60125481565b3480156107a257600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b3480156107d657600080fd5b506103457f000000000000000000000000000000000000000000000000000000000000000081565b34801561080a57600080fd5b5061037d611556565b34801561081f57600080fd5b5061031861082e366004613133565b611613565b61037d610841366004613552565b611855565b34801561085257600080fd5b5061037d61086136600461316c565b611992565b34801561087257600080fd5b50610318611adf565b34801561088757600080fd5b506102ee6108963660046136ea565b611b80565b3480156108a757600080fd5b506001546001600160a01b031633146102ee565b3480156108c757600080fd5b5061037d6108d63660046131d9565b611bae565b3480156108e757600080fd5b5061090f7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102fa565b60006001600160e01b031982166380ac58cd60e01b148061095257506001600160e01b03198216635b5e139f60e01b145b8061096d57506001600160e01b031982166301ffc9a760e01b145b8061098857506001600160e01b0319821663152a902d60e11b145b92915050565b6008805461099b90613718565b80601f01602080910402602001604051908101604052809291908181526020018280546109c790613718565b8015610a145780601f106109e957610100808354040283529160200191610a14565b820191906000526020600020905b8154815290600101906020018083116109f757829003601f168201915b505050505081565b6000818152600460205260408120546001600160a01b0316610a9a5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610ac182611c50565b9050806001600160a01b0316836001600160a01b031603610b2e5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610a91565b336001600160a01b0382161480610b4a5750610b4a8133611b80565b610bbc5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610a91565b610bc68383611cc7565b505050565b600d805461099b90613718565b6000546001600160a01b03163314610c025760405162461bcd60e51b8152600401610a919061374c565b600180546001600160a01b0319169055565b610c1e3382611d35565b610c3a5760405162461bcd60e51b8152600401610a9190613783565b610bc6838383611e0c565b6000546001600160a01b03163314610c6f5760405162461bcd60e51b8152600401610a919061374c565b60105460405163f0091f4f60e01b81526001600160a01b03918216600482015282821660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063f0091f4f90604401600060405180830381600087803b158015610cdf57600080fd5b505af1158015610cf3573d6000803e3d6000fd5b5050601080546001600160a01b0319166001600160a01b0394909416939093179092555050565b6000546001600160a01b03163314610d445760405162461bcd60e51b8152600401610a919061374c565b600b548110158015610d615750600f541580610d615750600f5481105b610db85760405162461bcd60e51b815260206004820152602260248201527f6c696d6974206d757374206265203c207468616e2063757272656e74206c696d6044820152611a5d60f21b6064820152608401610a91565b600f5460405163271c9e1f60e01b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063271c9e1f90604401600060405180830381600087803b158015610e2557600080fd5b505af1158015610e39573d6000803e3d6000fd5b505050600f9190915550565b6011546012546001600160a01b039091169060009061271090610e6890856137ea565b610e729190613817565b90509250929050565b600154600090600160a01b900460ff1615610e9857610e98611fb7565b610ea0611fe8565b610eaa8383612041565b90506109886001600355565b6060610ec06121e6565b905090565b610bc683838360405180602001604052806000815250612312565b606081516001600160401b03811115610efb57610efb613218565b604051908082528060200260200182016040528015610f24578160200160208202803683370190505b50905060005b8251811015610faf5760046000848381518110610f4957610f4961382b565b6020026020010151815260200190815260200160002060009054906101000a90046001600160a01b0316828281518110610f8557610f8561382b565b6001600160a01b039092166020928302919091019091015280610fa781613841565b915050610f2a565b50919050565b600c805461099b90613718565b6000546001600160a01b03163314610fec5760405162461bcd60e51b8152600401610a919061374c565b6013546001600160a01b03161561103c5760405162461bcd60e51b81526020600482015260146024820152731c995b99195c995c88185b1c9958591e481cd95d60621b6044820152606401610a91565b601380546001600160a01b0319166001600160a01b03838116918217909255604051631445778560e21b815260048101919091527f000000000000000000000000000000000000000000000000000000000000000090911690635115de1490602401600060405180830381600087803b1580156110b857600080fd5b505af11580156110cc573d6000803e3d6000fd5b5050505050565b600061098882611c50565b600080546001600160a01b031633146111095760405162461bcd60e51b8152600401610a919061374c565b61098882612344565b60006001600160a01b03821661117d5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610a91565b506001600160a01b031660009081526005602052604090205490565b6000546001600160a01b031633146111c35760405162461bcd60e51b8152600401610a919061374c565b6111cb6123c7565b565b60606111d76121e6565b6111e046612411565b6111e930612511565b6040516020016111fb93929190613876565b604051602081830303815290604052905090565b6001546001600160a01b0316331461127e5760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201526b103732bc3a1037bbb732b91760a11b6064820152608401610a91565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b6000546001600160a01b031633146112f05760405162461bcd60e51b8152600401610a919061374c565b600e5460405163509d812560e11b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a13b024a90604401600060405180830381600087803b15801561135d57600080fd5b505af1158015611371573d6000803e3d6000fd5b505050600e9190915550565b6009805461099b90613718565b6000546001600160a01b031633146113b45760405162461bcd60e51b8152600401610a919061374c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fc0ed66a6113eb6121e6565b836040518363ffffffff1660e01b81526004016114099291906138c6565b600060405180830381600087803b15801561142357600080fd5b505af1158015611437573d6000803e3d6000fd5b5050505080600a908161144a9190613942565b5050565b336001600160a01b038316036114a65760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610a91565b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6000546001600160a01b0316331461153c5760405162461bcd60e51b8152600401610a919061374c565b6111cb61267a565b61155084848484612312565b50505050565b6000546001600160a01b031633146115805760405162461bcd60e51b8152600401610a919061374c565b600f54600b5460405163271c9e1f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263271c9e1f926115d992600401918252602082015260400190565b600060405180830381600087803b1580156115f357600080fd5b505af1158015611607573d6000803e3d6000fd5b5050600b54600f555050565b6000818152600460205260409020546060906001600160a01b03166116865760405162461bcd60e51b815260206004820152602360248201527f4552433732313a20717565727920666f72206e6f6e6578697374656e7420746f60448201526235b2b760e91b6064820152608401610a91565b6013546001600160a01b0316156117085760135460405163c87b56dd60e01b8152600481018490526001600160a01b039091169063c87b56dd90602401600060405180830381865afa1580156116e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109889190810190613a01565b6060600f546000146117415761171f600f54612411565b60405160200161172f9190613a6e565b60405160208183030381529060405290505b600061182a6117d96008805461175690613718565b80601f016020809104026020016040519081016040528092919081815260200182805461178290613718565b80156117cf5780601f106117a4576101008083540402835291602001916117cf565b820191906000526020600020905b8154815290600101906020018083116117b257829003601f168201915b5050505050612691565b6117e286612411565b846117f36117ee6111cd565b612691565b600c600d6118008b612411565b6040516020016118169796959493929190613b0a565b604051602081830303815290604052612847565b90508060405160200161183d9190613c66565b60405160208183030381529060405292505050919050565b61185d611fe8565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118cb5760405162461bcd60e51b81526020600482015260136024820152723ab730baba3437b934bd32b21031b0b63632b960691b6044820152606401610a91565b83516008906118da9082613942565b5060208401516009906118ed9082613942565b506060840151600d906119009082613942565b506080840151600c906119139082613942565b5060a0840151600e5560c0840151600f5560e0840151601080546001600160a01b039283166001600160a01b0319918216179091556101008601516013805491909316911617905561196485612999565b61196d816129e4565b6001600160a01b03831615611988576119868383612041565b505b6110cc6001600355565b6000546001600160a01b031633146119bc5760405162461bcd60e51b8152600401610a919061374c565b612710811115611a1f5760405162461bcd60e51b815260206004820152602860248201527f627073206d757374206265206c657373207468616e206f7220657175616c207460448201526706f2031302c3030360c41b6064820152608401610a91565b601154601254604051630ba1ba8360e01b81526001600160a01b03928316600482015260248101919091528382166044820152606481018390527f000000000000000000000000000000000000000000000000000000000000000090911690630ba1ba8390608401600060405180830381600087803b158015611aa157600080fd5b505af1158015611ab5573d6000803e3d6000fd5b5050601180546001600160a01b0319166001600160a01b0395909516949094179093555060125550565b6013546060906001600160a01b031615611b7857601360009054906101000a90046001600160a01b03166001600160a01b031663e8a3d4856040518163ffffffff1660e01b8152600401600060405180830381865afa925050508015611b6757506040513d6000823e601f3d908101601f19168201604052611b649190810190613a01565b60015b611b7357610ec0612a02565b919050565b610ec0612a02565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6000546001600160a01b03163314611bd85760405162461bcd60e51b8152600401610a919061374c565b6001600160a01b038116611c2e5760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e006044820152606401610a91565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600460205260408120546001600160a01b0316806109885760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610a91565b600081815260066020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611cfc82611c50565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600460205260408120546001600160a01b0316611dae5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610a91565b6000611db983611c50565b9050806001600160a01b0316846001600160a01b03161480611df45750836001600160a01b0316611de984610a1c565b6001600160a01b0316145b80611e045750611e048185611b80565b949350505050565b826001600160a01b0316611e1f82611c50565b6001600160a01b031614611e875760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610a91565b6001600160a01b038216611ee95760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610a91565b611ef4838383612a8e565b611eff600082611cc7565b6001600160a01b0383166000908152600560205260408120805460019290611f28908490613cab565b90915550506001600160a01b0382166000908152600560205260408120805460019290611f56908490613cbe565b909155505060008181526004602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60005a60025490915060005a600254909150611fd38285613cab565b5a611fde9084613cab565b1061155057600080fd5b60026003540361203a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610a91565b6002600355565b600061204c83612344565b9050600080612059612b1d565b90506001600160a01b038116158015906120d25750806001600160a01b031663da8b5a566040518163ffffffff1660e01b81526004016020604051808303816000875af11580156120ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d29190613cd1565b1561213e57806001600160a01b031663ff0c44da6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213b9190613cee565b91505b600e5460405163ca9d19eb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163ca9d19eb916121949187918a91908a908990600401613d07565b600060405180830381600087803b1580156121ae57600080fd5b505af11580156121c2573d6000803e3d6000fd5b50506010546121de92506001600160a01b031690503484612ba3565b505092915050565b6060600a80546121f590613718565b15905061228c57600a805461220990613718565b80601f016020809104026020016040519081016040528092919081815260200182805461223590613718565b80156122825780601f1061225757610100808354040283529160200191612282565b820191906000526020600020905b81548152906001019060200180831161226557829003601f168201915b5050505050905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633cb70c2d6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156122ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ec09190810190613a01565b61231c3383611d35565b6123385760405162461bcd60e51b8152600401610a9190613783565b61155084848484612cfb565b6000600b6000815461235590613841565b9182905550600f54909150158061236f5750600019600f54145b806123865750600f54612383906001613cbe565b81105b6123bd5760405162461bcd60e51b81526020600482015260086024820152671cdbdb19081bdd5d60c21b6044820152606401610a91565b611b738282612d2e565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6060816000036124385750506040805180820190915260018152600360fc1b602082015290565b8160005b8115612462578061244c81613841565b915061245b9050600a83613817565b915061243c565b6000816001600160401b0381111561247c5761247c613218565b6040519080825280601f01601f1916602001820160405280156124a6576020820181803683370190505b5090505b8415611e04576124bb600183613cab565b91506124c8600a86613d46565b6124d3906030613cbe565b60f81b8183815181106124e8576124e861382b565b60200101906001600160f81b031916908160001a90535061250a600a86613817565b94506124aa565b60408051602880825260608281019093526000919060208201818036833701905050905060005b601481101561265157600061254e826013613cab565b6125599060086137ea565b612564906002613e3e565b612577906001600160a01b038716613817565b60f81b9050600060108260f81c61258e9190613e4a565b60f81b905060008160f81c60106125a59190613e6c565b8360f81c6125b39190613e8f565b60f81b90506125c182612e7c565b856125cd8660026137ea565b815181106125dd576125dd61382b565b60200101906001600160f81b031916908160001a9053506125fd81612e7c565b856126098660026137ea565b612614906001613cbe565b815181106126245761262461382b565b60200101906001600160f81b031916908160001a905350505050808061264990613841565b915050612538565b50806040516020016126639190613ea8565b604051602081830303815290604052915050919050565b6001546111cb90600160a01b900460ff16156129e4565b6060816000805b82518160ff1610156126f257828160ff16815181106126b9576126b961382b565b01602001516001600160f81b031916601160f91b036126e057816126dc81613ed2565b9250505b806126ea81613ed2565b915050612698565b5060ff81161561283f5760008160ff16835161270e9190613cbe565b6001600160401b0381111561272557612725613218565b6040519080825280601f01601f19166020018201604052801561274f576020820181803683370190505b5090506000805b84518160ff16101561283457848160ff16815181106127775761277761382b565b01602001516001600160f81b031916601160f91b036127ca57601760fa1b83836127a081613841565b9450815181106127b2576127b261382b565b60200101906001600160f81b031916908160001a9053505b848160ff16815181106127df576127df61382b565b01602001516001600160f81b03191683836127f981613841565b94508151811061280b5761280b61382b565b60200101906001600160f81b031916908160001a9053508061282c81613ed2565b915050612756565b509095945050505050565b509192915050565b6060815160000361286657505060408051602081019091526000815290565b600060405180606001604052806040815260200161412460409139905060006003845160026128959190613cbe565b61289f9190613817565b6128aa9060046137ea565b6001600160401b038111156128c1576128c1613218565b6040519080825280601f01601f1916602001820160405280156128eb576020820181803683370190505b509050600182016020820185865187015b80821015612957576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f81168501518453506001830192506128fc565b505060038651066001811461297357600281146129865761298e565b603d6001830353603d600283035361298e565b603d60018303535b509195945050505050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350565b60018054911515600160a01b0260ff60a01b19909216919091179055565b60606000612a66612a196008805461175690613718565b612a246117ee6111cd565b600c600d612a33601254612411565b601154612a48906001600160a01b0316612511565b612a506121e6565b6040516020016118169796959493929190613ef1565b905080604051602001612a799190613c66565b60405160208183030381529060405291505090565b60405163536a4ee560e11b81526001600160a01b0384811660048301528381166024830152604482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a6d49dca90606401600060405180830381600087803b158015612b0057600080fd5b505af1158015612b14573d6000803e3d6000fd5b50505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166398c47e8c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec09190614041565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612c05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c299190614041565b90508115801590612c4257506001600160a01b03811615155b15612caf5781600e54612c559190613cbe565b8314612c945760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b6044820152606401610a91565b612c9e8183612eb2565b612caa84600e54612eb2565b611550565b600e548314612cf15760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b6044820152606401610a91565b6115508484612eb2565b612d06848484611e0c565b612d1284848484612f92565b6115505760405162461bcd60e51b8152600401610a919061405e565b6001600160a01b038216612d845760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610a91565b6000818152600460205260409020546001600160a01b031615612de95760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610a91565b612df560008383612a8e565b6001600160a01b0382166000908152600560205260408120805460019290612e1e908490613cbe565b909155505060008181526004602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000600a60f883901c1015612ea357612e9a60f883901c60306140b0565b60f81b92915050565b612e9a60f883901c60576140b0565b80471015612ef95760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610a91565b6000826001600160a01b0316825a6040519091906000818181858888f193505050503d8060008114612f47576040519150601f19603f3d011682016040523d82523d6000602084013e612f4c565b606091505b5050905080610bc65760405162461bcd60e51b81526020600482015260126024820152711c9958da5c1a595b9d081c995d995c9d195960721b6044820152606401610a91565b60006001600160a01b0384163b1561308857604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612fd69033908990889088906004016140c9565b6020604051808303816000875af1925050508015613011575060408051601f3d908101601f1916820190925261300e91810190614106565b60015b61306e573d80801561303f576040519150601f19603f3d011682016040523d82523d6000602084013e613044565b606091505b5080516000036130665760405162461bcd60e51b8152600401610a919061405e565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611e04565b506001949350505050565b6001600160e01b0319811681146130a957600080fd5b50565b6000602082840312156130be57600080fd5b81356130c981613093565b9392505050565b60005b838110156130eb5781810151838201526020016130d3565b50506000910152565b6000815180845261310c8160208601602086016130d0565b601f01601f19169290920160200192915050565b6020815260006130c960208301846130f4565b60006020828403121561314557600080fd5b5035919050565b6001600160a01b03811681146130a957600080fd5b8035611b738161314c565b6000806040838503121561317f57600080fd5b823561318a8161314c565b946020939093013593505050565b6000806000606084860312156131ad57600080fd5b83356131b88161314c565b925060208401356131c88161314c565b929592945050506040919091013590565b6000602082840312156131eb57600080fd5b81356130c98161314c565b6000806040838503121561320957600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b038111828210171561325157613251613218565b60405290565b604051601f8201601f191681016001600160401b038111828210171561327f5761327f613218565b604052919050565b60006001600160401b038211156132a0576132a0613218565b50601f01601f191660200190565b60006132c16132bc84613287565b613257565b90508281528383830111156132d557600080fd5b828260208301376000602084830101529392505050565b600082601f8301126132fd57600080fd5b6130c9838335602085016132ae565b6000806040838503121561331f57600080fd5b823561332a8161314c565b915060208301356001600160401b0381111561334557600080fd5b613351858286016132ec565b9150509250929050565b6000602080838503121561336e57600080fd5b82356001600160401b038082111561338557600080fd5b818501915085601f83011261339957600080fd5b8135818111156133ab576133ab613218565b8060051b91506133bc848301613257565b81815291830184019184810190888411156133d657600080fd5b938501935b838510156133f4578435825293850193908501906133db565b98975050505050505050565b6020808252825182820181905260009190848201906040850190845b818110156134415783516001600160a01b03168352928401929184019160010161341c565b50909695505050505050565b60006020828403121561345f57600080fd5b81356001600160401b0381111561347557600080fd5b611e04848285016132ec565b80151581146130a957600080fd5b8035611b7381613481565b600080604083850312156134ad57600080fd5b82356134b88161314c565b915060208301356134c881613481565b809150509250929050565b600080600080608085870312156134e957600080fd5b84356134f48161314c565b935060208501356135048161314c565b92506040850135915060608501356001600160401b0381111561352657600080fd5b8501601f8101871361353757600080fd5b613546878235602084016132ae565b91505092959194509250565b600080600080600060a0868803121561356a57600080fd5b85356135758161314c565b945060208601356001600160401b038082111561359157600080fd5b90870190610140828a0312156135a657600080fd5b6135ae61322e565b8235828111156135bd57600080fd5b6135c98b8286016132ec565b8252506020830135828111156135de57600080fd5b6135ea8b8286016132ec565b60208301525060408301358281111561360257600080fd5b61360e8b8286016132ec565b60408301525060608301358281111561362657600080fd5b6136328b8286016132ec565b60608301525060808301358281111561364a57600080fd5b6136568b8286016132ec565b60808301525060a083013560a082015260c083013560c082015261367c60e08401613161565b60e082015261010061368f818501613161565b90820152610120838101359082015295506136ac60408901613161565b945060608801359150808211156136c257600080fd5b506136cf888289016132ec565b9250506136de6080870161348f565b90509295509295909350565b600080604083850312156136fd57600080fd5b82356137088161314c565b915060208301356134c88161314c565b600181811c9082168061372c57607f821691505b602082108103610faf57634e487b7160e01b600052602260045260246000fd5b60208082526018908201527f63616c6c6572206973206e6f7420746865206f776e65722e0000000000000000604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610988576109886137d4565b634e487b7160e01b600052601260045260246000fd5b60008261382657613826613801565b500490565b634e487b7160e01b600052603260045260246000fd5b600060018201613853576138536137d4565b5060010190565b6000815161386c8185602086016130d0565b9290920192915050565b600084516138888184602089016130d0565b84519083019061389c8183602089016130d0565b602f60f81b910190815283516138b98160018401602088016130d0565b0160010195945050505050565b6040815260006138d960408301856130f4565b82810360208401526138eb81856130f4565b95945050505050565b601f821115610bc657600081815260208120601f850160051c8101602086101561391b5750805b601f850160051c820191505b8181101561393a57828155600101613927565b505050505050565b81516001600160401b0381111561395b5761395b613218565b61396f816139698454613718565b846138f4565b602080601f8311600181146139a4576000841561398c5750858301515b600019600386901b1c1916600185901b17855561393a565b600085815260208120601f198616915b828110156139d3578886015182559484019460019091019084016139b4565b50858210156139f15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613a1357600080fd5b81516001600160401b03811115613a2957600080fd5b8201601f81018413613a3a57600080fd5b8051613a486132bc82613287565b818152856020838501011115613a5d57600080fd5b6138eb8260208301602086016130d0565b602f60f81b815260008251613a8a8160018501602087016130d0565b9190910160010192915050565b60008154613aa481613718565b60018281168015613abc5760018114613ad157613b00565b60ff1984168752821515830287019450613b00565b8560005260208060002060005b85811015613af75781548a820152908401908201613ade565b50505082870194505b5050505092915050565b693d913730b6b2911d101160b11b81528751600090613b3081600a850160208d016130d0565b600160fd1b600a918401918201528851613b5181600b840160208d016130d0565b8851910190613b6781600b840160208c016130d0565b72111610113232b9b1b934b83a34b7b7111d101160691b600b92909101918201528651613b9b81601e840160208b016130d0565b73222c2022636f6e74656e74223a202261723a2f2f60601b601e9290910191820152613bca6032820187613a97565b73222c2022696d616765223a2022697066733a2f2f60601b81529050613c58613c48613c42613bfc6014850189613a97565b7f222c202261747472696275746573223a5b7b202274726169745f74797065223a8152730101129b2b934b0b6111610113b30b63ab2911d160651b602082015260340190565b8661385a565b637d5d207d60e01b815260040190565b9a9950505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251613c9e81601d8501602087016130d0565b91909101601d0192915050565b81810381811115610988576109886137d4565b80820180821115610988576109886137d4565b600060208284031215613ce357600080fd5b81516130c981613481565b600060208284031215613d0057600080fd5b5051919050565b85815260018060a01b038516602082015283604082015260a060608201526000613d3460a08301856130f4565b90508260808301529695505050505050565b600082613d5557613d55613801565b500690565b600181815b80851115613d95578160001904821115613d7b57613d7b6137d4565b80851615613d8857918102915b93841c9390800290613d5f565b509250929050565b600082613dac57506001610988565b81613db957506000610988565b8160018114613dcf5760028114613dd957613df5565b6001915050610988565b60ff841115613dea57613dea6137d4565b50506001821b610988565b5060208310610133831016604e8410600b8410161715613e18575081810a610988565b613e228383613d5a565b8060001904821115613e3657613e366137d4565b029392505050565b60006130c98383613d9d565b600060ff831680613e5d57613e5d613801565b8060ff84160491505092915050565b60ff8181168382160290811690818114613e8857613e886137d4565b5092915050565b60ff8281168282160390811115610988576109886137d4565b61060f60f31b815260008251613ec58160028501602087016130d0565b9190910160020192915050565b600060ff821660ff8103613ee857613ee86137d4565b60010192915050565b693d913730b6b2911d101160b11b81528751600090613f1781600a850160208d016130d0565b72111610113232b9b1b934b83a34b7b7111d101160691b600a918401918201528851613f4a81601d840160208d016130d0565b73222c2022636f6e74656e74223a202261723a2f2f60601b601d9290910191820152613f796031820189613a97565b73222c2022696d616765223a2022697066733a2f2f60601b81529050613fa26014820188613a97565b90507f222c202273656c6c65725f6665655f62617369735f706f696e7473223a20000081528551613fda81601e840160208a016130d0565b731610113332b2afb932b1b4b834b2b73a111d101160611b601e9290910191820152613c58614033613c42614012603285018961385a565b741116101132bc3a32b93730b62fb634b735911d101160591b815260150190565b61227d60f01b815260020190565b60006020828403121561405357600080fd5b81516130c98161314c565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60ff8181168382160190811115610988576109886137d4565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906140fc908301846130f4565b9695505050505050565b60006020828403121561411857600080fd5b81516130c98161309356fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212200174dd34f8330e1cf22a1dcd8e36c6f82d8d20ff757e59313be324cd95b2432b64736f6c63430008110033000000000000000000000000ae6fdda940155d090e3a3de9b090ad6a392f761a000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde60000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec07200000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x6080604052600436106101815760003560e01c8063705bf368116100d1578063a56600631161008a578063e6d283a611610064578063e6d283a6146104c6578063ed459df2146104f6578063f2fde38b14610516578063ffa1ad741461053657600080fd5b8063a566006314610452578063bee0ec0b14610472578063d784d426146104a657600080fd5b8063705bf36814610394578063715018a6146103c857806379ba5097146103dd5780638da5cb5b146103f25780638f32d59b14610412578063949da7921461043257600080fd5b806330b844541161013e5780633cb70c2d116101185780633cb70c2d146102e95780635c60da1b1461033557806364d44b1e1461035a5780636f19d0b61461037a57600080fd5b806330b8445414610282578063360d0fad146102955780633644e515146102b557600080fd5b8063089dc13b1461018657806311ba1741146101c35780631552a369146102055780631a861d261461023557806323452b9c1461024b57806327ea6f2b14610262575b600080fd5b34801561019257600080fd5b506101a66101a1366004611ad2565b61057c565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101cf57600080fd5b506101f77f49679996e28ae3d719dbc33eac28d7aebde3d77d1283ed79b042f8ad99e1fecc81565b6040519081526020016101ba565b34801561021157600080fd5b50610225610220366004611b20565b6105a0565b60405190151581526020016101ba565b34801561024157600080fd5b506101f760055481565b34801561025757600080fd5b506102606105bb565b005b34801561026e57600080fd5b5061026061027d366004611b70565b610600565b6101a6610290366004611b89565b6106b7565b3480156102a157600080fd5b506101a66102b0366004611c38565b6108b2565b3480156102c157600080fd5b506101f77ffc8812d16d81e68c24359b3fd51d5169ab9eebe0cf94bdcea5b04b02d58358a981565b3480156102f557600080fd5b506103286040518060400160405280601381526020017268747470733a2f2f6d6972726f722e78797a2f60681b81525081565b6040516101ba9190611cb4565b34801561034157600080fd5b506003546101a69061010090046001600160a01b031681565b34801561036657600080fd5b50610260610375366004611cc7565b6108c6565b34801561038657600080fd5b506003546102259060ff1681565b3480156103a057600080fd5b506101a67f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec07281565b3480156103d457600080fd5b5061026061097f565b3480156103e957600080fd5b506102606109b3565b3480156103fe57600080fd5b506000546101a6906001600160a01b031681565b34801561041e57600080fd5b506000546001600160a01b03163314610225565b34801561043e57600080fd5b506101f761044d366004611ce9565b610a6a565b34801561045e57600080fd5b5061026061046d366004611d39565b610a76565b34801561047e57600080fd5b506101a67f000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde681565b3480156104b257600080fd5b506102606104c1366004611d72565b610c9b565b3480156104d257600080fd5b506102256104e1366004611b70565b60046020526000908152604090205460ff1681565b34801561050257600080fd5b506001546001600160a01b03163314610225565b34801561052257600080fd5b50610260610531366004611d72565b610d7a565b34801561054257600080fd5b5061056a7f000000000000000000000000000000000000000000000000000000000000000281565b60405160ff90911681526020016101ba565b600061059a3383600060405180602001604052806000815250610e1c565b92915050565b60006105af8686868686611138565b90505b95945050505050565b6000546001600160a01b031633146105ee5760405162461bcd60e51b81526004016105e590611d8f565b60405180910390fd5b600180546001600160a01b0319169055565b6000546001600160a01b0316331461062a5760405162461bcd60e51b81526004016105e590611d8f565b600554604051639ea75f2760e01b81526004810191909152602481018290527f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec0726001600160a01b031690639ea75f2790604401600060405180830381600087803b15801561069757600080fd5b505af11580156106ab573d6000803e3d6000fd5b50505060059190915550565b60006106c1611281565b60006106cd89896112d8565b60008181526004602052604090205490915060ff161561080d57610740600360019054906101000a90046001600160a01b03168a8a600001518b602001518c61012001516040516020016107249493929190611dc6565b604051602081830303815290604052805190602001203061141c565b91506000826001600160a01b03163b116107945760405162461bcd60e51b8152602060048201526015602482015274696e76616c696420636c6f6e65206164647265737360581b60448201526064016105e5565b604051633a1b1d5760e01b81526001600160a01b03831690633a1b1d579034906107c49088908890600401611e0e565b60206040518083038185885af11580156107e2573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906108079190611e32565b5061089c565b6000818152600460205260409020805460ff191660011790556108338982898989611138565b61088d5760405162461bcd60e51b815260206004820152602560248201527f696e76616c6964206f7220756e61626c6520746f20766572696679207369676e604482015264617475726560d81b60648201526084016105e5565b61089989898686610e1c565b91505b506108a76001600255565b979650505050505050565b60006108bf83833061141c565b9392505050565b6000546001600160a01b031633146108f05760405162461bcd60e51b81526004016105e590611d8f565b6040516302f848e760e11b815281151560048201527f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec0726001600160a01b0316906305f091ce90602401600060405180830381600087803b15801561095357600080fd5b505af1158015610967573d6000803e3d6000fd5b50506003805460ff1916931515939093179092555050565b6000546001600160a01b031633146109a95760405162461bcd60e51b81526004016105e590611d8f565b6109b161147a565b565b6001546001600160a01b03163314610a225760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201526b103732bc3a1037bbb732b91760a11b60648201526084016105e5565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b60006108bf83836112d8565b816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ab4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad89190611e4b565b6001600160a01b0316336001600160a01b031614610b275760405162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b60448201526064016105e5565b6000610b316114c4565b6040516352ba8c2b60e11b81526001600160a01b0385811660048301529192507f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec0728216916332c7791691869185169063a575185690602401602060405180830381865afa158015610ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bca9190611e4b565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015290821660248201529085166044820152606401600060405180830381600087803b158015610c1b57600080fd5b505af1158015610c2f573d6000803e3d6000fd5b505060405163a566006360e01b81526001600160a01b03868116600483015285811660248301528416925063a56600639150604401600060405180830381600087803b158015610c7e57600080fd5b505af1158015610c92573d6000803e3d6000fd5b50505050505050565b6000546001600160a01b03163314610cc55760405162461bcd60e51b81526004016105e590611d8f565b6003546040516322fd9ed760e01b81526101009091046001600160a01b03908116600483015282811660248301527f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec07216906322fd9ed790604401600060405180830381600087803b158015610d3957600080fd5b505af1158015610d4d573d6000803e3d6000fd5b5050600380546001600160a01b0390941661010002610100600160a81b0319909416939093179092555050565b6000546001600160a01b03163314610da45760405162461bcd60e51b81526004016105e590611d8f565b6001600160a01b038116610dfa5760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e0060448201526064016105e5565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60e08301516000906001600160a01b0316610e725760405162461bcd60e51b81526020600482015260166024820152751b5d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b60448201526064016105e5565b6005541580610e96575060008460c00151118015610e9657506005548460c0015111155b610ed25760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081b1a5b5a5d609a1b60448201526064016105e5565b6003548451602080870151610120880151604051610f249561010090046001600160a01b031694610f09948c949193919201611dc6565b6040516020818303038152906040528051906020012061154f565b90506000610f306114c4565b90506001600160a01b0381161561103c5760e0850151604051631963bc8b60e11b81526001600160a01b0384811660048301526000602483015291821660448201527f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec072909116906332c7791690606401600060405180830381600087803b158015610fba57600080fd5b505af1158015610fce573d6000803e3d6000fd5b5050505060e085015160405163a566006360e01b81526001600160a01b03848116600483015291821660248201529082169063a566006390604401600060405180830381600087803b15801561102357600080fd5b505af1158015611037573d6000803e3d6000fd5b505050505b600354604051630d09de2d60e41b81526001600160a01b0384169163d09de2d0913491611079918b918b918b918b9160ff90911690600401611e68565b6000604051808303818588803b15801561109257600080fd5b505af11580156110a6573d6000803e3d6000fd5b50506040516306e9fe9960e41b81526001600160a01b038a8116600483015286811660248301527f0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec072169350636e9fe99092506044019050600060405180830381600087803b15801561111757600080fd5b505af115801561112b573d6000803e3d6000fd5b5050505050949350505050565b60006001600160a01b0386166111825760405162461bcd60e51b815260206004820152600f60248201526e63616e6e6f742076616c696461746560881b60448201526064016105e5565b6001600160a01b0386163b1561125857604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b03881690631626ba7e906111f59089908590606501611f97565b602060405180830381865afa92505050801561122e575060408051601f3d908101601f1916820190925261122b91810190611fb0565b60015b61123c5760009150506105b2565b6001600160e01b031916630b135d3f60e11b1491506105b29050565b6000611266868686866115ef565b6001600160a01b039081169088161491505095945050505050565b60028054036112d25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105e5565b60028055565b60006108bf7ffc8812d16d81e68c24359b3fd51d5169ab9eebe0cf94bdcea5b04b02d58358a97f49679996e28ae3d719dbc33eac28d7aebde3d77d1283ed79b042f8ad99e1fecc8585600001518660200151876060015188608001516040516020016113479493929190611fda565b604051602081830303815290604052805190602001208660c001518760a001518860e001518961010001518a61012001516040516020016113d09897969594939291909788526001600160a01b039687166020890152604088019590955260608701939093526080860191909152831660a085015290911660c083015260e08201526101000190565b60408051601f19818403018152828252805160209182012061190160f01b8483015260228401949094526042808401949094528151808403909401845260629092019052815191012090565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60007f000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde66001600160a01b031663d6811b6f6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611526573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154a9190611e4b565b905090565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b03811661059a5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c656400000000000000000060448201526064016105e5565b600080600061160087878787611617565b9150915061160d81611704565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561164e57506000905060036116fb565b8460ff16601b1415801561166657508460ff16601c14155b1561167757506000905060046116fb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156116cb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116f4576000600192509250506116fb565b9150600090505b94509492505050565b600081600481111561171857611718612031565b036117205750565b600181600481111561173457611734612031565b036117815760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105e5565b600281600481111561179557611795612031565b036117e25760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105e5565b60038160048111156117f6576117f6612031565b0361184e5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105e5565b600481600481111561186257611862612031565b036118ba5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105e5565b50565b634e487b7160e01b600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156118f7576118f76118bd565b60405290565b600082601f83011261190e57600080fd5b813567ffffffffffffffff80821115611929576119296118bd565b604051601f8301601f19908116603f01168101908282118183101715611951576119516118bd565b8160405283815286602085880101111561196a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6001600160a01b03811681146118ba57600080fd5b80356119aa8161198a565b919050565b600061014082840312156119c257600080fd5b6119ca6118d3565b9050813567ffffffffffffffff808211156119e457600080fd5b6119f0858386016118fd565b83526020840135915080821115611a0657600080fd5b611a12858386016118fd565b60208401526040840135915080821115611a2b57600080fd5b611a37858386016118fd565b60408401526060840135915080821115611a5057600080fd5b611a5c858386016118fd565b60608401526080840135915080821115611a7557600080fd5b50611a82848285016118fd565b60808301525060a082013560a082015260c082013560c0820152611aa860e0830161199f565b60e0820152610100611abb81840161199f565b818301525061012080830135818301525092915050565b600060208284031215611ae457600080fd5b813567ffffffffffffffff811115611afb57600080fd5b611b07848285016119af565b949350505050565b803560ff811681146119aa57600080fd5b600080600080600060a08688031215611b3857600080fd5b8535611b438161198a565b945060208601359350611b5860408701611b0f565b94979396509394606081013594506080013592915050565b600060208284031215611b8257600080fd5b5035919050565b600080600080600080600060e0888a031215611ba457600080fd5b8735611baf8161198a565b9650602088013567ffffffffffffffff80821115611bcc57600080fd5b611bd88b838c016119af565b9750611be660408b01611b0f565b965060608a0135955060808a0135945060a08a01359150611c068261198a565b90925060c08901359080821115611c1c57600080fd5b50611c298a828b016118fd565b91505092959891949750929550565b60008060408385031215611c4b57600080fd5b8235611c568161198a565b946020939093013593505050565b60005b83811015611c7f578181015183820152602001611c67565b50506000910152565b60008151808452611ca0816020860160208601611c64565b601f01601f19169290920160200192915050565b6020815260006108bf6020830184611c88565b600060208284031215611cd957600080fd5b813580151581146108bf57600080fd5b60008060408385031215611cfc57600080fd5b8235611d078161198a565b9150602083013567ffffffffffffffff811115611d2357600080fd5b611d2f858286016119af565b9150509250929050565b60008060408385031215611d4c57600080fd5b8235611d578161198a565b91506020830135611d678161198a565b809150509250929050565b600060208284031215611d8457600080fd5b81356108bf8161198a565b60208082526018908201527f63616c6c6572206973206e6f7420746865206f776e65722e0000000000000000604082015260600190565b6001600160a01b0385168152608060208201819052600090611dea90830186611c88565b8281036040840152611dfc8186611c88565b91505082606083015295945050505050565b6001600160a01b0383168152604060208201819052600090611b0790830184611c88565b600060208284031215611e4457600080fd5b5051919050565b600060208284031215611e5d57600080fd5b81516108bf8161198a565b60018060a01b038616815260a06020820152600085516101408060a0850152611e956101e0850183611c88565b91506020880151609f19808685030160c0870152611eb38483611c88565b935060408a01519150808685030160e0870152611ed08483611c88565b935060608a01519150610100818786030181880152611eef8584611c88565b945060808b01519250610120828887030181890152611f0e8685611c88565b955060a08c01518589015260c08c015161016089015260e08c01519450611f416101808901866001600160a01b03169052565b908b01516001600160a01b039081166101a0890152908b01516101c0880152891660408701525050508281036060840152611f7c8186611c88565b915050611f8d608083018415159052565b9695505050505050565b828152604060208201526000611b076040830184611c88565b600060208284031215611fc257600080fd5b81516001600160e01b0319811681146108bf57600080fd5b60008551611fec818460208a01611c64565b855190830190612000818360208a01611c64565b8551910190612013818360208901611c64565b8451910190612026818360208801611c64565b019695505050505050565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220efb303927abd81e930f0222dd93758055b0b004795461d5cd2535e81f987f49064736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ae6fdda940155d090e3a3de9b090ad6a392f761a000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde60000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec07200000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _owner (address): 0xae6FdDA940155D090E3A3DE9b090aD6A392F761a
Arg [1] : _treasuryConfiguration (address): 0x004D8438f4016A96F2D6dDc17808F4e40b47cdE6
Arg [2] : _o11y (address): 0x3F2408693cc2E0C8E0bb68f039cEB6DEac0EC072
Arg [3] : _maxLimit (uint256): 10000
Arg [4] : _guardOn (bool): True
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000ae6fdda940155d090e3a3de9b090ad6a392f761a
Arg [1] : 000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde6
Arg [2] : 0000000000000000000000003f2408693cc2e0c8e0bb68f039ceb6deac0ec072
Arg [3] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Token Allocations
POL
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| POL | 100.00% | $0.123942 | 0.0015 | $0.000186 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.