Contract 0x1ad641eCdeaF065FaE8c7087AA121c3A569A29b7 1

 
Txn Hash Method
Index
From
To
Value
0x37dc6a00d0a3d4284b0a210ab01a12bef67c14c4b507decfb8e5335fd4ce2de9Set Approval For...262498292022-09-29 12:19:131 day 11 hrs ago0x1652c3a047c0d75733f71b82616b24b982b58fa0 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000393638330.00100155
0x28cd6860c88962664cc2b9387c57cdcfceae98d976f14ab490391d8ff3f64486Set Approval For...258342212022-09-27 21:18:083 days 2 hrs ago0x11b08b74dda1602fc9fb6810806636e4348022a2 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000494302120.00100155
0xf57a0580ccc4b5471fc15bebb4230310cf555c65d0406f42166e6c1205641d51Set Approval For...257018822022-09-27 6:52:113 days 16 hrs ago0xcbf5cf96fd7f2ac026bf35d6bb577c79e1ebb4a4 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000359323520.00100155
0x94968e372ea519dfba1de361c7281e9780273767916ba00f0d8b7853d2c6ce3fSet Approval For...253146282022-09-25 12:19:495 days 11 hrs ago0xc762b6fd63f4a6c66524819c262f76dcfd4a3821 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000287514760.00100155
0x0ee761502fd77cab2d0405ead4c74af75da1719ade28397fde32a3dac2b2a310Set Approval For...250482872022-09-24 7:02:126 days 16 hrs ago0xfc442dd2a1d1f61867406bbff682e33cb0da1ecc IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000169944230.00100155
0x56313d10aad35acf2e6c0945f1edc0bb39b11d96b8c9a918eb89a05433c91045Set Approval For...250317262022-09-24 5:15:376 days 18 hrs ago0xe6ec83200fa6f55a3ada624e074e599d74cffa86 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000181387690.00100155
0x620b574b09ebe6cdf19d67c90ee6bf4085309943d7f50d2ecde1788322bf34aaSet Approval For...247787292022-09-23 7:46:177 days 15 hrs ago0x96bf1fc0845fe80e2b64e6ac701469c7a452bbfd IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000177290270.00100155
0x622dff2c29d80bbdc485150bb66ef2c6db2237f9fa10722b8d58ca9afdbf2ba6Set Approval For...244987802022-09-22 9:04:348 days 14 hrs ago0x049bc926899b3c35ff3787865d5041aa1ec815c3 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000188827090.00100155
0x3a727640d7a28d33bd09821099ff4f159752f1e462ee7f148612ada543bb4fcaSet Approval For...244978672022-09-22 9:02:498 days 14 hrs ago0x84b387e46b6042e1e21ae490360fc157255af785 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000226109140.00100155
0x3436ffb1e6a143eac61f29caa676c784eca07434e2c11c3e495607c9416c826eSet Approval For...244963222022-09-22 8:57:348 days 14 hrs ago0xc2830346f90a8f191c1684f06060134b618f4f31 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000239582480.00100155
0xff32eebfdea03237fb7d83d753f87f7fae5a5f4aa6278e80942c762b0cd56c53Set Approval For...244959662022-09-22 8:56:048 days 14 hrs ago0xfbd9ad1cd896a366aa0c1c07299ba6372a1b614a IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000278988430.00100155
0x1ba46bbb3419c5e524b88d71e540c16c7aee3ef81262198b05f58adf5328e244Set Approval For...244954452022-09-22 8:53:498 days 14 hrs ago0x9cc31bf729d92b066f23c88ea8b8b3b60e572a33 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.000030266790.00100155
0x6fd66f6accf336b487f22c740f59b195926d1e24109c2d20f2adcbe8249cb5e8Set Approval For...244950402022-09-22 8:52:348 days 14 hrs ago0xdcaaab48c2909f7fcc0edf5d1ed8ba6fe839fc10 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000263750020.00100155
0x032baceec89b04c9dd55697f3e394dc9a273a35b43aefdd2ad8ea61a2a565675Set Approval For...244941672022-09-22 8:49:498 days 14 hrs ago0x7847cee2801c0647e9c762a3bd44ffe2164cf0fd IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000278702590.00100155
0x451cdcecda03024ac6ca05ad48a257a11ea85fa0c9cd1a6438ba3f28912a5e2cSet Approval For...244920402022-09-22 8:43:048 days 15 hrs ago0x172ccfa1484142356bc54edc7073b03eae10e2f6 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000166387070.00100155
0x9682f7151513bbf5f84740b679bad8df9a82f72ec2eabc26a429d58e491df3dfSet Approval For...244916372022-09-22 8:41:348 days 15 hrs ago0x301b1d29d164db632c30aead9354c3cb48d6f71d IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000166387070.00100155
0x23c226758b45074dcbaaf098ec431f3ffc28c81737595f82c25bb2189d622310Set Approval For...244904282022-09-22 8:37:188 days 15 hrs ago0xc6884e3f814c010b1e8fde4e479650f1f4c3101a IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000167284690.00100155
0xfb569c16896f0a299f163d2f1435225238fbb2b4ada16795c0b1dcab6ce34f9dSet Approval For...244899492022-09-22 8:35:488 days 15 hrs ago0x98ac2f6a0f3e2d4ca997c73df4f924b8829c6215 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000186685630.00100155
0x2c0c5cae3b8aae18033597f08a8e8a8f95bf6f402d8b895ee726817d5fc9cef9Set Approval For...244891852022-09-22 8:33:338 days 15 hrs ago0xeaa4047ff03c8dd2e501ba99d757beb575dd2aac IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000224813140.00100155
0xd73eb6dfaad35dcb7b1dde6bf687c91089bd4602a57eb849014e5102b43f34a4Set Approval For...244879862022-09-22 8:29:338 days 15 hrs ago0xe4d7030f0ad81ee8c157eba61526430b9a409297 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000227090490.00100155
0x329006d9dc670324260b11b374692144c3814dec4bc585bd112a70db7aefac56Set Approval For...244875342022-09-22 8:28:038 days 15 hrs ago0x056d6b0c371a05d309915fb746b7ad7bcf470135 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000204132720.00100155
0x6f9408011f44c83200093a1ab0248abb741e848328cd9efd83a5a76e9fc59699Set Approval For...241346862022-09-21 7:08:139 days 16 hrs ago0xbcc1916d128149f4f206a88fc2f3e11d6bc61534 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000184279720.001
0x0a0b8d992bdb501ea5ea2761968e3091440178dbb691e19da0f69ab352f2ffffSet Approval For...239592652022-09-20 15:07:3510 days 8 hrs ago0xf007de7228aaf2e7832af5c536ef30a103359aee IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000542193460.001
0x4b9f47113b31a66615ca93f83afa3543286cba16da3e7a0fa0ed5803313579a2Set Approval For...224502052022-09-09 2:14:3321 days 21 hrs ago0x836f5632768e988f8b978161815bbf6638c26c98 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000763644050.001
0xb4ad82a43b832bd4b68d0a1dacfac38cfbff57aff36556cee9bf8126ad99191aSafe Transfer Fr...189290582022-08-13 3:57:0848 days 19 hrs ago0x603f9f25ea89f465e36e2e9a9eb13289f0e7dae8 IN 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether0.0000373863810.001
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xc6ac294940a20dddb55164a395eb9c511718966c04638c0b58670deea71f8062265750102022-09-30 21:07:512 hrs 36 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0xc6ac294940a20dddb55164a395eb9c511718966c04638c0b58670deea71f8062265750102022-09-30 21:07:512 hrs 36 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xc6ac294940a20dddb55164a395eb9c511718966c04638c0b58670deea71f8062265750102022-09-30 21:07:512 hrs 36 mins ago 0xc78a09d6a4badecc7614a339fd264b7290361ef10x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0xc6ac294940a20dddb55164a395eb9c511718966c04638c0b58670deea71f8062265750102022-09-30 21:07:512 hrs 36 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0xc6ac294940a20dddb55164a395eb9c511718966c04638c0b58670deea71f8062265750102022-09-30 21:07:512 hrs 36 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xc6ac294940a20dddb55164a395eb9c511718966c04638c0b58670deea71f8062265750102022-09-30 21:07:512 hrs 36 mins ago 0x998ef16ea4111094eb5ee72fc2c6f4e6e86476660x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0x91d8daeb4e9328ac3a1c042e6a48ccd13511e6f50e5d4da99200f6fb05cd2383263980962022-09-30 5:59:5617 hrs 44 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0x91d8daeb4e9328ac3a1c042e6a48ccd13511e6f50e5d4da99200f6fb05cd2383263980962022-09-30 5:59:5617 hrs 44 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0x91d8daeb4e9328ac3a1c042e6a48ccd13511e6f50e5d4da99200f6fb05cd2383263980962022-09-30 5:59:5617 hrs 44 mins ago 0xc78a09d6a4badecc7614a339fd264b7290361ef10x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0x91d8daeb4e9328ac3a1c042e6a48ccd13511e6f50e5d4da99200f6fb05cd2383263980962022-09-30 5:59:5617 hrs 44 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0x91d8daeb4e9328ac3a1c042e6a48ccd13511e6f50e5d4da99200f6fb05cd2383263980962022-09-30 5:59:5617 hrs 44 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0x91d8daeb4e9328ac3a1c042e6a48ccd13511e6f50e5d4da99200f6fb05cd2383263980962022-09-30 5:59:5617 hrs 44 mins ago 0x998ef16ea4111094eb5ee72fc2c6f4e6e86476660x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0xd62eb975307a911c369ca70919d0bee33b4b41c2bd46fc366bfa3ffb694a9c4a263966672022-09-30 5:48:5017 hrs 55 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0xd62eb975307a911c369ca70919d0bee33b4b41c2bd46fc366bfa3ffb694a9c4a263966672022-09-30 5:48:5017 hrs 55 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xd62eb975307a911c369ca70919d0bee33b4b41c2bd46fc366bfa3ffb694a9c4a263966672022-09-30 5:48:5017 hrs 55 mins ago 0xc78a09d6a4badecc7614a339fd264b7290361ef10x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0xd62eb975307a911c369ca70919d0bee33b4b41c2bd46fc366bfa3ffb694a9c4a263966672022-09-30 5:48:5017 hrs 55 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0xd62eb975307a911c369ca70919d0bee33b4b41c2bd46fc366bfa3ffb694a9c4a263966672022-09-30 5:48:5017 hrs 55 mins ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xd62eb975307a911c369ca70919d0bee33b4b41c2bd46fc366bfa3ffb694a9c4a263966672022-09-30 5:48:5017 hrs 55 mins ago 0x998ef16ea4111094eb5ee72fc2c6f4e6e86476660x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0x37dc6a00d0a3d4284b0a210ab01a12bef67c14c4b507decfb8e5335fd4ce2de9262498292022-09-29 12:19:131 day 11 hrs ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xf176828b7fcdb4e763a0b20d630718c474311f8ffa8fa06b5277d0625a4ef78e261501952022-09-29 3:28:461 day 20 hrs ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0xf176828b7fcdb4e763a0b20d630718c474311f8ffa8fa06b5277d0625a4ef78e261501952022-09-29 3:28:461 day 20 hrs ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xf176828b7fcdb4e763a0b20d630718c474311f8ffa8fa06b5277d0625a4ef78e261501952022-09-29 3:28:461 day 20 hrs ago 0xc78a09d6a4badecc7614a339fd264b7290361ef10x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
0xf176828b7fcdb4e763a0b20d630718c474311f8ffa8fa06b5277d0625a4ef78e261501952022-09-29 3:28:461 day 20 hrs ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0x4c2393aae4f0ad55dfd4ddcfa192f817d1b28d1f0 Ether
0xf176828b7fcdb4e763a0b20d630718c474311f8ffa8fa06b5277d0625a4ef78e261501952022-09-29 3:28:461 day 20 hrs ago 0x1ad641ecdeaf065fae8c7087aa121c3a569a29b7 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a280 Ether
0xf176828b7fcdb4e763a0b20d630718c474311f8ffa8fa06b5277d0625a4ef78e261501952022-09-29 3:28:461 day 20 hrs ago 0x998ef16ea4111094eb5ee72fc2c6f4e6e86476660x1ad641ecdeaf065fae8c7087aa121c3a569a29b70 Ether
[ Download CSV Export 
Loading

Minimal Proxy Contract for 0xfd8077f228e5cd9ded1b558ac21f98ecf18f1a28

Contract Name:
WritingEditions

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
Decompile ByteCode

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 18 : WritingEditions.sol
// 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 = 101;

    /// > [[[[[[[[[[[ 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);

        // Store guard status.
        _setGuard(_guardOn);

        // Mint initial token to recipient, assuming
        // the correct value was sent through the factory
        if (tokenRecipient != address(0)) {
            _purchase(tokenRecipient, message);
        }
    }

    /// @notice Base description URI.
    function baseDescriptionURI()
        external
        view
        override
        returns (string memory)
    {
        return _getBaseDescriptionURI();
    }

    /// @notice Token description.
    function description() public view override returns (string memory) {
        return
            string(
                abi.encodePacked(
                    _getBaseDescriptionURI(),
                    Strings.toString(block.chainid),
                    "/",
                    _addressToString(address(this))
                )
            );
    }

    /// > [[[[[[[[[[[ View Functions ]]]]]]]]]]]

    /// @notice Helper function to get owners for a list of tokenIds.
    /// @dev Could revert if `tokenIds` is too long.
    /// @param tokenIds a list of token-ids to check ownership of.
    /// @return owners a list of token-id owners, address(0) if token is not minted
    function ownerOf(uint256[] memory tokenIds)
        external
        view
        override
        returns (address[] memory owners)
    {
        owners = new address[](tokenIds.length);

        for (uint256 i = 0; i < tokenIds.length; i++) {
            owners[i] = _owners[tokenIds[i]];
        }
    }

    /// > [[[[[[[[[[[ Funding Recipient ]]]]]]]]]]]

    /// @notice Set a new funding recipient.
    /// @param _fundingRecipient new funding recipient.
    function setFundingRecipient(address _fundingRecipient)
        external
        override
        onlyOwner
    {
        // slither-disable-next-line reentrancy-no-eth
        IObservability(o11y).emitFundingRecipientSet(
            // oldFundingRecipient
            fundingRecipient,
            // newFundingRecipient
            _fundingRecipient
        );

        fundingRecipient = _fundingRecipient;
    }

    /// > [[[[[[[[[[[ Price ]]]]]]]]]]]

    /// @notice Set a new price.
    /// @param _price new price.
    function setPrice(uint256 _price) external override onlyOwner {
        // slither-disable-next-line reentrancy-no-eth
        IObservability(o11y).emitPriceSet(
            // oldPrice
            price,
            // newPrice
            _price
        );

        price = _price;
    }

    /// @notice Set a new base description URI.
    /// @param newBaseDescriptionURI new base description URI
    function setBaseDescriptionURI(string memory newBaseDescriptionURI)
        external
        override
        onlyOwner
    {
        // slither-disable-next-line reentrancy-no-eth
        IObservability(o11y).emitBaseDescriptionURISet(
            // oldDescriptionURI
            _getBaseDescriptionURI(),
            // oldDescriptionURI
            newBaseDescriptionURI
        );

        _baseDescriptionURI = newBaseDescriptionURI;
    }

    /// @notice Turn Transaction Level Reentrancy Guard on/off.
    function toggleGuard() external override onlyOwner {
        _toggleGuard();
    }

    /// > [[[[[[[[[[[ Purchase ]]]]]]]]]]]

    /// @notice Purchase a token.
    /// @param tokenRecipient the account to receive the token.
    /// @param message an optional message during purchase, not stored.
    /// @return tokenId the id of the minted token.
    function purchase(address tokenRecipient, string memory message)
        external
        payable
        override
        guard
        nonReentrant
        returns (uint256 tokenId)
    {
        // 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": "',
                        _escapeQuotes(name),
                        " ",
                        Strings.toString(tokenId),
                        editionNumber,
                        '", "description": "',
                        _escapeQuotes(description()),
                        '", "content": "ar://',
                        contentURI,
                        '", "image": "ipfs://',
                        imageURI,
                        '", "attributes":[{ "trait_type": "Serial", "value": ',
                        Strings.toString(tokenId),
                        "}] }"
                    )
                )
            )
        );
        return string(abi.encodePacked("data:application/json;base64,", json));
    }

    /// > [[[[[[[[[[[ IERC165 Method ]]]]]]]]]]]

    /// @param interfaceId The interface identifier, as specified in ERC-165
    function supportsInterface(bytes4 interfaceId)
        public
        pure
        override
        returns (bool)
    {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            interfaceId == type(IERC165).interfaceId ||
            interfaceId == type(IERC2981).interfaceId;
    }

    /// > [[[[[[[[[[[ Internal Functions ]]]]]]]]]]]

    function _generateContractURI() internal view returns (string memory) {
        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "',
                        _escapeQuotes(name),
                        '", "description": "',
                        _escapeQuotes(description()),
                        '", "content": "ar://',
                        contentURI,
                        '", "image": "ipfs://',
                        imageURI,
                        '", "seller_fee_basis_points": ',
                        Strings.toString(_royaltyBPS()),
                        ', "fee_recipient": "',
                        _addressToString(_royaltyRecipient()),
                        '", "external_link": "',
                        _getBaseDescriptionURI(),
                        '"}'
                    )
                )
            )
        );

        return string(abi.encodePacked("data:application/json;base64,", json));
    }

    /// @dev Emit a transfer event from observability contract.
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        IObservability(o11y).emitTransferEvent(from, to, tokenId);
    }

    function _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);
    }

    function _escapeQuotes(string memory str)
        internal
        pure
        returns (string memory)
    {
        bytes memory strBytes = bytes(str);
        uint8 quotesCount = 0;
        for (uint8 i = 0; i < strBytes.length; i++) {
            if (strBytes[i] == '"') {
                quotesCount++;
            }
        }
        if (quotesCount > 0) {
            bytes memory escapedBytes = new bytes(
                strBytes.length + (quotesCount)
            );
            uint256 index;
            for (uint8 i = 0; i < strBytes.length; i++) {
                if (strBytes[i] == '"') {
                    escapedBytes[index++] = "\\";
                }
                escapedBytes[index++] = strBytes[i];
            }
            return string(escapedBytes);
        }
        return str;
    }
}

File 2 of 18 : IWritingEditions.sol
// 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);
}

File 3 of 18 : IWritingEditionsFactory.sol
// 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);
}

File 4 of 18 : IObservability.sol
// 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;
}

File 5 of 18 : IFeeConfiguration.sol
// 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);
}

File 6 of 18 : IRenderer.sol
// 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);
}

File 7 of 18 : ITreasuryConfiguration.sol
// 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;
}

File 8 of 18 : ITreasury.sol
// 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;
}

File 9 of 18 : ITributaryRegistry.sol
// 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;
}

File 10 of 18 : Ownable.sol
// 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);
    }
}

File 11 of 18 : ERC721.sol
// 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 {}
}

File 12 of 18 : ERC165.sol
// 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;
    }
}

File 13 of 18 : IERC721.sol
// 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);
}

File 14 of 18 : IERC2981.sol
// 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);
}

File 15 of 18 : TransactionReentrancyGuard.sol
// 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;
    }
}

File 16 of 18 : ReentrancyGuard.sol
// 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;
    }
}

File 17 of 18 : Base64.sol
// 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;
    }
}

File 18 of 18 : Strings.sol
// 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);
    }
}

Settings
{
  "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 ABI

[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_treasuryConfiguration","type":"address"},{"internalType":"address","name":"_o11y","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"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":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":"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":false,"internalType":"uint256","name":"price","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":"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":"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":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"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":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":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseDescriptionURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contentURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundingRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardOn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"imageURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","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":"address","name":"tokenRecipient","type":"address"},{"internalType":"string","name":"message","type":"string"},{"internalType":"bool","name":"_guardOn","type":"bool"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenRecipient","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"ownerOf","outputs":[{"internalType":"address[]","name":"owners","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenRecipient","type":"address"},{"internalType":"string","name":"message","type":"string"}],"name":"purchase","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"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":"renderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"royaltyBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"royaltyRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newBaseDescriptionURI","type":"string"}],"name":"setBaseDescriptionURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fundingRecipient","type":"address"}],"name":"setFundingRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setMaxLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_renderer","type":"address"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"royaltyRecipient_","type":"address"},{"internalType":"uint256","name":"royaltyBPS_","type":"uint256"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleGuard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","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"}]

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.