Contract 0x302f746ee2fdc10ddff63188f71639094717a766 16
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
WritingEditionsFactory
Compiler Version
v0.8.12+commit.f00d7308
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 = 1; /// @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,uint16 fee)" ); /// @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 _maxLimit Max edition limit. /// @param _guardOn guard status. constructor( address _owner, address _treasuryConfiguration, 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) ) ); // Deploy and store Observability contract. o11y = address(new Observability()); // Deploy and store implementation contract. implementation = address( new WritingEditions(address(this), _treasuryConfiguration, o11y) ); // 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) { // Assert enough ETH was sent to purchase the token. require(msg.value == edition.price, "incorrect value"); // 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).purchaseThroughFactory{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); } /// > [[[[[[[[[[[ Purchase functions ]]]]]]]]]]] /// @notice Purchase a token through the factory. /// @param clone the WritingEdition address for the token to purchase. /// @param tokenRecipient account that will receive the first minted token. /// @param message message sent with the token purchase, not stored. function purchaseThroughFactory( address clone, address tokenRecipient, string memory message ) external payable override returns (uint256 tokenId) { return WritingEditions(clone).purchaseThroughFactory{value: msg.value}( tokenRecipient, message ); } /// > [[[[[[[[[[[ 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, edition.fee ) ) ); } /// @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 = 1; /// > [[[[[[[[[[[ 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; /// > [[[[[[[[[[[ Fees ]]]]]]]]]]] /// @notice Fee basis points paid if fees are on. uint16 public override fee; /// > [[[[[[[[[[[ 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 fee. _setFee(edition.fee); // Store owner. _setInitialOwner(_owner); // Mint initial token to recipient, assuming // the correct value was sent through the factory if (tokenRecipient != address(0)) { _purchase(tokenRecipient, message); } // Store guard status. _setGuard(_guardOn); } /// @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) { // Ensure enough value is sent. require(msg.value == price, "incorrect value"); return _purchase(tokenRecipient, message); } /// @notice Purchase a token through the factory. Assumes balance checks /// were made in the factory. /// @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 purchaseThroughFactory( address tokenRecipient, string memory message ) external payable override nonReentrant returns (uint256 tokenId) { // Ensure only factory calls. require(msg.sender == factory, "unauthorized"); tokenId = _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 payable 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": "', name, " ", Strings.toString(tokenId), editionNumber, '", "description": "', string(description()), '", "content": "ar://', string(contentURI), '", "image": "ipfs://', string(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": "', name, '", "description": "', string(description()), '", "content": "ar://', string(contentURI), '", "image": "ipfs://', string(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 _royaltyRecipient() internal view returns (address) { return royaltyRecipient == address(0) ? fundingRecipient : royaltyRecipient; } /// @dev The ternary expression below prevents from returning 0 as the /// royalty amount. To turn off royalties, we make the assumption that /// if the royaltyRecipient is set to address(0), the marketplace code /// will ignore the royalty amount. function _royaltyBPS() internal view returns (uint256) { return royaltyBPS == 0 ? 1000 : royaltyBPS; } function _purchase(address tokenRecipient, string memory message) internal returns (uint256 tokenId) { // Mint token, and get a tokenId. tokenId = _getTokenIdAndMint(tokenRecipient); // Emit event through observability contract. IObservability(o11y).emitWritingEditionPurchased( // tokenId tokenId, // recipient tokenRecipient, // price price, // message message ); _withdraw(fundingRecipient, msg.value); } 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) internal { address feeConfiguration = _getFeeConfiguration(); if ( feeConfiguration != address(0) && IFeeConfiguration(feeConfiguration).on() ) { // Calculate the fee on the current balance, using the fee percentage. uint256 feeAmount = _feeAmount(amount, fee); // 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 (feeAmount != 0 && treasury != address(0)) { _sendEther(payable(treasury), feeAmount); // Transfer the remaining amount to the recipient. _sendEther(payable(fundsRecipient), amount - feeAmount); } else { _sendEther(payable(fundsRecipient), amount); } } else { _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"); } function _feeAmount(uint256 amount, uint16 fee_) internal pure returns (uint256) { if (amount >= 10_000) { // Ignore warning since we check amount >= divisor // Hence no loss of precision. // slither-disable-next-line divide-before-multiply return (amount / 10_000) * fee_; } return 0; } /// @dev If fee is invalid, default to minimum fee. function _setFee(uint16 newFee) internal { address feeConfiguration = _getFeeConfiguration(); fee = IFeeConfiguration(feeConfiguration).valid(newFee) ? newFee : IFeeConfiguration(feeConfiguration).minimumFee(); } /// @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); } }
// 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; function purchaseThroughFactory( address clone, address tokenRecipient, string memory message ) external payable returns (uint256 tokenId); }
// 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 ) external override { emit WritingEditionPurchased( msg.sender, tokenId, recipient, price, message ); } 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 v4.4.1 (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) { assembly { let ptr := mload(0x40) mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) mstore(add(ptr, 0x13), shl(0x60, implementation)) mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x36) } 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) { assembly { let ptr := mload(0x40) mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) mstore(add(ptr, 0x13), shl(0x60, implementation)) mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x36, 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) { assembly { let ptr := mload(0x40) mstore(ptr, 0x602d8060093d393df3363d3d373d3d3d363d7300000000000000000000000000) mstore(add(ptr, 0x13), shl(0x60, implementation)) mstore(add(ptr, 0x27), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x37), shl(0x60, deployer)) mstore(add(ptr, 0x4b), salt) mstore(add(ptr, 0x6b), keccak256(ptr, 0x36)) predicted := keccak256(add(ptr, 0x36), 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.5.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() { // 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; _; // 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; uint16 fee; } 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 fee() external returns (uint16); 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 payable royaltyRecipient_, uint256 royaltyPercentage_ ) external; function toggleGuard() external; function purchase(address tokenRecipient, string memory message) external payable returns (uint256 tokenId); function purchaseThroughFactory( 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 ); 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 ) 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 MinimumFee(uint16 fee); event MaximumFee(uint16 fee); } interface IFeeConfiguration { function on() external returns (bool); function maximumFee() external returns (uint16); function minimumFee() external returns (uint16); function switchFee() external; function updateMinimumFee(uint16 newFee) external; function updateMaximumFee(uint16 newFe) external; function valid(uint16) 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.5.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)); 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 v4.4.1 (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/", "src/=src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london" }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_treasuryConfiguration","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"}],"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":"uint16","name":"fee","type":"uint16"}],"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":"uint16","name":"fee","type":"uint16"}],"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":"uint16","name":"fee","type":"uint16"}],"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":[{"internalType":"address","name":"clone","type":"address"},{"internalType":"address","name":"tokenRecipient","type":"address"},{"internalType":"string","name":"message","type":"string"}],"name":"purchaseThroughFactory","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","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
61010060405260016080523480156200001757600080fd5b50604051620072da380380620072da8339810160408190526200003a916200028b565b83620000468162000207565b5060016002556001600160a01b038316620000a75760405162461bcd60e51b815260206004820152601860248201527f6d7573742073657420747265617375727920636f6e6669670000000000000000604482015260640160405180910390fd5b6001600160a01b03831660c05260408051808201825260018152603160f81b60209182015281517f2aef22f9d7df5f9d21c56d14029233f3fdaa91917727e1eb68e504d27072d6cd818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc681840152466060820152306080828101919091528351808303909101815260a090910192839052805191012060e0526200014e9062000252565b604051809103906000f0801580156200016b573d6000803e3d6000fd5b506001600160a01b031660a0819052604051309185916200018c9062000260565b6001600160a01b03938416815291831660208301529091166040820152606001604051809103906000f080158015620001c9573d6000803e3d6000fd5b506003805492151560ff196001600160a01b039390931661010002929092166001600160a81b03199093169290921717905560055550620002e59050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350565b6108f8806200257783390190565b61446b8062002e6f83390190565b80516001600160a01b03811681146200028657600080fd5b919050565b60008060008060808587031215620002a257600080fd5b620002ad856200026e565b9350620002bd602086016200026e565b92506040850151915060608501518015158114620002da57600080fd5b939692955090935050565b60805160a05160c05160e05161222062000357600039600081816102af01526114ee0152600081816104b201526114600152600081816103ae01528181610655015281816107360152818161097601528181610e290152818161124e01526113a90152600061057601526122206000f3fe60806040526004361061019c5760003560e01c8063715018a6116100ec578063ad768cb31161008a578063e6d283a611610064578063e6d283a6146104f4578063ed459df214610524578063f2fde38b14610544578063ffa1ad741461056457600080fd5b8063ad768cb31461048d578063bee0ec0b146104a0578063d784d426146104d457600080fd5b80638f32d59b116100c65780638f32d59b1461041a578063a56600631461043a578063a61788f31461045a578063ad3c6b611461047a57600080fd5b8063715018a6146103d057806379ba5097146103e55780638da5cb5b146103fa57600080fd5b80633644e515116101595780635c60da1b116101335780635c60da1b1461033d57806364d44b1e146103625780636f19d0b614610382578063705bf3681461039c57600080fd5b80633644e5151461029d5780633cb70c2d146102d15780635a5df2b71461031d57600080fd5b806311ba1741146101a15780631552a369146101e85780631a861d261461021857806323452b9c1461022e57806327ea6f2b14610245578063360d0fad14610265575b600080fd5b3480156101ad57600080fd5b506101d57f682b3920f0bf70eb759a59b34e1c6ff903edb5ced39efd66303d66cc0eac774e81565b6040519081526020015b60405180910390f35b3480156101f457600080fd5b506102086102033660046119e7565b6105aa565b60405190151581526020016101df565b34801561022457600080fd5b506101d560055481565b34801561023a57600080fd5b506102436105c5565b005b34801561025157600080fd5b50610243610260366004611a37565b61060a565b34801561027157600080fd5b50610285610280366004611a50565b6106c1565b6040516001600160a01b0390911681526020016101df565b3480156102a957600080fd5b506101d57f000000000000000000000000000000000000000000000000000000000000000081565b3480156102dd57600080fd5b506103106040518060400160405280601381526020017268747470733a2f2f6d6972726f722e78797a2f60681b81525081565b6040516101df9190611ad8565b34801561032957600080fd5b50610285610338366004611cfd565b6106d7565b34801561034957600080fd5b506003546102859061010090046001600160a01b031681565b34801561036e57600080fd5b5061024361037d366004611d32565b6106f5565b34801561038e57600080fd5b506003546102089060ff1681565b3480156103a857600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b3480156103dc57600080fd5b506102436107ae565b3480156103f157600080fd5b506102436107e2565b34801561040657600080fd5b50600054610285906001600160a01b031681565b34801561042657600080fd5b506000546001600160a01b03163314610208565b34801561044657600080fd5b50610243610455366004611d5b565b610899565b34801561046657600080fd5b506101d5610475366004611d94565b610abe565b610285610488366004611de4565b610aca565b6101d561049b366004611e93565b610d53565b3480156104ac57600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e057600080fd5b506102436104ef366004611ef5565b610dcf565b34801561050057600080fd5b5061020861050f366004611a37565b60046020526000908152604090205460ff1681565b34801561053057600080fd5b506001546001600160a01b03163314610208565b34801561055057600080fd5b5061024361055f366004611ef5565b610eae565b34801561057057600080fd5b506105987f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101df565b60006105b98686868686610f50565b90505b95945050505050565b6000546001600160a01b031633146105f85760405162461bcd60e51b81526004016105ef90611f12565b60405180910390fd5b600180546001600160a01b0319169055565b6000546001600160a01b031633146106345760405162461bcd60e51b81526004016105ef90611f12565b600554604051639ea75f2760e01b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639ea75f2790604401600060405180830381600087803b1580156106a157600080fd5b505af11580156106b5573d6000803e3d6000fd5b50505060059190915550565b60006106ce838330611099565b90505b92915050565b60006106d133836000604051806020016040528060008152506110f6565b6000546001600160a01b0316331461071f5760405162461bcd60e51b81526004016105ef90611f12565b6040516302f848e760e11b815281151560048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906305f091ce90602401600060405180830381600087803b15801561078257600080fd5b505af1158015610796573d6000803e3d6000fd5b50506003805460ff1916931515939093179092555050565b6000546001600160a01b031633146107d85760405162461bcd60e51b81526004016105ef90611f12565b6107e0611412565b565b6001546001600160a01b031633146108515760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201526b103732bc3a1037bbb732b91760a11b60648201526084016105ef565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fb9190611f49565b6001600160a01b0316336001600160a01b03161461094a5760405162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b60448201526064016105ef565b600061095461145c565b6040516352ba8c2b60e11b81526001600160a01b0385811660048301529192507f00000000000000000000000000000000000000000000000000000000000000008216916332c7791691869185169063a575185690602401602060405180830381865afa1580156109c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ed9190611f49565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015290821660248201529085166044820152606401600060405180830381600087803b158015610a3e57600080fd5b505af1158015610a52573d6000803e3d6000fd5b505060405163a566006360e01b81526001600160a01b03868116600483015285811660248301528416925063a56600639150604401600060405180830381600087803b158015610aa157600080fd5b505af1158015610ab5573d6000803e3d6000fd5b50505050505050565b60006106ce83836114e7565b6000600280541415610b1e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105ef565b6002805560a08701513414610b675760405162461bcd60e51b815260206004820152600f60248201526e696e636f72726563742076616c756560881b60448201526064016105ef565b6000610b7389896114e7565b60008181526004602052604090205490915060ff1615610cb357610be6600360019054906101000a90046001600160a01b03168a8a600001518b602001518c6101200151604051602001610bca9493929190611f66565b6040516020818303038152906040528051906020012030611099565b91506000826001600160a01b03163b11610c3a5760405162461bcd60e51b8152602060048201526015602482015274696e76616c696420636c6f6e65206164647265737360581b60448201526064016105ef565b6040516333f0ff8b60e21b81526001600160a01b0383169063cfc3fe2c903490610c6a9088908890600401611fae565b60206040518083038185885af1158015610c88573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cad9190611fd2565b50610d42565b6000818152600460205260409020805460ff19166001179055610cd98982898989610f50565b610d335760405162461bcd60e51b815260206004820152602560248201527f696e76616c6964206f7220756e61626c6520746f20766572696679207369676e604482015264617475726560d81b60648201526084016105ef565b610d3f898986866110f6565b91505b506001600255979650505050505050565b6000836001600160a01b031663cfc3fe2c3485856040518463ffffffff1660e01b8152600401610d84929190611fae565b60206040518083038185885af1158015610da2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610dc79190611fd2565b949350505050565b6000546001600160a01b03163314610df95760405162461bcd60e51b81526004016105ef90611f12565b6003546040516322fd9ed760e01b81526101009091046001600160a01b03908116600483015282811660248301527f000000000000000000000000000000000000000000000000000000000000000016906322fd9ed790604401600060405180830381600087803b158015610e6d57600080fd5b505af1158015610e81573d6000803e3d6000fd5b5050600380546001600160a01b0390941661010002610100600160a81b0319909416939093179092555050565b6000546001600160a01b03163314610ed85760405162461bcd60e51b81526004016105ef90611f12565b6001600160a01b038116610f2e5760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e0060448201526064016105ef565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038616610f9a5760405162461bcd60e51b815260206004820152600f60248201526e63616e6e6f742076616c696461746560881b60448201526064016105ef565b6001600160a01b0386163b1561107057604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b03881690631626ba7e9061100d9089908590606501611feb565b602060405180830381865afa925050508015611046575060408051601f3d908101601f1916820190925261104391810190612004565b60015b6110545760009150506105bc565b6001600160e01b031916630b135d3f60e11b1491506105bc9050565b600061107e8686868661163f565b6001600160a01b039081169088161491505095945050505050565b60405172602d8060093d393df3363d3d373d3d3d363d7360681b8152606093841b60138201526f5af43d82803e903d91602b57fd5bf3ff60801b6027820152921b6037830152604b8201526036808220606b830152605591012090565b60e08301516000906001600160a01b031661114c5760405162461bcd60e51b81526020600482015260166024820152751b5d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b60448201526064016105ef565b6005541580611170575060008460c0015111801561117057506005548460c0015111155b6111ac5760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081b1a5b5a5d609a1b60448201526064016105ef565b60035484516020808701516101208801516040516111fe9561010090046001600160a01b0316946111e3948c949193919201611f66565b60405160208183030381529060405280519060200120611667565b9050600061120a61145c565b90506001600160a01b038116156113165760e0850151604051631963bc8b60e11b81526001600160a01b0384811660048301526000602483015291821660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906332c7791690606401600060405180830381600087803b15801561129457600080fd5b505af11580156112a8573d6000803e3d6000fd5b5050505060e085015160405163a566006360e01b81526001600160a01b03848116600483015291821660248201529082169063a566006390604401600060405180830381600087803b1580156112fd57600080fd5b505af1158015611311573d6000803e3d6000fd5b505050505b60035460405163dbdc37f360e01b81526001600160a01b0384169163dbdc37f3913491611353918b918b918b918b9160ff9091169060040161202e565b6000604051808303818588803b15801561136c57600080fd5b505af1158015611380573d6000803e3d6000fd5b50506040516306e9fe9960e41b81526001600160a01b038a8116600483015286811660248301527f0000000000000000000000000000000000000000000000000000000000000000169350636e9fe99092506044019050600060405180830381600087803b1580156113f157600080fd5b505af1158015611405573d6000803e3d6000fd5b5050505050949350505050565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d6811b6f6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156114be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e29190611f49565b905090565b60006106ce7f00000000000000000000000000000000000000000000000000000000000000007f682b3920f0bf70eb759a59b34e1c6ff903edb5ced39efd66303d66cc0eac774e858560000151866020015187606001518860800151604051602001611556949392919061217d565b604051602081830303815290604052805190602001208660c001518760a001518860e001518961010001518a61012001518b61014001516040516020016115f3999897969594939291909889526001600160a01b0397881660208a0152604089019690965260608801949094526080870192909252841660a086015290921660c084015260e083019190915261ffff166101008201526101200190565b60408051601f19818403018152828252805160209182012061190160f01b8483015260228401949094526042808401949094528151808403909401845260629092019052815191012090565b600080600061165087878787611706565b9150915061165d816117f3565b5095945050505050565b600060405172602d8060093d393df3363d3d373d3d3d363d7360681b81528360601b60138201526e5af43d82803e903d91602b57fd5bf360881b6027820152826036826000f59150506001600160a01b0381166106d15760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c656400000000000000000060448201526064016105ef565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561173d57506000905060036117ea565b8460ff16601b1415801561175557508460ff16601c14155b1561176657506000905060046117ea565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156117ba573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166117e3576000600192509250506117ea565b9150600090505b94509492505050565b6000816004811115611807576118076121d4565b14156118105750565b6001816004811115611824576118246121d4565b14156118725760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105ef565b6002816004811115611886576118866121d4565b14156118d45760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105ef565b60038160048111156118e8576118e86121d4565b14156119415760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105ef565b6004816004811115611955576119556121d4565b14156119ae5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105ef565b50565b6001600160a01b03811681146119ae57600080fd5b80356119d1816119b1565b919050565b803560ff811681146119d157600080fd5b600080600080600060a086880312156119ff57600080fd5b8535611a0a816119b1565b945060208601359350611a1f604087016119d6565b94979396509394606081013594506080013592915050565b600060208284031215611a4957600080fd5b5035919050565b60008060408385031215611a6357600080fd5b8235611a6e816119b1565b946020939093013593505050565b60005b83811015611a97578181015183820152602001611a7f565b83811115611aa6576000848401525b50505050565b60008151808452611ac4816020860160208601611a7c565b601f01601f19169290920160200192915050565b6020815260006106ce6020830184611aac565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715611b2557611b25611aeb565b60405290565b600082601f830112611b3c57600080fd5b813567ffffffffffffffff80821115611b5757611b57611aeb565b604051601f8301601f19908116603f01168101908282118183101715611b7f57611b7f611aeb565b81604052838152866020858801011115611b9857600080fd5b836020870160208301376000602085830101528094505050505092915050565b803561ffff811681146119d157600080fd5b60006101608284031215611bdd57600080fd5b611be5611b01565b9050813567ffffffffffffffff80821115611bff57600080fd5b611c0b85838601611b2b565b83526020840135915080821115611c2157600080fd5b611c2d85838601611b2b565b60208401526040840135915080821115611c4657600080fd5b611c5285838601611b2b565b60408401526060840135915080821115611c6b57600080fd5b611c7785838601611b2b565b60608401526080840135915080821115611c9057600080fd5b50611c9d84828501611b2b565b60808301525060a082013560a082015260c082013560c0820152611cc360e083016119c6565b60e0820152610100611cd68184016119c6565b908201526101208281013590820152610140611cf3818401611bb8565b9082015292915050565b600060208284031215611d0f57600080fd5b813567ffffffffffffffff811115611d2657600080fd5b610dc784828501611bca565b600060208284031215611d4457600080fd5b81358015158114611d5457600080fd5b9392505050565b60008060408385031215611d6e57600080fd5b8235611d79816119b1565b91506020830135611d89816119b1565b809150509250929050565b60008060408385031215611da757600080fd5b8235611db2816119b1565b9150602083013567ffffffffffffffff811115611dce57600080fd5b611dda85828601611bca565b9150509250929050565b600080600080600080600060e0888a031215611dff57600080fd5b8735611e0a816119b1565b9650602088013567ffffffffffffffff80821115611e2757600080fd5b611e338b838c01611bca565b9750611e4160408b016119d6565b965060608a0135955060808a0135945060a08a01359150611e61826119b1565b90925060c08901359080821115611e7757600080fd5b50611e848a828b01611b2b565b91505092959891949750929550565b600080600060608486031215611ea857600080fd5b8335611eb3816119b1565b92506020840135611ec3816119b1565b9150604084013567ffffffffffffffff811115611edf57600080fd5b611eeb86828701611b2b565b9150509250925092565b600060208284031215611f0757600080fd5b8135611d54816119b1565b60208082526018908201527f63616c6c6572206973206e6f7420746865206f776e65722e0000000000000000604082015260600190565b600060208284031215611f5b57600080fd5b8151611d54816119b1565b6001600160a01b0385168152608060208201819052600090611f8a90830186611aac565b8281036040840152611f9c8186611aac565b91505082606083015295945050505050565b6001600160a01b0383168152604060208201819052600090610dc790830184611aac565b600060208284031215611fe457600080fd5b5051919050565b828152604060208201526000610dc76040830184611aac565b60006020828403121561201657600080fd5b81516001600160e01b031981168114611d5457600080fd5b60018060a01b038616815260a06020820152600085516101608060a085015261205b610200850183611aac565b91506020880151609f19808685030160c08701526120798483611aac565b935060408a01519150808685030160e08701526120968483611aac565b935060608a015191506101008187860301818801526120b58584611aac565b945060808b015192506101208288870301818901526120d48685611aac565b955060a08c015193506101409250838389015260c08c01518589015260e08c0151945061210d6101808901866001600160a01b03169052565b908b01516001600160a01b03166101a08801528a01516101c087015289015161ffff81166101e087015291506121409050565b506001600160a01b038616604084015282810360608401526121628186611aac565b915050612173608083018415159052565b9695505050505050565b6000855161218f818460208a01611a7c565b8551908301906121a3818360208a01611a7c565b85519101906121b6818360208901611a7c565b84519101906121c9818360208801611a7c565b019695505050505050565b634e487b7160e01b600052602160045260246000fdfea264697066735822122039472762c33600bb9c364030aaf7e8f014d849edcb745dac6fcc79fe26f1adbf64736f6c634300080c0033608060405234801561001057600080fd5b506108d8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636e9fe9901161008c578063a6d49dca11610066578063a6d49dca14610181578063bbeeea3514610194578063f0091f4f146101a7578063fc0ed66a146101ba57600080fd5b80636e9fe990146101485780639ea75f271461015b578063a13b024a1461016e57600080fd5b806305f091ce146100d45780630ba1ba83146100e957806322fd9ed7146100fc578063271c9e1f1461010f57806332c77916146101225780635115de1414610135575b600080fd5b6100e76100e2366004610528565b6101cd565b005b6100e76100f736600461056d565b610205565b6100e761010a3660046105b1565b610256565b6100e761011d3660046105e4565b610295565b6100e7610130366004610606565b6102d5565b6100e7610143366004610649565b610322565b6100e76101563660046105b1565b61035b565b6100e76101693660046105e4565b61039a565b6100e761017c3660046105e4565b6103d2565b6100e761018f366004610664565b61040a565b6100e76101a2366004610743565b610459565b6100e76101b53660046105b1565b6104ae565b6100e76101c83660046107a4565b6104ed565b60405181151581527f48f558308664f690bb62e2e7859cb0cc0e4206065ee613c4124fe46f2fbba33d9060200160405180910390a150565b60408051848152602081018390526001600160a01b03808516929087169133917f445617be23737f769f001a14b79033ca2d6157166e27ff0fa79cb3d7b1473ce5910160405180910390a450505050565b6040516001600160a01b03808316919084169033907f0a7edb67b6ca4b003a2209d9b62ce843cd9fa2dcc68932f6e6eba54c16c32d0290600090a45050565b604080518381526020810183905233917f4b4a2ff355c13f32702752ac92eeaf13c9b36031372aadda0599e3f0e9278fb591015b60405180910390a25050565b6040516001600160a01b038381168252808316919085169033907f08493ccfa704da7eac9de51bbe498add35885fd4fde0f8cb59a30d544d7a6cea906020015b60405180910390a4505050565b6040516001600160a01b0382169033907f64a09d2d1013a7b08dfa13b95383781d6723b1e504df7e58e16cbda867950b5290600090a350565b6040516001600160a01b03808316919084169033907fe30784b97c85804517b7c35cb82a1ba9f5f5e7a90ceb80ffab76908cb9b1a70890600090a45050565b604080518381526020810183905233917fb59835113815d633ef2c99e436a22350ceb0286c3ebbb62f66592530675525e691016102c9565b604080518381526020810183905233917fd9359f6744c286382115ed720fc5e2e5da40d7aa33113ed0f1a3a4557c87ae4091016102c9565b816001600160a01b0316836001600160a01b0316336001600160a01b03167fd1398bee19313d6bf672ccb116e51f4a1a947e91c757907f51fbb5b5e56c698f8460405161031591815260200190565b826001600160a01b0316336001600160a01b03167f6d127962f8e412a3050dd402e293265d1b21852a77b965abd7b16a1f4de86ed08685856040516104a093929190610855565b60405180910390a350505050565b6040516001600160a01b03808316919084169033907fcfdb5bf35cd540089cd8f95da6d222385981136736f852cfa4203ecc6be705d990600090a45050565b336001600160a01b03167fcc112814b751eaa17155a559b546552f6dacebd853ad2a950b22a929ff94535783836040516102c992919061087d565b60006020828403121561053a57600080fd5b8135801515811461054a57600080fd5b9392505050565b80356001600160a01b038116811461056857600080fd5b919050565b6000806000806080858703121561058357600080fd5b61058c85610551565b9350602085013592506105a160408601610551565b9396929550929360600135925050565b600080604083850312156105c457600080fd5b6105cd83610551565b91506105db60208401610551565b90509250929050565b600080604083850312156105f757600080fd5b50508035926020909101359150565b60008060006060848603121561061b57600080fd5b61062484610551565b925061063260208501610551565b915061064060408501610551565b90509250925092565b60006020828403121561065b57600080fd5b61054a82610551565b60008060006060848603121561067957600080fd5b61068284610551565b925061069060208501610551565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126106c757600080fd5b813567ffffffffffffffff808211156106e2576106e26106a0565b604051601f8301601f19908116603f0116810190828211818310171561070a5761070a6106a0565b8160405283815286602085880101111561072357600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806080858703121561075957600080fd5b8435935061076960208601610551565b925060408501359150606085013567ffffffffffffffff81111561078c57600080fd5b610798878288016106b6565b91505092959194509250565b600080604083850312156107b757600080fd5b823567ffffffffffffffff808211156107cf57600080fd5b6107db868387016106b6565b935060208501359150808211156107f157600080fd5b506107fe858286016106b6565b9150509250929050565b6000815180845260005b8181101561082e57602081850181015186830182015201610812565b81811115610840576000602083870101525b50601f01601f19169290920160200192915050565b8381528260208201526060604082015260006108746060830184610808565b95945050505050565b6040815260006108906040830185610808565b8281036020840152610874818561080856fea26469706673582212208944b489ba8bbcd39da30db625f8682998a971df1eff1b2fcceb6e9dd7a7e69864736f6c634300080c0033610100604052600160028190556080523480156200001c57600080fd5b506040516200446b3803806200446b8339810160408190526200003f91620001f4565b600160006200004e816200018c565b506001805460ff60a01b1916600160a01b831515021790555060016003556001600160a01b038316620000bb5760405162461bcd60e51b815260206004820152601060248201526f6d7573742073657420666163746f727960801b60448201526064015b60405180910390fd5b6001600160a01b0380841660a0528216620001195760405162461bcd60e51b815260206004820152601f60248201527f6d7573742073657420747265617375727920636f6e66696775726174696f6e006044820152606401620000b2565b6001600160a01b0380831660c0528116620001775760405162461bcd60e51b815260206004820152601660248201527f6d75737420736574206f62736572766162696c697479000000000000000000006044820152606401620000b2565b6001600160a01b031660e052506200023e9050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350565b80516001600160a01b0381168114620001ef57600080fd5b919050565b6000806000606084860312156200020a57600080fd5b6200021584620001d7565b92506200022560208501620001d7565b91506200023560408501620001d7565b90509250925092565b60805160a05160c05160e051614191620002da600039600081816105ff01528181610d1801528181610e5801528181611154015281816113f3015281816114980152818161168401528181611b4a0152818161219c0152612a350152600081816107de01528181612b400152612dd1015260008181610812015281816118d80152818161196701526122c60152600061096b01526141916000f3fe6080604052600436106102ff5760003560e01c806379ba509711610190578063bee0ec0b116100dc578063ddca3f4311610095578063e985e9c51161006f578063e985e9c5146108f9578063ed459df214610919578063f2fde38b14610939578063ffa1ad741461095957600080fd5b8063ddca3f431461088f578063e2e784d5146108c4578063e8a3d485146108e457600080fd5b8063bee0ec0b146107cc578063c45a015514610800578063c7381da314610834578063c87b56dd14610849578063cfc3fe2c14610869578063dbdc37f31461087c57600080fd5b80639c1fd6e011610149578063a4d66daf11610123578063a4d66daf1461076b578063a8d13a2914610781578063b88d4fde14610796578063b9c9d93a146107b657600080fd5b80639c1fd6e014610715578063a035b1fe14610735578063a22cb4651461074b57600080fd5b806379ba50971461066b5780638ada6b0f146106805780638da5cb5b146106a05780638f32d59b146106c057806391b7f5ed146106e057806395d89b411461070057600080fd5b80633cb70c2d1161024f5780636352211e11610208578063705bf368116101e2578063705bf368146105ed57806370a0823114610621578063715018a6146106415780637284e4161461065657600080fd5b80636352211e1461058c5780636a627842146105ac5780636f19d0b6146105cc57600080fd5b80633cb70c2d146104d557806342842e0e146104ea578063475911351461050a5780634c00de82146105375780634dcd14b21461055757806356d3163d1461056c57600080fd5b80631bb534ba116102bc578063241d965111610296578063241d96511461044357806327ea6f2b146104635780632a55205a146104835780633a1b1d57146104c257600080fd5b80631bb534ba146103ee57806323452b9c1461040e57806323b872dd1461042357600080fd5b806301ffc9a71461030457806306fdde0314610339578063081812fc1461035b578063095ea7b314610393578063135d088d146103b557806318160ddd146103ca575b600080fd5b34801561031057600080fd5b5061032461031f366004613119565b61099f565b60405190151581526020015b60405180910390f35b34801561034557600080fd5b5061034e610a0c565b6040516103309190613195565b34801561036757600080fd5b5061037b6103763660046131a8565b610a9a565b6040516001600160a01b039091168152602001610330565b34801561039f57600080fd5b506103b36103ae3660046131e1565b610b34565b005b3480156103c157600080fd5b5061034e610c4a565b3480156103d657600080fd5b506103e0600b5481565b604051908152602001610330565b3480156103fa57600080fd5b5060105461037b906001600160a01b031681565b34801561041a57600080fd5b506103b3610c57565b34801561042f57600080fd5b506103b361043e36600461320d565b610c93565b34801561044f57600080fd5b506103b361045e36600461324e565b610cc4565b34801561046f57600080fd5b506103b361047e3660046131a8565b610d99565b34801561048f57600080fd5b506104a361049e36600461326b565b610ec4565b604080516001600160a01b039093168352602083019190915201610330565b6103e06104d0366004613384565b610ef9565b3480156104e157600080fd5b5061034e610f97565b3480156104f657600080fd5b506103b361050536600461320d565b610fa6565b34801561051657600080fd5b5061052a6105253660046133d4565b610fc1565b604051610330919061347a565b34801561054357600080fd5b5060115461037b906001600160a01b031681565b34801561056357600080fd5b5061034e611097565b34801561057857600080fd5b506103b361058736600461324e565b6110a4565b34801561059857600080fd5b5061037b6105a73660046131a8565b6111b5565b3480156105b857600080fd5b506103e06105c736600461324e565b6111c0565b3480156105d857600080fd5b5060015461032490600160a01b900460ff1681565b3480156105f957600080fd5b5061037b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561062d57600080fd5b506103e061063c36600461324e565b6111f4565b34801561064d57600080fd5b506103b361127b565b34801561066257600080fd5b5061034e6112af565b34801561067757600080fd5b506103b36112f1565b34801561068c57600080fd5b5060135461037b906001600160a01b031681565b3480156106ac57600080fd5b5060005461037b906001600160a01b031681565b3480156106cc57600080fd5b506000546001600160a01b03163314610324565b3480156106ec57600080fd5b506103b36106fb3660046131a8565b6113a8565b34801561070c57600080fd5b5061034e61145f565b34801561072157600080fd5b506103b36107303660046134c7565b61146c565b34801561074157600080fd5b506103e0600e5481565b34801561075757600080fd5b506103b3610766366004613515565b611534565b34801561077757600080fd5b506103e0600f5481565b34801561078d57600080fd5b506103b36115f9565b3480156107a257600080fd5b506103b36107b136600461354e565b61162b565b3480156107c257600080fd5b506103e060125481565b3480156107d857600080fd5b5061037b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561080c57600080fd5b5061037b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561084057600080fd5b506103b361163d565b34801561085557600080fd5b5061034e6108643660046131a8565b6116fa565b6103e0610877366004613384565b6118a3565b6103b361088a3660046135e9565b611934565b34801561089b57600080fd5b506010546108b190600160a01b900461ffff1681565b60405161ffff9091168152602001610330565b3480156108d057600080fd5b506103b36108df3660046131e1565b611abb565b3480156108f057600080fd5b5061034e611c1d565b34801561090557600080fd5b50610324610914366004613794565b611cbe565b34801561092557600080fd5b506001546001600160a01b03163314610324565b34801561094557600080fd5b506103b361095436600461324e565b611cec565b34801561096557600080fd5b5061098d7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610330565b60006001600160e01b031982166380ac58cd60e01b14806109d057506001600160e01b03198216635b5e139f60e01b145b806109eb57506001600160e01b031982166301ffc9a760e01b145b80610a0657506001600160e01b0319821663152a902d60e11b145b92915050565b60088054610a19906137c2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a45906137c2565b8015610a925780601f10610a6757610100808354040283529160200191610a92565b820191906000526020600020905b815481529060010190602001808311610a7557829003601f168201915b505050505081565b6000818152600460205260408120546001600160a01b0316610b185760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610b3f82611d8e565b9050806001600160a01b0316836001600160a01b03161415610bad5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610b0f565b336001600160a01b0382161480610bc95750610bc98133611cbe565b610c3b5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b0f565b610c458383611e05565b505050565b600d8054610a19906137c2565b6000546001600160a01b03163314610c815760405162461bcd60e51b8152600401610b0f906137f7565b600180546001600160a01b0319169055565b610c9d3382611e73565b610cb95760405162461bcd60e51b8152600401610b0f9061382e565b610c45838383611f4a565b6000546001600160a01b03163314610cee5760405162461bcd60e51b8152600401610b0f906137f7565b60105460405163f0091f4f60e01b81526001600160a01b03918216600482015282821660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063f0091f4f90604401600060405180830381600087803b158015610d5e57600080fd5b505af1158015610d72573d6000803e3d6000fd5b5050601080546001600160a01b0319166001600160a01b0394909416939093179092555050565b6000546001600160a01b03163314610dc35760405162461bcd60e51b8152600401610b0f906137f7565b600b548110158015610de05750600f541580610de05750600f5481105b610e375760405162461bcd60e51b815260206004820152602260248201527f6c696d6974206d757374206265203c207468616e2063757272656e74206c696d6044820152611a5d60f21b6064820152608401610b0f565b600f5460405163271c9e1f60e01b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063271c9e1f90604401600060405180830381600087803b158015610ea457600080fd5b505af1158015610eb8573d6000803e3d6000fd5b505050600f9190915550565b600080610ecf6120f5565b9150612710610edc612129565b610ee69085613895565b610ef091906138ca565b90509250929050565b600154600090600160a01b900460ff1615610f1657610f16612143565b60026003541415610f395760405162461bcd60e51b8152600401610b0f906138de565b6002600355600e543414610f815760405162461bcd60e51b815260206004820152600f60248201526e696e636f72726563742076616c756560881b6044820152606401610b0f565b610f8b8383612174565b60016003559392505050565b6060610fa161221e565b905090565b610c458383836040518060200160405280600081525061234a565b6060815167ffffffffffffffff811115610fdd57610fdd61328d565b604051908082528060200260200182016040528015611006578160200160208202803683370190505b50905060005b8251811015611091576004600084838151811061102b5761102b613915565b6020026020010151815260200190815260200160002060009054906101000a90046001600160a01b031682828151811061106757611067613915565b6001600160a01b0390921660209283029190910190910152806110898161392b565b91505061100c565b50919050565b600c8054610a19906137c2565b6000546001600160a01b031633146110ce5760405162461bcd60e51b8152600401610b0f906137f7565b6013546001600160a01b03161561111e5760405162461bcd60e51b81526020600482015260146024820152731c995b99195c995c88185b1c9958591e481cd95d60621b6044820152606401610b0f565b601380546001600160a01b0319166001600160a01b03838116918217909255604051631445778560e21b815260048101919091527f000000000000000000000000000000000000000000000000000000000000000090911690635115de1490602401600060405180830381600087803b15801561119a57600080fd5b505af11580156111ae573d6000803e3d6000fd5b5050505050565b6000610a0682611d8e565b600080546001600160a01b031633146111eb5760405162461bcd60e51b8152600401610b0f906137f7565b610a068261237c565b60006001600160a01b03821661125f5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610b0f565b506001600160a01b031660009081526005602052604090205490565b6000546001600160a01b031633146112a55760405162461bcd60e51b8152600401610b0f906137f7565b6112ad6123ff565b565b60606112b961221e565b6112c246612449565b6112cb30612547565b6040516020016112dd93929190613962565b604051602081830303815290604052905090565b6001546001600160a01b031633146113605760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201526b103732bc3a1037bbb732b91760a11b6064820152608401610b0f565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b6000546001600160a01b031633146113d25760405162461bcd60e51b8152600401610b0f906137f7565b600e5460405163509d812560e11b81526004810191909152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a13b024a90604401600060405180830381600087803b15801561143f57600080fd5b505af1158015611453573d6000803e3d6000fd5b505050600e9190915550565b60098054610a19906137c2565b6000546001600160a01b031633146114965760405162461bcd60e51b8152600401610b0f906137f7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fc0ed66a6114cd61221e565b836040518363ffffffff1660e01b81526004016114eb9291906139b2565b600060405180830381600087803b15801561150557600080fd5b505af1158015611519573d6000803e3d6000fd5b505082516115309250600a91506020840190613067565b5050565b6001600160a01b03821633141561158d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b0f565b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6000546001600160a01b031633146116235760405162461bcd60e51b8152600401610b0f906137f7565b6112ad6126b0565b6116378484848461234a565b50505050565b6000546001600160a01b031633146116675760405162461bcd60e51b8152600401610b0f906137f7565b600f54600b5460405163271c9e1f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263271c9e1f926116c092600401918252602082015260400190565b600060405180830381600087803b1580156116da57600080fd5b505af11580156116ee573d6000803e3d6000fd5b5050600b54600f555050565b6000818152600460205260409020546060906001600160a01b031661176d5760405162461bcd60e51b815260206004820152602360248201527f4552433732313a20717565727920666f72206e6f6e6578697374656e7420746f60448201526235b2b760e91b6064820152608401610b0f565b6013546001600160a01b0316156117ef5760135460405163c87b56dd60e01b8152600481018490526001600160a01b039091169063c87b56dd90602401600060405180830381865afa1580156117c7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a0691908101906139e0565b6060600f5460001461182857611806600f54612449565b6040516020016118169190613a4e565b60405160208183030381529060405290505b6000611878600861183886612449565b846118416112af565b600c600d61184e8b612449565b6040516020016118649796959493929190613b10565b6040516020818303038152906040526126c7565b90508060405160200161188b9190613c5b565b60405160208183030381529060405292505050919050565b6000600260035414156118c85760405162461bcd60e51b8152600401610b0f906138de565b6002600355336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f815760405162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b6044820152606401610b0f565b600260035414156119575760405162461bcd60e51b8152600401610b0f906138de565b6002600355336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119ca5760405162461bcd60e51b81526020600482015260136024820152723ab730baba3437b934bd32b21031b0b63632b960691b6044820152606401610b0f565b835180516119e091600891602090910190613067565b5060208085015180516119f7926009920190613067565b5060608401518051611a1191600d91602090910190613067565b5060808401518051611a2b91600c91602090910190613067565b5060a0840151600e5560c0840151600f5560e0840151601080546001600160a01b039283166001600160a01b03199182161790915561010086015160138054919093169116179055610140840151611a829061281b565b611a8b85612923565b6001600160a01b03831615611aa657611aa48383612174565b505b611aaf8161296e565b50506001600355505050565b6000546001600160a01b03163314611ae55760405162461bcd60e51b8152600401610b0f906137f7565b612710811115611b485760405162461bcd60e51b815260206004820152602860248201527f627073206d757374206265206c657373207468616e206f7220657175616c207460448201526706f2031302c3030360c41b6064820152608401610b0f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630ba1ba83611b7f6120f5565b611b87612129565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201526024810191909152908516604482015260648101849052608401600060405180830381600087803b158015611bdf57600080fd5b505af1158015611bf3573d6000803e3d6000fd5b5050601180546001600160a01b0319166001600160a01b0395909516949094179093555060125550565b6013546060906001600160a01b031615611cb657601360009054906101000a90046001600160a01b03166001600160a01b031663e8a3d4856040518163ffffffff1660e01b8152600401600060405180830381865afa925050508015611ca557506040513d6000823e601f3d908101601f19168201604052611ca291908101906139e0565b60015b611cb157610fa161298c565b919050565b610fa161298c565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b6000546001600160a01b03163314611d165760405162461bcd60e51b8152600401610b0f906137f7565b6001600160a01b038116611d6c5760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e006044820152606401610b0f565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600460205260408120546001600160a01b031680610a065760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610b0f565b600081815260066020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611e3a82611d8e565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600460205260408120546001600160a01b0316611eec5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b0f565b6000611ef783611d8e565b9050806001600160a01b0316846001600160a01b03161480611f325750836001600160a01b0316611f2784610a9a565b6001600160a01b0316145b80611f425750611f428185611cbe565b949350505050565b826001600160a01b0316611f5d82611d8e565b6001600160a01b031614611fc55760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610b0f565b6001600160a01b0382166120275760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610b0f565b612032838383612a07565b61203d600082611e05565b6001600160a01b0383166000908152600560205260408120805460019290612066908490613ca0565b90915550506001600160a01b0382166000908152600560205260408120805460019290612094908490613cb7565b909155505060008181526004602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6011546000906001600160a01b03161561211957506011546001600160a01b031690565b506010546001600160a01b031690565b600060125460001461213c575060125490565b506103e890565b60005a60025490915060005a60025490915061215f8285613ca0565b5a61216a9084613ca0565b1061163757600080fd5b600061217f8361237c565b600e5460405163bbeeea3560e01b81529192506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163bbeeea35916121d591859188918890600401613ccf565b600060405180830381600087803b1580156121ef57600080fd5b505af1158015612203573d6000803e3d6000fd5b5050601054610a0692506001600160a01b0316905034612a96565b6060600a805461222d906137c2565b1590506122c457600a8054612241906137c2565b80601f016020809104026020016040519081016040528092919081815260200182805461226d906137c2565b80156122ba5780601f1061228f576101008083540402835291602001916122ba565b820191906000526020600020905b81548152906001019060200180831161229d57829003601f168201915b5050505050905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633cb70c2d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612322573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fa191908101906139e0565b6123543383611e73565b6123705760405162461bcd60e51b8152600401610b0f9061382e565b61163784848484612c16565b6000600b6000815461238d9061392b565b9182905550600f5490915015806123a75750600019600f54145b806123be5750600f546123bb906001613cb7565b81105b6123f55760405162461bcd60e51b81526020600482015260086024820152671cdbdb19081bdd5d60c21b6044820152606401610b0f565b611cb18282612c49565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60608161246d5750506040805180820190915260018152600360fc1b602082015290565b8160005b811561249757806124818161392b565b91506124909050600a836138ca565b9150612471565b60008167ffffffffffffffff8111156124b2576124b261328d565b6040519080825280601f01601f1916602001820160405280156124dc576020820181803683370190505b5090505b8415611f42576124f1600183613ca0565b91506124fe600a86613d06565b612509906030613cb7565b60f81b81838151811061251e5761251e613915565b60200101906001600160f81b031916908160001a905350612540600a866138ca565b94506124e0565b60408051602880825260608281019093526000919060208201818036833701905050905060005b6014811015612687576000612584826013613ca0565b61258f906008613895565b61259a906002613dfe565b6125ad906001600160a01b0387166138ca565b60f81b9050600060108260f81c6125c49190613e0a565b60f81b905060008160f81c60106125db9190613e2c565b8360f81c6125e99190613e4d565b60f81b90506125f782612d97565b85612603866002613895565b8151811061261357612613613915565b60200101906001600160f81b031916908160001a90535061263381612d97565b8561263f866002613895565b61264a906001613cb7565b8151811061265a5761265a613915565b60200101906001600160f81b031916908160001a905350505050808061267f9061392b565b91505061256e565b50806040516020016126999190613e70565b604051602081830303815290604052915050919050565b6001546112ad90600160a01b900460ff161561296e565b60608151600014156126e757505060408051602081019091526000815290565b600060405180606001604052806040815260200161411c60409139905060006003845160026127169190613cb7565b61272091906138ca565b61272b906004613895565b67ffffffffffffffff8111156127435761274361328d565b6040519080825280601f01601f19166020018201604052801561276d576020820181803683370190505b509050600182016020820185865187015b808210156127d9576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f811685015184535060018301925061277e565b50506003865106600181146127f5576002811461280857612810565b603d6001830353603d6002830353612810565b603d60018303535b509195945050505050565b6000612825612dcd565b6040516308c090cf60e11b815261ffff841660048201529091506001600160a01b03821690631181219e90602401602060405180830381865afa158015612870573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128949190613e9a565b61290157806001600160a01b0316631a7626e76040518163ffffffff1660e01b81526004016020604051808303816000875af11580156128d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fc9190613eb7565b612903565b815b601060146101000a81548161ffff021916908361ffff1602179055505050565b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350565b60018054911515600160a01b0260ff60a01b19909216919091179055565b606060006129df600861299d6112af565b600c600d6129b16129ac612129565b612449565b6129c16129bc6120f5565b612547565b6129c961221e565b6040516020016118649796959493929190613ed4565b9050806040516020016129f29190613c5b565b60405160208183030381529060405291505090565b60405163536a4ee560e11b81526001600160a01b0384811660048301528381166024830152604482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a6d49dca90606401600060405180830381600087803b158015612a7957600080fd5b505af1158015612a8d573d6000803e3d6000fd5b50505050505050565b6000612aa0612dcd565b90506001600160a01b03811615801590612b195750806001600160a01b03166367b7c0346040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612af5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b199190613e9a565b15612c0c576000612b3a83601060149054906101000a900461ffff16612e53565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166361d027b36040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612b9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc29190614037565b90508115801590612bdb57506001600160a01b03811615155b15612c0257612bea8183612e89565b612bfd85612bf88487613ca0565b612e89565b6111ae565b6111ae8585612e89565b610c458383612e89565b612c21848484611f4a565b612c2d84848484612f69565b6116375760405162461bcd60e51b8152600401610b0f90614054565b6001600160a01b038216612c9f5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b0f565b6000818152600460205260409020546001600160a01b031615612d045760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b0f565b612d1060008383612a07565b6001600160a01b0382166000908152600560205260408120805460019290612d39908490613cb7565b909155505060008181526004602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000600a60f883901c1015612dbe57612db560f883901c60306140a6565b60f81b92915050565b612db560f883901c60576140a6565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166398c47e8c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612e2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa19190614037565b60006127108310612e805761ffff8216612e6f612710856138ca565b612e799190613895565b9050610a06565b50600092915050565b80471015612ed05760405162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b6044820152606401610b0f565b6000826001600160a01b0316825a6040519091906000818181858888f193505050503d8060008114612f1e576040519150601f19603f3d011682016040523d82523d6000602084013e612f23565b606091505b5050905080610c455760405162461bcd60e51b81526020600482015260126024820152711c9958da5c1a595b9d081c995d995c9d195960721b6044820152606401610b0f565b60006001600160a01b0384163b1561305c57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612fad9033908990889088906004016140cb565b6020604051808303816000875af1925050508015612fe8575060408051601f3d908101601f19168201909252612fe5918101906140fe565b60015b613042573d808015613016576040519150601f19603f3d011682016040523d82523d6000602084013e61301b565b606091505b50805161303a5760405162461bcd60e51b8152600401610b0f90614054565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611f42565b506001949350505050565b828054613073906137c2565b90600052602060002090601f01602090048101928261309557600085556130db565b82601f106130ae57805160ff19168380011785556130db565b828001600101855582156130db579182015b828111156130db5782518255916020019190600101906130c0565b506130e79291506130eb565b5090565b5b808211156130e757600081556001016130ec565b6001600160e01b03198116811461311657600080fd5b50565b60006020828403121561312b57600080fd5b813561313681613100565b9392505050565b60005b83811015613158578181015183820152602001613140565b838111156116375750506000910152565b6000815180845261318181602086016020860161313d565b601f01601f19169290920160200192915050565b6020815260006131366020830184613169565b6000602082840312156131ba57600080fd5b5035919050565b6001600160a01b038116811461311657600080fd5b8035611cb1816131c1565b600080604083850312156131f457600080fd5b82356131ff816131c1565b946020939093013593505050565b60008060006060848603121561322257600080fd5b833561322d816131c1565b9250602084013561323d816131c1565b929592945050506040919091013590565b60006020828403121561326057600080fd5b8135613136816131c1565b6000806040838503121561327e57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff811182821017156132c7576132c761328d565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156132f6576132f661328d565b604052919050565b600067ffffffffffffffff8211156133185761331861328d565b50601f01601f191660200190565b6000613339613334846132fe565b6132cd565b905082815283838301111561334d57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261337557600080fd5b61313683833560208501613326565b6000806040838503121561339757600080fd5b82356133a2816131c1565b9150602083013567ffffffffffffffff8111156133be57600080fd5b6133ca85828601613364565b9150509250929050565b600060208083850312156133e757600080fd5b823567ffffffffffffffff808211156133ff57600080fd5b818501915085601f83011261341357600080fd5b8135818111156134255761342561328d565b8060051b91506134368483016132cd565b818152918301840191848101908884111561345057600080fd5b938501935b8385101561346e57843582529385019390850190613455565b98975050505050505050565b6020808252825182820181905260009190848201906040850190845b818110156134bb5783516001600160a01b031683529284019291840191600101613496565b50909695505050505050565b6000602082840312156134d957600080fd5b813567ffffffffffffffff8111156134f057600080fd5b611f4284828501613364565b801515811461311657600080fd5b8035611cb1816134fc565b6000806040838503121561352857600080fd5b8235613533816131c1565b91506020830135613543816134fc565b809150509250929050565b6000806000806080858703121561356457600080fd5b843561356f816131c1565b9350602085013561357f816131c1565b925060408501359150606085013567ffffffffffffffff8111156135a257600080fd5b8501601f810187136135b357600080fd5b6135c287823560208401613326565b91505092959194509250565b61ffff8116811461311657600080fd5b8035611cb1816135ce565b600080600080600060a0868803121561360157600080fd5b853561360c816131c1565b9450602086013567ffffffffffffffff8082111561362957600080fd5b90870190610160828a03121561363e57600080fd5b6136466132a3565b82358281111561365557600080fd5b6136618b828601613364565b82525060208301358281111561367657600080fd5b6136828b828601613364565b60208301525060408301358281111561369a57600080fd5b6136a68b828601613364565b6040830152506060830135828111156136be57600080fd5b6136ca8b828601613364565b6060830152506080830135828111156136e257600080fd5b6136ee8b828601613364565b60808301525060a083013560a082015260c083013560c082015261371460e084016131d6565b60e08201526101006137278185016131d6565b9082015261012083810135908201526101406137448185016135de565b908201529550613756604089016131d6565b9450606088013591508082111561376c57600080fd5b5061377988828901613364565b9250506137886080870161350a565b90509295509295909350565b600080604083850312156137a757600080fd5b82356137b2816131c1565b91506020830135613543816131c1565b600181811c908216806137d657607f821691505b6020821081141561109157634e487b7160e01b600052602260045260246000fd5b60208082526018908201527f63616c6c6572206973206e6f7420746865206f776e65722e0000000000000000604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008160001904831182151516156138af576138af61387f565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826138d9576138d96138b4565b500490565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060001982141561393f5761393f61387f565b5060010190565b6000815161395881856020860161313d565b9290920192915050565b6000845161397481846020890161313d565b84519083019061398881836020890161313d565b602f60f81b910190815283516139a581600184016020880161313d565b0160010195945050505050565b6040815260006139c56040830185613169565b82810360208401526139d78185613169565b95945050505050565b6000602082840312156139f257600080fd5b815167ffffffffffffffff811115613a0957600080fd5b8201601f81018413613a1a57600080fd5b8051613a28613334826132fe565b818152856020838501011115613a3d57600080fd5b6139d782602083016020860161313d565b602f60f81b815260008251613a6a81600185016020870161313d565b9190910160010192915050565b8054600090600181811c9080831680613a9157607f831692505b6020808410821415613ab357634e487b7160e01b600052602260045260246000fd5b818015613ac75760018114613ad857613b04565b60ff19861689528489019650613b04565b876000528160002060005b86811015613afc5781548b820152908501908301613ae3565b505084890196505b50505050505092915050565b693d913730b6b2911d101160b11b81526000613b2f600a83018a613a77565b600160fd1b81528851613b49816001840160208d0161313d565b8851910190613b5f816001840160208c0161313d565b72111610113232b9b1b934b83a34b7b7111d101160691b600192909101918201528651613b93816014840160208b0161313d565b73222c2022636f6e74656e74223a202261723a2f2f60601b60149290910191820152613bc26028820187613a77565b73222c2022696d616765223a2022697066733a2f2f60601b81529050613beb6014820186613a77565b7f222c202261747472696275746573223a5b7b202274726169745f74797065223a8152730101129b2b934b0b6111610113b30b63ab2911d160651b60208201529050613c4d613c3d6034830186613946565b637d5d207d60e01b815260040190565b9a9950505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251613c9381601d85016020870161313d565b91909101601d0192915050565b600082821015613cb257613cb261387f565b500390565b60008219821115613cca57613cca61387f565b500190565b84815260018060a01b0384166020820152826040820152608060608201526000613cfc6080830184613169565b9695505050505050565b600082613d1557613d156138b4565b500690565b600181815b80851115613d55578160001904821115613d3b57613d3b61387f565b80851615613d4857918102915b93841c9390800290613d1f565b509250929050565b600082613d6c57506001610a06565b81613d7957506000610a06565b8160018114613d8f5760028114613d9957613db5565b6001915050610a06565b60ff841115613daa57613daa61387f565b50506001821b610a06565b5060208310610133831016604e8410600b8410161715613dd8575081810a610a06565b613de28383613d1a565b8060001904821115613df657613df661387f565b029392505050565b60006131368383613d5d565b600060ff831680613e1d57613e1d6138b4565b8060ff84160491505092915050565b600060ff821660ff84168160ff0481118215151615613df657613df661387f565b600060ff821660ff841680821015613e6757613e6761387f565b90039392505050565b61060f60f31b815260008251613e8d81600285016020870161313d565b9190910160020192915050565b600060208284031215613eac57600080fd5b8151613136816134fc565b600060208284031215613ec957600080fd5b8151613136816135ce565b693d913730b6b2911d101160b11b81526000613ef3600a83018a613a77565b72111610113232b9b1b934b83a34b7b7111d101160691b81528851613f1f816013840160208d0161313d565b73222c2022636f6e74656e74223a202261723a2f2f60601b60139290910191820152613f4e6027820189613a77565b73222c2022696d616765223a2022697066733a2f2f60601b81529050613f776014820188613a77565b90507f222c202273656c6c65725f6665655f62617369735f706f696e7473223a20000081528551613faf81601e840160208a0161313d565b731610113332b2afb932b1b4b834b2b73a111d101160611b601e92909101918201528451613fe481603284016020890161313d565b61402861401a614014603284860101741116101132bc3a32b93730b62fb634b735911d101160591b815260150190565b87613946565b61227d60f01b815260020190565b9b9a5050505050505050505050565b60006020828403121561404957600080fd5b8151613136816131c1565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b600060ff821660ff84168060ff038211156140c3576140c361387f565b019392505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613cfc90830184613169565b60006020828403121561411057600080fd5b81516131368161310056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220d7e7496affe5f37b45f47bf801871236b411daebbe75a78465fc49260da82e4a64736f6c634300080c0033000000000000000000000000ae6fdda940155d090e3a3de9b090ad6a392f761a000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde600000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x60806040526004361061019c5760003560e01c8063715018a6116100ec578063ad768cb31161008a578063e6d283a611610064578063e6d283a6146104f4578063ed459df214610524578063f2fde38b14610544578063ffa1ad741461056457600080fd5b8063ad768cb31461048d578063bee0ec0b146104a0578063d784d426146104d457600080fd5b80638f32d59b116100c65780638f32d59b1461041a578063a56600631461043a578063a61788f31461045a578063ad3c6b611461047a57600080fd5b8063715018a6146103d057806379ba5097146103e55780638da5cb5b146103fa57600080fd5b80633644e515116101595780635c60da1b116101335780635c60da1b1461033d57806364d44b1e146103625780636f19d0b614610382578063705bf3681461039c57600080fd5b80633644e5151461029d5780633cb70c2d146102d15780635a5df2b71461031d57600080fd5b806311ba1741146101a15780631552a369146101e85780631a861d261461021857806323452b9c1461022e57806327ea6f2b14610245578063360d0fad14610265575b600080fd5b3480156101ad57600080fd5b506101d57f682b3920f0bf70eb759a59b34e1c6ff903edb5ced39efd66303d66cc0eac774e81565b6040519081526020015b60405180910390f35b3480156101f457600080fd5b506102086102033660046119e7565b6105aa565b60405190151581526020016101df565b34801561022457600080fd5b506101d560055481565b34801561023a57600080fd5b506102436105c5565b005b34801561025157600080fd5b50610243610260366004611a37565b61060a565b34801561027157600080fd5b50610285610280366004611a50565b6106c1565b6040516001600160a01b0390911681526020016101df565b3480156102a957600080fd5b506101d57faf7e1a4374d6ed205cea6893db2342a239d64b04ad26a4a7987f77492397780981565b3480156102dd57600080fd5b506103106040518060400160405280601381526020017268747470733a2f2f6d6972726f722e78797a2f60681b81525081565b6040516101df9190611ad8565b34801561032957600080fd5b50610285610338366004611cfd565b6106d7565b34801561034957600080fd5b506003546102859061010090046001600160a01b031681565b34801561036e57600080fd5b5061024361037d366004611d32565b6106f5565b34801561038e57600080fd5b506003546102089060ff1681565b3480156103a857600080fd5b506102857f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f81565b3480156103dc57600080fd5b506102436107ae565b3480156103f157600080fd5b506102436107e2565b34801561040657600080fd5b50600054610285906001600160a01b031681565b34801561042657600080fd5b506000546001600160a01b03163314610208565b34801561044657600080fd5b50610243610455366004611d5b565b610899565b34801561046657600080fd5b506101d5610475366004611d94565b610abe565b610285610488366004611de4565b610aca565b6101d561049b366004611e93565b610d53565b3480156104ac57600080fd5b506102857f000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde681565b3480156104e057600080fd5b506102436104ef366004611ef5565b610dcf565b34801561050057600080fd5b5061020861050f366004611a37565b60046020526000908152604090205460ff1681565b34801561053057600080fd5b506001546001600160a01b03163314610208565b34801561055057600080fd5b5061024361055f366004611ef5565b610eae565b34801561057057600080fd5b506105987f000000000000000000000000000000000000000000000000000000000000000181565b60405160ff90911681526020016101df565b60006105b98686868686610f50565b90505b95945050505050565b6000546001600160a01b031633146105f85760405162461bcd60e51b81526004016105ef90611f12565b60405180910390fd5b600180546001600160a01b0319169055565b6000546001600160a01b031633146106345760405162461bcd60e51b81526004016105ef90611f12565b600554604051639ea75f2760e01b81526004810191909152602481018290527f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f6001600160a01b031690639ea75f2790604401600060405180830381600087803b1580156106a157600080fd5b505af11580156106b5573d6000803e3d6000fd5b50505060059190915550565b60006106ce838330611099565b90505b92915050565b60006106d133836000604051806020016040528060008152506110f6565b6000546001600160a01b0316331461071f5760405162461bcd60e51b81526004016105ef90611f12565b6040516302f848e760e11b815281151560048201527f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f6001600160a01b0316906305f091ce90602401600060405180830381600087803b15801561078257600080fd5b505af1158015610796573d6000803e3d6000fd5b50506003805460ff1916931515939093179092555050565b6000546001600160a01b031633146107d85760405162461bcd60e51b81526004016105ef90611f12565b6107e0611412565b565b6001546001600160a01b031633146108515760405162461bcd60e51b815260206004820152602c60248201527f63757272656e74206f776e6572206d757374207365742063616c6c657220617360448201526b103732bc3a1037bbb732b91760a11b60648201526084016105ef565b600180546001600160a01b0319908116909155600080543392168217815560405182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3565b816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fb9190611f49565b6001600160a01b0316336001600160a01b03161461094a5760405162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b60448201526064016105ef565b600061095461145c565b6040516352ba8c2b60e11b81526001600160a01b0385811660048301529192507f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f8216916332c7791691869185169063a575185690602401602060405180830381865afa1580156109c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ed9190611f49565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015290821660248201529085166044820152606401600060405180830381600087803b158015610a3e57600080fd5b505af1158015610a52573d6000803e3d6000fd5b505060405163a566006360e01b81526001600160a01b03868116600483015285811660248301528416925063a56600639150604401600060405180830381600087803b158015610aa157600080fd5b505af1158015610ab5573d6000803e3d6000fd5b50505050505050565b60006106ce83836114e7565b6000600280541415610b1e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105ef565b6002805560a08701513414610b675760405162461bcd60e51b815260206004820152600f60248201526e696e636f72726563742076616c756560881b60448201526064016105ef565b6000610b7389896114e7565b60008181526004602052604090205490915060ff1615610cb357610be6600360019054906101000a90046001600160a01b03168a8a600001518b602001518c6101200151604051602001610bca9493929190611f66565b6040516020818303038152906040528051906020012030611099565b91506000826001600160a01b03163b11610c3a5760405162461bcd60e51b8152602060048201526015602482015274696e76616c696420636c6f6e65206164647265737360581b60448201526064016105ef565b6040516333f0ff8b60e21b81526001600160a01b0383169063cfc3fe2c903490610c6a9088908890600401611fae565b60206040518083038185885af1158015610c88573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cad9190611fd2565b50610d42565b6000818152600460205260409020805460ff19166001179055610cd98982898989610f50565b610d335760405162461bcd60e51b815260206004820152602560248201527f696e76616c6964206f7220756e61626c6520746f20766572696679207369676e604482015264617475726560d81b60648201526084016105ef565b610d3f898986866110f6565b91505b506001600255979650505050505050565b6000836001600160a01b031663cfc3fe2c3485856040518463ffffffff1660e01b8152600401610d84929190611fae565b60206040518083038185885af1158015610da2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610dc79190611fd2565b949350505050565b6000546001600160a01b03163314610df95760405162461bcd60e51b81526004016105ef90611f12565b6003546040516322fd9ed760e01b81526101009091046001600160a01b03908116600483015282811660248301527f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f16906322fd9ed790604401600060405180830381600087803b158015610e6d57600080fd5b505af1158015610e81573d6000803e3d6000fd5b5050600380546001600160a01b0390941661010002610100600160a81b0319909416939093179092555050565b6000546001600160a01b03163314610ed85760405162461bcd60e51b81526004016105ef90611f12565b6001600160a01b038116610f2e5760405162461bcd60e51b815260206004820152601f60248201527f4e657874206f776e657220697320746865207a65726f20616464726573732e0060448201526064016105ef565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038616610f9a5760405162461bcd60e51b815260206004820152600f60248201526e63616e6e6f742076616c696461746560881b60448201526064016105ef565b6001600160a01b0386163b1561107057604080516020810185905280820184905260f886901b6001600160f81b0319166060820152815160418183030181526061820192839052630b135d3f60e11b9092526001600160a01b03881690631626ba7e9061100d9089908590606501611feb565b602060405180830381865afa925050508015611046575060408051601f3d908101601f1916820190925261104391810190612004565b60015b6110545760009150506105bc565b6001600160e01b031916630b135d3f60e11b1491506105bc9050565b600061107e8686868661163f565b6001600160a01b039081169088161491505095945050505050565b60405172602d8060093d393df3363d3d373d3d3d363d7360681b8152606093841b60138201526f5af43d82803e903d91602b57fd5bf3ff60801b6027820152921b6037830152604b8201526036808220606b830152605591012090565b60e08301516000906001600160a01b031661114c5760405162461bcd60e51b81526020600482015260166024820152751b5d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b60448201526064016105ef565b6005541580611170575060008460c0015111801561117057506005548460c0015111155b6111ac5760405162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081b1a5b5a5d609a1b60448201526064016105ef565b60035484516020808701516101208801516040516111fe9561010090046001600160a01b0316946111e3948c949193919201611f66565b60405160208183030381529060405280519060200120611667565b9050600061120a61145c565b90506001600160a01b038116156113165760e0850151604051631963bc8b60e11b81526001600160a01b0384811660048301526000602483015291821660448201527f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f909116906332c7791690606401600060405180830381600087803b15801561129457600080fd5b505af11580156112a8573d6000803e3d6000fd5b5050505060e085015160405163a566006360e01b81526001600160a01b03848116600483015291821660248201529082169063a566006390604401600060405180830381600087803b1580156112fd57600080fd5b505af1158015611311573d6000803e3d6000fd5b505050505b60035460405163dbdc37f360e01b81526001600160a01b0384169163dbdc37f3913491611353918b918b918b918b9160ff9091169060040161202e565b6000604051808303818588803b15801561136c57600080fd5b505af1158015611380573d6000803e3d6000fd5b50506040516306e9fe9960e41b81526001600160a01b038a8116600483015286811660248301527f0000000000000000000000004c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f169350636e9fe99092506044019050600060405180830381600087803b1580156113f157600080fd5b505af1158015611405573d6000803e3d6000fd5b5050505050949350505050565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60007f000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde66001600160a01b031663d6811b6f6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156114be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e29190611f49565b905090565b60006106ce7faf7e1a4374d6ed205cea6893db2342a239d64b04ad26a4a7987f7749239778097f682b3920f0bf70eb759a59b34e1c6ff903edb5ced39efd66303d66cc0eac774e858560000151866020015187606001518860800151604051602001611556949392919061217d565b604051602081830303815290604052805190602001208660c001518760a001518860e001518961010001518a61012001518b61014001516040516020016115f3999897969594939291909889526001600160a01b0397881660208a0152604089019690965260608801949094526080870192909252841660a086015290921660c084015260e083019190915261ffff166101008201526101200190565b60408051601f19818403018152828252805160209182012061190160f01b8483015260228401949094526042808401949094528151808403909401845260629092019052815191012090565b600080600061165087878787611706565b9150915061165d816117f3565b5095945050505050565b600060405172602d8060093d393df3363d3d373d3d3d363d7360681b81528360601b60138201526e5af43d82803e903d91602b57fd5bf360881b6027820152826036826000f59150506001600160a01b0381166106d15760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c656400000000000000000060448201526064016105ef565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561173d57506000905060036117ea565b8460ff16601b1415801561175557508460ff16601c14155b1561176657506000905060046117ea565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156117ba573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166117e3576000600192509250506117ea565b9150600090505b94509492505050565b6000816004811115611807576118076121d4565b14156118105750565b6001816004811115611824576118246121d4565b14156118725760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105ef565b6002816004811115611886576118866121d4565b14156118d45760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105ef565b60038160048111156118e8576118e86121d4565b14156119415760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016105ef565b6004816004811115611955576119556121d4565b14156119ae5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016105ef565b50565b6001600160a01b03811681146119ae57600080fd5b80356119d1816119b1565b919050565b803560ff811681146119d157600080fd5b600080600080600060a086880312156119ff57600080fd5b8535611a0a816119b1565b945060208601359350611a1f604087016119d6565b94979396509394606081013594506080013592915050565b600060208284031215611a4957600080fd5b5035919050565b60008060408385031215611a6357600080fd5b8235611a6e816119b1565b946020939093013593505050565b60005b83811015611a97578181015183820152602001611a7f565b83811115611aa6576000848401525b50505050565b60008151808452611ac4816020860160208601611a7c565b601f01601f19169290920160200192915050565b6020815260006106ce6020830184611aac565b634e487b7160e01b600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715611b2557611b25611aeb565b60405290565b600082601f830112611b3c57600080fd5b813567ffffffffffffffff80821115611b5757611b57611aeb565b604051601f8301601f19908116603f01168101908282118183101715611b7f57611b7f611aeb565b81604052838152866020858801011115611b9857600080fd5b836020870160208301376000602085830101528094505050505092915050565b803561ffff811681146119d157600080fd5b60006101608284031215611bdd57600080fd5b611be5611b01565b9050813567ffffffffffffffff80821115611bff57600080fd5b611c0b85838601611b2b565b83526020840135915080821115611c2157600080fd5b611c2d85838601611b2b565b60208401526040840135915080821115611c4657600080fd5b611c5285838601611b2b565b60408401526060840135915080821115611c6b57600080fd5b611c7785838601611b2b565b60608401526080840135915080821115611c9057600080fd5b50611c9d84828501611b2b565b60808301525060a082013560a082015260c082013560c0820152611cc360e083016119c6565b60e0820152610100611cd68184016119c6565b908201526101208281013590820152610140611cf3818401611bb8565b9082015292915050565b600060208284031215611d0f57600080fd5b813567ffffffffffffffff811115611d2657600080fd5b610dc784828501611bca565b600060208284031215611d4457600080fd5b81358015158114611d5457600080fd5b9392505050565b60008060408385031215611d6e57600080fd5b8235611d79816119b1565b91506020830135611d89816119b1565b809150509250929050565b60008060408385031215611da757600080fd5b8235611db2816119b1565b9150602083013567ffffffffffffffff811115611dce57600080fd5b611dda85828601611bca565b9150509250929050565b600080600080600080600060e0888a031215611dff57600080fd5b8735611e0a816119b1565b9650602088013567ffffffffffffffff80821115611e2757600080fd5b611e338b838c01611bca565b9750611e4160408b016119d6565b965060608a0135955060808a0135945060a08a01359150611e61826119b1565b90925060c08901359080821115611e7757600080fd5b50611e848a828b01611b2b565b91505092959891949750929550565b600080600060608486031215611ea857600080fd5b8335611eb3816119b1565b92506020840135611ec3816119b1565b9150604084013567ffffffffffffffff811115611edf57600080fd5b611eeb86828701611b2b565b9150509250925092565b600060208284031215611f0757600080fd5b8135611d54816119b1565b60208082526018908201527f63616c6c6572206973206e6f7420746865206f776e65722e0000000000000000604082015260600190565b600060208284031215611f5b57600080fd5b8151611d54816119b1565b6001600160a01b0385168152608060208201819052600090611f8a90830186611aac565b8281036040840152611f9c8186611aac565b91505082606083015295945050505050565b6001600160a01b0383168152604060208201819052600090610dc790830184611aac565b600060208284031215611fe457600080fd5b5051919050565b828152604060208201526000610dc76040830184611aac565b60006020828403121561201657600080fd5b81516001600160e01b031981168114611d5457600080fd5b60018060a01b038616815260a06020820152600085516101608060a085015261205b610200850183611aac565b91506020880151609f19808685030160c08701526120798483611aac565b935060408a01519150808685030160e08701526120968483611aac565b935060608a015191506101008187860301818801526120b58584611aac565b945060808b015192506101208288870301818901526120d48685611aac565b955060a08c015193506101409250838389015260c08c01518589015260e08c0151945061210d6101808901866001600160a01b03169052565b908b01516001600160a01b03166101a08801528a01516101c087015289015161ffff81166101e087015291506121409050565b506001600160a01b038616604084015282810360608401526121628186611aac565b915050612173608083018415159052565b9695505050505050565b6000855161218f818460208a01611a7c565b8551908301906121a3818360208a01611a7c565b85519101906121b6818360208901611a7c565b84519101906121c9818360208801611a7c565b019695505050505050565b634e487b7160e01b600052602160045260246000fdfea264697066735822122039472762c33600bb9c364030aaf7e8f014d849edcb745dac6fcc79fe26f1adbf64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ae6fdda940155d090e3a3de9b090ad6a392f761a000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde600000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _owner (address): 0xae6FdDA940155D090E3A3DE9b090aD6A392F761a
Arg [1] : _treasuryConfiguration (address): 0x004D8438f4016A96F2D6dDc17808F4e40b47cdE6
Arg [2] : _maxLimit (uint256): 10000
Arg [3] : _guardOn (bool): True
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000ae6fdda940155d090e3a3de9b090ad6a392f761a
Arg [1] : 000000000000000000000000004d8438f4016a96f2d6ddc17808f4e40b47cde6
Arg [2] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000001
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.