ETH Price: $2,870.34 (-2.67%)
 

Overview

Max Total Supply

200,000,000 LOUDER

Holders

85,651 (0.00%)

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Filtered by Token Holder
galaxzy.base.eth
Balance
130.35 LOUDER

Value
$0.00
0x54503eEdEd1fC55B94330Bf82092aD41A76A8683
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Louder is the first meme artist on Base. It is also one of the first 404's on BASE. Louder is connected to an album of songs developed by grammy award winning producers in collaboration with AI. Owning 10,000 LOUDER tokens allows you to unlock SUPALOUDS which represent LOUDER songs.

Contract Source Code Verified (Exact Match)

Contract Name:
Louder

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 100 runs

Other Settings:
paris EvmVersion
File 1 of 11 : Louder.sol
// SPDX-License-Identifier: MIT

// @title: Louder
// // @author: Humie Devs
// @+---*@          @@@@@@@@@@@@@    @*---+@ @=--+@ @+-----=*@@    @=--------=@ @#------=#@    @%===#@
// %-----@    @@#+--=+*#######*+=--+#@=----%@+----#@#---------=@  @*----------+@@=---------*@  @-----%
// %-----@  @*-=@@@               @@@+-*+--%@+----#@#----------=@ @*----------+@@=----------#@ @-----%
// %-----@ @==@                      @*==+-%@+----#@#-----------%@@*----------+@@=-----------@ @-----%
// %-----@ @+=@                      @%-#=-%@+----#@#------------@@*----------+@@=-----------% @=----%
// %-----@  @@--+@@              @@%=-+%---%@+----#@#------------@@*----------+@@=-----------#@@=----%
// %-----@     @@#+=-------------=+@@@-----%@+----#@#----=@@-----@@*-----%@@@@  @=----#@=----*@@=----%
// %-----@       @%*#%@@@@@@@@@%#*%@ @-----%@+----#@#----=@@-----%@*----=@      @=----#@=----*@@=----@
// %-----@       ##@             @## @-----%@+----#@#----=@@-----%@*------===*@ @=----#@=----*@@=----@
// %-----@       @##@@@      @@@@##@ @-----%@+----#@#----=@@-----%@*----------# @=----#@-----*@@=----@
// %-----@        @@%#***###**##%@@  @-----%@+----#@#----=@@-----%@*----------# @=-----------# @=----@
// %-----@          @*#@@   @@#*@    @-----%@+----#@#----=@@-----%@*----------# @=-----------% @=----@
// %-----@          @**#%@@@%#**@    @-----%@+----#@#----=@@-----%@*----------# @=----------+@ @=----@
// %-----@            @@%%%%@@@      @-----%@+----#@#----=@@-----%@*---------=@ @=----------@   %---#@
// %-----@           @@@@%%%@@@@     @-----%@+----#@#----=@@-----%@*-----@      @=----------#@        
// %-----#@@@@   @@+*%#=-::::=*##+%@ @-----%@+----#@#----=@@-----%@*-----@      @=----%#----*@ @%***#@
// %----------+@ ##-:--=%***%=--::#+ @-----*@=----#@#-----#=-----@@*----------# @=----#@----=@ @-----%
// %----------=@ %-##-::+%@%+::-##-* @=-----------#@#------------@@*----------+@@=----#@-----@ @-----%
// %----------=@  @%+---=====---+%@  @+-----------@@#-----------+@@*----------+@@=----#@=----% @-----%
// %----------=@     @=--------@      #----------=@@#-----------@ @*----------+@@=----#@=----% @-----%
// %----------=@     @+-------=@      @=---------@ @#----------*@ @*----------+@@=----#@=----# @-----%
// %----------=@      @=------#        @--------%@ @%---------%@  @*----------+@@=----%@+----*@@-----%
//  @@@@@@@@@@@         @@@@@@          @@+--=%@     @@@@@@@@      @@@@@@@@@@@@  @@@@@  @@@@@@  @@@@@ 

pragma solidity ^0.8.4;

import {DN404} from "./DN404.sol";
import {DN404Mirror} from "./DN404Mirror.sol";

import "./Adminable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/*                         STRUCTS                            */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/


/// Everything required for construction.
/// @param name The Token name.
/// @param symbol The Token symbol.
/// @param admin The initial admin address (onchain administration).
/// @param owner The initial owner address (offchain administration).
/// @param lpTokenReserve The initial address for the Liquidity Pool Token Reserve
/// @param teamReserve The initial address for the Team Token Reserve
struct ConstructorConfig {
    string name;
    string symbol;
    address admin;
    address owner;
    address lpTokenReserve;
    address teamReserve;
}

/// Struct to store per-drop variables
/// @param price Price of the drop.
/// @param supply Supply of the drop.
struct DropStorage {
    uint256 price;
    uint256 supply;
}

struct TransferTo {
    uint256 amount;
    address to;
}

/**
 * @title Louder
 * @notice Music 404 NFT 
 * When a user has at least one base unit (10000) amount of tokens, they will automatically receive an NFT.
 * NFTs are minted as an address accumulates each base unit amount of tokens.
 */
contract Louder is DN404, Ownable, Adminable {

    using Address for address payable;
    using Math for uint256;

    /// Max coin Supply - 1 billion coins
    uint256 public MAX_COIN_SUPPLY = 1_000_000_000 * 10 ** 18;

    string private _name;
    string private _symbol;
    string private _baseURI;
    bool private _lockTransfers;
    bool private _unlockTransfersForever = false;
    uint8 private _dropIndex = 0;
    address public _lpTokenReserve;
    address public _teamReserve;

    /// @dev tracks the state of the contract
    enum State {
        Setup,
        Presale,
        Open
    }

    /// @dev set by admin and read by minting methods
    State private _state;

    /// @dev drop storage mapping per drop
    mapping(uint8 => DropStorage) public dropData;
    
    /// @dev canAlwaysTransfer mapping per address
    /// Certain wallets (e.g.: liquidity providers) will be allowed to transfer coins while transfer are locked
    mapping(address => bool) private canAlwaysTransfer;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                            EVENTS                          */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// Token constructor.
    /// Assigns owner and admin roles,
    /// and mints initial tokens for the admin
    /// @param config_ All construction config.
    constructor(ConstructorConfig memory config_) 
    Ownable(config_.owner)
    {
        // Enter setup
        _state = State.Setup;

        // Setup roles
        _transferAdmin(config_.admin);
        _transferOwnership(config_.owner);

        _name = config_.name;
        _symbol = config_.symbol;

        // lock transfers as presale has not opened yet
        _lockTransfers = true;
        _unlockTransfersForever = false;

        // Admin can always transfer even when transfers are locked
        canAlwaysTransfer[config_.admin] = true;

        // set the Liquidity Pool Token Reserve address
        _setLpTokenReserve(config_.lpTokenReserve);

        // set the Louder Team Reserve address
        _setTeamReserve(config_.teamReserve);

        address mirror = address(new DN404Mirror(msg.sender));
        _initializeDN404(0, config_.admin, mirror);
        _setSkipNFT(config_.admin, true);

        // Mint 10M coins to the team address
        _mint(_teamReserve, 10_000_000 * 10 ** 18);
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*               OVERRIDEN DN404 FUNCTIONS                    */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @inheritdoc DN404
    function name() public view override returns (string memory) {
        return _name;
    }

    /// @inheritdoc DN404
    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    /// @inheritdoc DN404
    function _tokenURI(uint256 tokenId) internal view override returns (string memory result) {
        if (bytes(_baseURI).length != 0) {
            result = string(abi.encodePacked(_baseURI, Strings.toString(tokenId)));
        }
    }

    /// @inheritdoc DN404
    function _addToBurnedPool(uint256 totalNFTSupplyAfterBurn, uint256 totalSupplyAfterBurn)
        internal
        pure
        override
        returns (bool)
    {
        // Silence unused variable compiler warning.
        totalSupplyAfterBurn = totalNFTSupplyAfterBurn;
        // Louder uses the burn pool in a strict manner to accomodate the drops logic - always true
        return true;
    }

     /// @inheritdoc DN404
    function _useExistsLookup() internal pure override returns (bool) {
        return false;
    }

    /// @inheritdoc DN404
    function _unit() internal pure override returns (uint256) {
        // 1 NFT = 1 base unit of coins = 10.000 coins 
        return 10_000 * 10 ** 18;
    }

    /// @inheritdoc DN404
    function _mint(address to, uint256 amount) internal override {
        /// Overriden mint method to always mint new NFTs and not recycle the burn pool
        /// Restrict recycling NFTs from the burn pool only for transfers 
    
        if (to == address(0)) revert TransferToZeroAddress();

        DN404Storage storage $ = _getDN404Storage();
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();
        AddressData storage toAddressData = $.addressData[to];

        uint256 newTotalSupply = uint256($.totalSupply) + amount;
        require(newTotalSupply <= MAX_COIN_SUPPLY, "Total supply of coins can not exceed 1 billion");

        _DNMintTemps memory t;
        unchecked {
            {
                uint256 toBalance = uint256(toAddressData.balance) + amount;
                toAddressData.balance = uint96(toBalance);
                t.toEnd = toBalance / _unit();
            }
            uint256 maxId;
            {
                $.totalSupply = uint96(newTotalSupply);
                uint256 overflows = _toUint(_totalSupplyOverflows(newTotalSupply));
                if (overflows | _toUint(newTotalSupply < amount) != 0) revert TotalSupplyOverflow();
                maxId = newTotalSupply / _unit();
            }
            while (!getSkipNFT(to)) {
                Uint32Map storage toOwned = $.owned[to];
                Uint32Map storage oo = $.oo;
                uint256 toIndex = toAddressData.ownedLength;
                if ((t.numNFTMints = _zeroFloorSub(t.toEnd, toIndex)) == uint256(0)) break;

                t.packedLogs = _packedLogsMalloc(t.numNFTMints);
                _packedLogsSet(t.packedLogs, to, 0);
                $.totalNFTSupply += uint32(t.numNFTMints);
                toAddressData.ownedLength = uint32(t.toEnd);
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                t.nextTokenId = _wrapNFTId($.nextTokenId, maxId);
                // Mint loop.
                do {
                    uint256 id;
                    id = t.nextTokenId;
                    while (_get(oo, _ownershipIndex(id)) != 0) {
                        id = _useExistsLookup()
                            ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId), maxId)
                            : _wrapNFTId(id + 1, maxId);
                    }
                    t.nextTokenId = _wrapNFTId(id + 1, maxId);
                    if (_useExistsLookup()) _set($.exists, id, true);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));
                    _packedLogsAppend(t.packedLogs, id);
                } while (toIndex != t.toEnd);

                $.nextTokenId = uint32(t.nextTokenId);
                _packedLogsSend(t.packedLogs, $);
                break;
            }
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)))
        }
        if (_useAfterNFTTransfers()) {
            _afterNFTTransfers(
                _zeroAddresses(t.numNFTMints),
                _filled(t.numNFTMints, to),
                _packedLogsIds(t.packedLogs)
            );
        }
    }

    /// @inheritdoc DN404
    function _transfer(address from, address to, uint256 amount) internal virtual override {
        if (to == address(0)) revert TransferToZeroAddress();

        DN404Storage storage $ = _getDN404Storage();
        AddressData storage fromAddressData = $.addressData[from];
        AddressData storage toAddressData = $.addressData[to];
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();

        _DNTransferTemps memory t;
        t.fromOwnedLength = fromAddressData.ownedLength;
        t.toOwnedLength = toAddressData.ownedLength;

        unchecked {
            {
                uint256 fromBalance = fromAddressData.balance;
                if (amount > fromBalance) revert InsufficientBalance();
                fromAddressData.balance = uint96(fromBalance -= amount);

                uint256 toBalance = uint256(toAddressData.balance) + amount;
                toAddressData.balance = uint96(toBalance);
                t.numNFTBurns = _zeroFloorSub(t.fromOwnedLength, fromBalance / _unit());

                if (!getSkipNFT(to)) {
                    if (from == to) t.toOwnedLength = t.fromOwnedLength - t.numNFTBurns;
                    t.numNFTMints = _zeroFloorSub(toBalance / _unit(), t.toOwnedLength);
                }
            }

            while (_useDirectTransfersIfPossible()) {
                uint256 n = _min(t.fromOwnedLength, _min(t.numNFTBurns, t.numNFTMints));
                if (n == uint256(0)) break;
                t.numNFTBurns -= n;
                t.numNFTMints -= n;
                if (from == to) {
                    t.toOwnedLength += n;
                    break;
                }
                t.directLogs = _directLogsMalloc(n, from, to);
                Uint32Map storage fromOwned = $.owned[from];
                Uint32Map storage toOwned = $.owned[to];
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                uint256 toIndex = t.toOwnedLength;
                n = toIndex + n;
                // Direct transfer loop.
                do {
                    uint256 id = _get(fromOwned, --t.fromOwnedLength);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex($.oo, id, t.toAlias, uint32(toIndex));
                    _directLogsAppend(t.directLogs, id);
                    if (_get($.mayHaveNFTApproval, id)) {
                        _set($.mayHaveNFTApproval, id, false);
                        delete $.nftApprovals[id];
                    }
                } while (++toIndex != n);

                toAddressData.ownedLength = uint32(t.toOwnedLength = toIndex);
                fromAddressData.ownedLength = uint32(t.fromOwnedLength);
                break;
            }

            t.totalNFTSupply = uint256($.totalNFTSupply) + t.numNFTMints - t.numNFTBurns;
            $.totalNFTSupply = uint32(t.totalNFTSupply);

            Uint32Map storage oo = $.oo;
            t.packedLogs = _packedLogsMalloc(t.numNFTBurns + t.numNFTMints);

            t.burnedPoolTail = $.burnedPoolTail;
            if (t.numNFTBurns != 0) {
                _packedLogsSet(t.packedLogs, from, 1);
                bool addToBurnedPool = _addToBurnedPool(t.totalNFTSupply, $.totalSupply);
                Uint32Map storage fromOwned = $.owned[from];
                uint256 fromIndex = t.fromOwnedLength;
                fromAddressData.ownedLength = uint32(t.fromEnd = fromIndex - t.numNFTBurns);
                uint32 burnedPoolTail = t.burnedPoolTail;
                // Burn loop.
                do {
                    uint256 id = _get(fromOwned, --fromIndex);
                    _setOwnerAliasAndOwnedIndex(oo, id, 0, 0);
                    _packedLogsAppend(t.packedLogs, id);
                    if (_useExistsLookup()) _set($.exists, id, false);
                    if (addToBurnedPool) _set($.burnedPool, burnedPoolTail++, uint32(id));
                    if (_get($.mayHaveNFTApproval, id)) {
                        _set($.mayHaveNFTApproval, id, false);
                        delete $.nftApprovals[id];
                    }
                } while (fromIndex != t.fromEnd);

                if (addToBurnedPool) $.burnedPoolTail = (t.burnedPoolTail = burnedPoolTail);
            }

            if (t.numNFTMints != 0) {
                _packedLogsSet(t.packedLogs, to, 0);
                Uint32Map storage toOwned = $.owned[to];
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                uint256 maxId = $.totalSupply / _unit();
                t.nextTokenId = $.nextTokenId;
                uint256 toIndex = t.toOwnedLength;
                toAddressData.ownedLength = uint32(t.toEnd = toIndex + t.numNFTMints);
                uint32 burnedPoolHead = $.burnedPoolHead;
                // Mint loop.
                do {
                    uint256 id;
                    if (burnedPoolHead != t.burnedPoolTail) {
                        id = _get($.burnedPool, burnedPoolHead++);
                    } else {
                        // MOVED IN LOOP FROM OUT OF LOOP
                        // t.nextTokenId = _wrapNFTId($.nextTokenId, maxId);

                        id = t.nextTokenId;
                        while (_get(oo, _ownershipIndex(id)) != 0) {
                            id = _useExistsLookup()
                                ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId), maxId)
                                : _wrapNFTId(id + 1, maxId);
                        }
                        t.nextTokenId = _wrapNFTId(id + 1, maxId);
                        
                        // MOVED IN LOOP FROM OUT OF LOOP
                        // $.nextTokenId = uint32(t.nextTokenId);
                    }
                    if (_useExistsLookup()) _set($.exists, id, true);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));
                    _packedLogsAppend(t.packedLogs, id);
                } while (toIndex != t.toEnd);

                $.burnedPoolHead = burnedPoolHead;
                $.nextTokenId = uint32(t.nextTokenId);
            }

            if (t.directLogs != bytes32(0)) _directLogsSend(t.directLogs, $);
            if (t.packedLogs != bytes32(0)) _packedLogsSend(t.packedLogs, $);
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), shr(96, shl(96, to)))
        }
        if (_useAfterNFTTransfers()) {
            uint256[] memory ids = _directLogsIds(t.directLogs);
            unchecked {
                _afterNFTTransfers(
                    _concat(
                        _filled(ids.length + t.numNFTBurns, from), _zeroAddresses(t.numNFTMints)
                    ),
                    _concat(
                        _concat(_filled(ids.length, to), _zeroAddresses(t.numNFTBurns)),
                        _filled(t.numNFTMints, to)
                    ),
                    _concat(ids, _packedLogsIds(t.packedLogs))
                );
            }
        }
    }

    /// @inheritdoc DN404
    function transfer(address to, uint256 amount) public override returns (bool) {
        // the transfer will initiate only if transfers are not locked or if sender can always transfer
        require((!_lockTransfers || canAlwaysTransfer[msg.sender]) , "Transfers are currently locked.");

        return super.transfer(to, amount);
    }

    /// @inheritdoc DN404
    function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
        // the transfer will initiate only if transfers are not locked or if sender can always transfer
        require((!_lockTransfers || canAlwaysTransfer[from]) , "Transfers are currently locked.");

        return super.transferFrom(from, to, amount);
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                    LOUDER FUNCTIONS                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// Admin MAY mint more tokens to a wallet
    function mintTo(address to, uint256 amount) external onlyAdmin {
        _mint(to, amount);
    }

    /// Admin MAY set a new baseURI
    function setBaseURI(string calldata baseURI_) external onlyAdmin {
        _baseURI = baseURI_;
    }

    /// Optimistically transfer many tokens to many EOA
    /// (Externally Owned Account) recipients.
    /// @param transfers_ List of ids and recipients to transfer to.
    function multiTransferToEOA(TransferTo[] calldata transfers_) external {
        address to_;
        uint256 amount_;
        for (uint256 i_ = 0; i_ < transfers_.length; i_++) {
            to_ = transfers_[i_].to;
            amount_ = transfers_[i_].amount;
            // Skip transfer if recipient is smart contract
            if (to_.code.length == 0) {
                transfer(to_, amount_);
            }
        }
    }

    /// Admin WILL manually progress the state of the contract
    /// @param state_ The new state
    function adminChangeState(State state_) external onlyAdmin {
        _state = state_;
    }

    /// @return current contract state
    function currentState() public view returns (State) {
        return _state;
    }

    /// @return current contract drop as uint8
    function currentDrop() public view returns (uint8) {
        return _dropIndex;
    }

    /// @return State as uint8
    function valueOfState(State state_) internal pure returns (uint8) {
        return uint8(state_);
    }

    /// @return current coin price
    function getPrice() public view returns (uint256) {
        return dropData[currentDrop()].price;
    }

    /// @return owned NFT Ids by wallet
    /// If the adress holds more than 35k NFTs this tx will likely run out of gas
    function getOwnedNFTs(address address_) public view returns (uint256[] memory) {
        DN404Storage storage $ = _getDN404Storage();
        
        uint256 zeroIndex = 0;
        uint256 ownedIndex = $.addressData[address_].ownedLength;

        return _ownedIds(address_, zeroIndex, ownedIndex);
    }

    /// Presale minting function
    /// Allows minting only of the current PreSale state
    /// @param quantity amount of tokens to mint in $louder, not decimals
    /// @param drop_ For which Drop the minting is targeted at (optional validation - passed from the FE)
    function mintPresale(uint64 quantity, uint8 drop_) public payable {
        // Are we on that Presale?
        require(currentState() != State.Setup, "Presale hasn't started yet");
        require(currentState() != State.Open, "Presale has ended");
        require(currentDrop() == drop_, "Wrong presale stage selected"); // optional
        // Require at least 1 coin to be minted
        require(quantity != 0, "Can't mint 0 coins");

        // Calculate full uint256 token quantity 
        uint256 tokenQuantity = uint256(quantity) * 10 ** 18;
        // Mint should not exceed drop supply cap
        DN404Storage storage $ = _getDN404Storage();
        uint256 newTotalSupply = uint256($.totalSupply) + tokenQuantity;
        require(newTotalSupply <= dropData[currentDrop()].supply, "Not enough coins left");

        // Pay the right price 
        (bool mulOverflow, uint256 mulResult) = uint256(dropData[currentDrop()].price).tryMul(quantity);
        assert(mulOverflow);
        require(mulResult <= msg.value, "Not enough ETH sent");

        // Mint tokens to Sender
        _mint(msg.sender, tokenQuantity);
    }

    /// Admin WILL manually start drops to begin each presale
    /// @param price Price per token for the new drop
    /// @param dropSupply Total supply for the new drop
    function startDrop(uint256 price, uint256 dropSupply) external onlyAdmin {
        require(currentState() != State.Presale, "A drop is already active");

        // increment the current drop index
        _dropIndex++;

        // making sure total supply can not exceed maximum coin supply
        uint256 newTotalSupply = dropSupply + dropData[_dropIndex-1].supply;
        require( newTotalSupply <= MAX_COIN_SUPPLY, "Total supply cannot exceed 1 billion coins");

        // require at least unit() worth of supply
        uint256 dropNFTAmount = dropSupply / _unit();
        require(dropNFTAmount > 0, "Drop supply too low, need at least 1 NFT worth of coins");

        // set the drop's data
        DropStorage storage newDrop = dropData[_dropIndex];
        newDrop.price = price;
        newDrop.supply = newTotalSupply;

        // Mint to LP wallet 20% of the new supply
        (bool divOverflow, uint256 coinsToMint) = dropSupply.tryDiv(5);
        assert(divOverflow);
        _mint(_lpTokenReserve, coinsToMint);

        // Mint to Team Reserve wallet 15% of the new supply
        (bool mulOverflow, uint256 mulResult) = dropSupply.tryMul(3);
        assert(mulOverflow);
        (divOverflow, coinsToMint) = mulResult.tryDiv(20);
        assert(divOverflow);
        _mint(_teamReserve, coinsToMint);

        // set the State to Presale
        _state = State.Presale;
    }

    /// Admin WILL manually end drops when each presale ends
    /// When the drop ends, we check if there is any remaining coins & NFTs
    /// Remaining NFTs are added to the burned pool to be later recycled to users who get coins via transfers
    /// Remaining coins are minted to the admin address, which can later send them to liquidity providers
    /// When the drop ends, the contract state is set to Open
    function endDrop() external onlyAdmin {
        // Are we on that Drop?
        require(currentState() != State.Setup, "No active Drops");
        require(currentState() != State.Open, "Drop has already ended");

        DN404Storage storage $ = _getDN404Storage();
        
        // NFT ID to start adding to the burn pool
        uint32 id = uint32($.nextTokenId);


        uint256 dropSupply = dropData[currentDrop()].supply;
        uint256 dropMaxId = dropSupply / _unit();
        uint32 quantityToBurn = uint32(dropMaxId) - id;
        _addNFTsToBurnPool(quantityToBurn);

        // minting the remaining coins of the current drop to the admin address
        // dropSupply can't be less or equal to the totalSupply
        // as then we would be trying to mint 0 or negative amount of coins
        if (dropSupply > $.totalSupply){
            uint256 coinsToMint = dropSupply - $.totalSupply;
            _mint(msg.sender, coinsToMint);
        }

        // starting the next drop
        _state = State.Open;
    }

    /// Admin MAY  manually add NFTs to the burn pool before ending a Presale
    /// @param quantity How many NFTs should be added to the burned pool
    function adminAddToBurnPool(uint32 quantity) external onlyAdmin {
        _addNFTsToBurnPool(quantity);
    }

    /// Admin MAY  manually add NFTs to the burn pool before ending a Presale
    /// @param quantity How many NFTs should be added to the burned pool
    /// Adds a certain quantity of the current drop's IDs to the burned pool
    /// Loops over the quantity of IDs to set the values on the burnedPool storage map
    /// Sets burndPoolTail & nextTokenId to the values they have acquired after looping
    function _addNFTsToBurnPool(uint32 quantity) internal {
        // Are we on a Presale?
        require(currentState() == State.Presale, "No active Drops");

        DN404Storage storage $ = _getDN404Storage();
        // Max NFT ID for this drop
        uint256 dropSupply = dropData[currentDrop()].supply;
        uint256 dropMaxId = dropSupply / _unit();
        // NFT ID to start adding to the burn pool
        uint32 id = uint32($.nextTokenId);
        // Last NFT ID to burn
        uint32 targetBurnMaxId = id + quantity;
        require(targetBurnMaxId <= dropMaxId, "Can't add that many NFTs to burn pool for this drop");

        // Adding to burn pool
        uint32 burnedPoolTail = $.burnedPoolTail;
        do{
            _set($.burnedPool, burnedPoolTail++, id++);
        } while (id <= targetBurnMaxId);
        $.burnedPoolTail = burnedPoolTail;
        
        // setting the nextTokenId to the last NFT added to the burned pool to prepare the next NFT ID that will be MINTED
        $.nextTokenId = id;
    }

    /// Admin MAY manually change the price of the coin for the current drop
    /// @param price_ The new price in gwei
    /// @param drop_ The drop to apply the change
    function adminChangePrice(uint256 price_, uint8 drop_) external onlyAdmin {
        dropData[drop_].price = price_ * 1 gwei;
    }

    /// Admin WILL manually lock (or unlock) the ability to transfer coins before (or during) presale period.
    function changeLockState(bool lock_) external onlyAdmin {
        require((!_unlockTransfersForever), "Transfers can not be locked again, once they have been unlocked forever");

        _lockTransfers = lock_;
    }

    /// Admin WILL manually unlock the ability to transfer coins forever.
    function unlockForever() external onlyAdmin {
        _lockTransfers = false;
        _unlockTransfersForever = true;
    }

    /// get the drop supply for a specific drop
    /// @param drop_ The drop in question
    function getDropSupply(uint8 drop_) public view returns (uint256) {
        return dropData[drop_].supply;
    }

    /// Admin MAY set/change the ability of a wallet to transfer coins while transfers are locked
    /// @param _address The address to be changed.
    /// @param _canTransfer Boolean depicting whether _address will be able to transfer coins 
    /// even while transfers are locked.
    /// This ensures that wallets will be able to get coins through the liquidity providers.
    function setCanAlwaysTransfer(address _address, bool _canTransfer) external onlyAdmin {
        // addresses that can always transfer funds are considered liquidity providers
        canAlwaysTransfer[_address] = _canTransfer;
    }

    /// Admin MAY set/change the ability of a wallet to receive NFTs
    /// @param _address The address to be changed.
    /// @param _skipNFT Boolean depicting whether _address should receive NFTs 
    /// when it acquires unit() worth of coins.
    /// LP Token Reserve & Team Reserve can not be able to receive NFTs
    function adminSetSkipNFT(address _address, bool _skipNFT) external onlyAdmin {
        require((_address == _lpTokenReserve && _skipNFT == false), "LP Token Reserve can not be able to receive NFTs.");
        require((_address == _teamReserve  && _skipNFT == false), "Team Reserve can not be able to receive NFTs.");
        // addresses that will not get NFTs based on their coin balance
        _setSkipNFT(_address, _skipNFT);
    }

    // _lpTokenReserve will not receive NFTs when getting coins
    // _lpTokenReserve will always be able to transfer coins as it will act as a Liquidity Pool for this coin Token
    function _setLpTokenReserve(address _address) internal {
        _lpTokenReserve = _address;
        _setSkipNFT(_address, true);
        canAlwaysTransfer[_address] = true;
    }

    /// Admin MAY set/change the wallet address of the Liquidity Pool Token Reserve
    /// The newly assigned LP Token Reserve WILL receive all of the coin Tokens held by the previous LP Token Reserve
    function adminSetLpTokenReserve(address _address) external onlyAdmin {
        address previousLpTokenReserve_ = _lpTokenReserve;
        _setLpTokenReserve(_address);

        // transfer previous reserve's tokens to the new reserve
        uint256 lpTokenBalance = balanceOf(previousLpTokenReserve_);
        _transfer(previousLpTokenReserve_, _address, lpTokenBalance);

        // previous reserve will be able to get NFTs & will no longer be able to always transfer
        _setSkipNFT(previousLpTokenReserve_, false);
        canAlwaysTransfer[previousLpTokenReserve_] = false;
    }

    // TeamReserve will not receive NFTs when getting coins
    // TeamReserve will always be able to transfer coins
    function _setTeamReserve(address _address) internal {
        _teamReserve = _address;
        _setSkipNFT(_address, true);
        canAlwaysTransfer[_address] = true;
    }

    /// Admin MAY set/change the wallet address of the Louder Team Reserve
    /// The newly assigned TeamReserve WILL receive all of the coin Tokens held by the old TeamReserve
    function adminSetTeamReserve(address _address) external onlyAdmin {
        address previousTeamReserve_ = _teamReserve;
        _setTeamReserve(_address);

        // transfer previous reserve's tokens to the new reserve
        uint256 teamBalance = balanceOf(previousTeamReserve_);
        _transfer(previousTeamReserve_, _address, teamBalance);

        // previous reserve will be able to get NFTs & will no longer be able to always transfer
        _setSkipNFT(previousTeamReserve_, false);
        canAlwaysTransfer[previousTeamReserve_] = false;
    }

    

    /// Admin WILL withdraw all ETH
    function adminWithdrawETH(address payable payee) public virtual onlyAdmin {
        payee.sendValue(address(this).balance);
    }

}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        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_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        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);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @title Adminable
/// @notice Mimics Open Zeppelin Ownable so that a contract can be BOTH Ownable
/// AND Adminable. Centralised offchain marketplaces often expect an owner to
/// be present to manage NFT content on the platform. However it is not clear
/// what criteria the marketplace uses to determine whether a contract
/// implements Ownable, and the criteria may change over time even if we did
/// know it. It's also not necessarily easy or possible to interface with
/// centralised marketplaces using multisig wallets such as gnosis. For that
/// reason we want an onchain admin with a relatively cold multisig separate
/// from the hot wallet doing offchain signing, etc.
/// If there is ever an issue with the owner (e.g. it is hacked/stolen/lost)
/// then the admin MUST be able to recover the owner by setting it directly to
/// a known good uncompromised wallet.
abstract contract Adminable {
    /// Singleton admin address. Analogous to Open Zeppelin owner.
    address public admin;

    /// Admin was transferred to a new address.
    /// @param previousAdmin The admin initiating the transfer, losing admin.
    /// @param newAdmin The address newly receiving/becoming admin.
    event AdminTransferred(address indexed previousAdmin, address indexed newAdmin);

    /// Throws if called by any account other than the admin.
    modifier onlyAdmin() {
        require(admin == msg.sender, "Adminable: caller is not the admin");
        _;
    }

    /// Transfers admin of the contract to a new account (`newAdmin`).
    /// Can only be called by the current admin.
    /// @param newAdmin_ The new admin address.
    function transferAdmin(address newAdmin_) external onlyAdmin {
        require(newAdmin_ != address(0), "Adminable: new admin is the zero address");
        _transferAdmin(newAdmin_);
    }

    /// Transfers admin of the contract to a new account (`newAdmin`).
    /// Internal function without access restriction.
    /// @param newAdmin_ The new admin address.
    function _transferAdmin(address newAdmin_) internal {
        address oldAdmin_ = admin;
        admin = newAdmin_;
        emit AdminTransferred(oldAdmin_, newAdmin_);
    }
}

File 9 of 11 : DN404.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "hardhat/console.sol";

/// @title DN404
/// @notice DN404 is a hybrid ERC20 and ERC721 implementation that mints
/// and burns NFTs based on an account's ERC20 token balance.
///
/// @author vectorized.eth (@optimizoor)
/// @author Quit (@0xQuit)
/// @author Michael Amadi (@AmadiMichaels)
/// @author cygaar (@0xCygaar)
/// @author Thomas (@0xjustadev)
/// @author Harrison (@PopPunkOnChain)
///
/// @dev Note:
/// - The ERC721 data is stored in this base DN404 contract, however a
///   DN404Mirror contract ***MUST*** be deployed and linked during
///   initialization.
/// - For ERC20 transfers, the most recently acquired NFT will be burned / transferred out first.
/// - A unit worth of ERC20 tokens equates to a deed to one NFT token.
///   The skip NFT status determines if this deed is automatically exercised.
///   An account can configure their skip NFT status.
///     * If `getSkipNFT(owner) == true`, ERC20 mints / transfers to `owner`
///       will NOT trigger NFT mints / transfers to `owner` (i.e. deeds are left unexercised).
///     * If `getSkipNFT(owner) == false`, ERC20 mints / transfers to `owner`
///       will trigger NFT mints / transfers to `owner`, until the NFT balance of `owner`
///       is equal to its ERC20 balance divided by the unit (rounded down).
/// - Invariant: `mirror.balanceOf(owner) <= base.balanceOf(owner) / _unit()`.
/// - The gas costs for automatic minting / transferring / burning of NFTs is O(n).
///   This can exceed the block gas limit.
///   Applications and users may need to break up large transfers into a few transactions.
/// - This implementation does not support "safe" transfers for automatic NFT transfers.
/// - The ERC20 token allowances and ERC721 token / operator approvals are separate.
/// - For MEV safety, users should NOT have concurrently open orders for the ERC20 and ERC721.
abstract contract DN404 {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                           EVENTS                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /// @dev Emitted when `owner` sets their skipNFT flag to `status`.
    event SkipNFTSet(address indexed owner, bool status);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 internal constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("SkipNFTSet(address,bool)"))`.
    uint256 private constant _SKIP_NFT_SET_EVENT_SIGNATURE =
        0xb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d6420393;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        CUSTOM ERRORS                       */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Thrown when attempting to double-initialize the contract.
    error DNAlreadyInitialized();

    /// @dev The function can only be called after the contract has been initialized.
    error DNNotInitialized();

    /// @dev Thrown when attempting to transfer or burn more tokens than sender's balance.
    error InsufficientBalance();

    /// @dev Thrown when a spender attempts to transfer tokens with an insufficient allowance.
    error InsufficientAllowance();

    /// @dev Thrown when minting an amount of tokens that would overflow the max tokens.
    error TotalSupplyOverflow();

    /// @dev The unit must be greater than zero and less than `2**96`.
    error InvalidUnit();

    /// @dev Thrown when the caller for a fallback NFT function is not the mirror contract.
    error SenderNotMirror();

    /// @dev Thrown when attempting to transfer tokens to the zero address.
    error TransferToZeroAddress();

    /// @dev Thrown when the mirror address provided for initialization is the zero address.
    error MirrorAddressIsZero();

    /// @dev Thrown when the link call to the mirror contract reverts.
    error LinkMirrorContractFailed();

    /// @dev Thrown when setting an NFT token approval
    /// and the caller is not the owner or an approved operator.
    error ApprovalCallerNotOwnerNorApproved();

    /// @dev Thrown when transferring an NFT
    /// and the caller is not the owner or an approved operator.
    error TransferCallerNotOwnerNorApproved();

    /// @dev Thrown when transferring an NFT and the from address is not the current owner.
    error TransferFromIncorrectOwner();

    /// @dev Thrown when checking the owner or approved address for a non-existent NFT.
    error TokenDoesNotExist();

    /// @dev The function selector is not recognized.
    error FnSelectorNotRecognized();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                         CONSTANTS                          */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev The flag to denote that the skip NFT flag is initialized.
    uint8 internal constant _ADDRESS_DATA_SKIP_NFT_INITIALIZED_FLAG = 1 << 0;

    /// @dev The flag to denote that the address should skip NFTs.
    uint8 internal constant _ADDRESS_DATA_SKIP_NFT_FLAG = 1 << 1;

    /// @dev The flag to denote that the address has overridden the default Permit2 allowance.
    uint8 internal constant _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG = 1 << 2;

    /// @dev The canonical Permit2 address.
    /// For signature-based allowance granting for single transaction ERC20 `transferFrom`.
    /// To enable, override `_givePermit2DefaultInfiniteAllowance()`.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Struct containing an address's token data and settings.
    struct AddressData {
        // Auxiliary data.
        uint88 aux;
        // Flags for `initialized` and `skipNFT`.
        uint8 flags;
        // The alias for the address. Zero means absence of an alias.
        uint32 addressAlias;
        // The number of NFT tokens.
        uint32 ownedLength;
        // The token balance in wei.
        uint96 balance;
    }

    /// @dev A uint32 map in storage.
    struct Uint32Map {
        uint256 spacer;
    }

    /// @dev A bitmap in storage.
    struct Bitmap {
        uint256 spacer;
    }

    /// @dev A struct to wrap a uint256 in storage.
    struct Uint256Ref {
        uint256 value;
    }

    /// @dev A mapping of an address pair to a Uint256Ref.
    struct AddressPairToUint256RefMap {
        uint256 spacer;
    }

    /// @dev Struct containing the base token contract storage.
    struct DN404Storage {
        // Current number of address aliases assigned.
        uint32 numAliases;
        // Next NFT ID to assign for a mint.
        uint32 nextTokenId;
        // The head of the burned pool.
        uint32 burnedPoolHead;
        // The tail of the burned pool.
        uint32 burnedPoolTail;
        // Total number of NFTs in existence.
        uint32 totalNFTSupply;
        // Total supply of tokens.
        uint96 totalSupply;
        // Address of the NFT mirror contract.
        address mirrorERC721;
        // Mapping of a user alias number to their address.
        mapping(uint32 => address) aliasToAddress;
        // Mapping of user operator approvals for NFTs.
        AddressPairToUint256RefMap operatorApprovals;
        // Mapping of NFT approvals to approved operators.
        mapping(uint256 => address) nftApprovals;
        // Bitmap of whether an non-zero NFT approval may exist.
        Bitmap mayHaveNFTApproval;
        // Bitmap of whether a NFT ID exists. Ignored if `_useExistsLookup()` returns false.
        Bitmap exists;
        // Mapping of user allowances for ERC20 spenders.
        AddressPairToUint256RefMap allowance;
        // Mapping of NFT IDs owned by an address.
        mapping(address => Uint32Map) owned;
        // The pool of burned NFT IDs.
        Uint32Map burnedPool;
        // Even indices: owner aliases. Odd indices: owned indices.
        Uint32Map oo;
        // Mapping of user account AddressData.
        mapping(address => AddressData) addressData;
    }

    /// @dev Returns a storage pointer for DN404Storage.
    function _getDN404Storage() internal pure virtual returns (DN404Storage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `uint72(bytes9(keccak256("DN404_STORAGE")))`.
            $.slot := 0xa20d6e21d0e5255308 // Truncate to 9 bytes to reduce bytecode size.
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                         INITIALIZER                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Initializes the DN404 contract with an
    /// `initialTokenSupply`, `initialTokenOwner` and `mirror` NFT contract address.
    ///
    /// Note: The `initialSupplyOwner` will have their skip NFT status set to true.
    function _initializeDN404(
        uint256 initialTokenSupply,
        address initialSupplyOwner,
        address mirror
    ) internal virtual {
        DN404Storage storage $ = _getDN404Storage();

        unchecked {
            if (_unit() - 1 >= 2 ** 96 - 1) revert InvalidUnit();
        }
        if ($.mirrorERC721 != address(0)) revert DNAlreadyInitialized();
        if (mirror == address(0)) revert MirrorAddressIsZero();

        /// @solidity memory-safe-assembly
        assembly {
            // Make the call to link the mirror contract.
            mstore(0x00, 0x0f4599e5) // `linkMirrorContract(address)`.
            mstore(0x20, caller())
            if iszero(and(eq(mload(0x00), 1), call(gas(), mirror, 0, 0x1c, 0x24, 0x00, 0x20))) {
                mstore(0x00, 0xd125259c) // `LinkMirrorContractFailed()`.
                revert(0x1c, 0x04)
            }
        }

        $.nextTokenId = 1;
        $.mirrorERC721 = mirror;

        if (initialTokenSupply != 0) {
            if (initialSupplyOwner == address(0)) revert TransferToZeroAddress();
            if (_totalSupplyOverflows(initialTokenSupply)) revert TotalSupplyOverflow();

            $.totalSupply = uint96(initialTokenSupply);
            AddressData storage initialOwnerAddressData = $.addressData[initialSupplyOwner];
            initialOwnerAddressData.balance = uint96(initialTokenSupply);

            /// @solidity memory-safe-assembly
            assembly {
                // Emit the {Transfer} event.
                mstore(0x00, initialTokenSupply)
                log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, initialSupplyOwner)))
            }

            _setSkipNFT(initialSupplyOwner, true);
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*               BASE UNIT FUNCTION TO OVERRIDE               */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Amount of token balance that is equal to one NFT.
    ///
    /// Note: The return value MUST be kept constant after `_initializeDN404` is called.
    function _unit() internal view virtual returns (uint256) {
        return 10 ** 18;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*               METADATA FUNCTIONS TO OVERRIDE               */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the name of the token.
    function name() public view virtual returns (string memory);

    /// @dev Returns the symbol of the token.
    function symbol() public view virtual returns (string memory);

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.
    function _tokenURI(uint256 id) internal view virtual returns (string memory);

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CONFIGURABLES                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns if direct NFT transfers should be used during ERC20 transfers
    /// whenever possible, instead of burning and re-minting.
    function _useDirectTransfersIfPossible() internal view virtual returns (bool) {
        return true;
    }

    /// @dev Returns if burns should be added to the burn pool.
    /// This returns false by default, which means the NFT IDs are re-minted in a cycle.
    function _addToBurnedPool(uint256 totalNFTSupplyAfterBurn, uint256 totalSupplyAfterBurn)
        internal
        view
        virtual
        returns (bool)
    {
        // Silence unused variable compiler warning.
        totalSupplyAfterBurn = totalNFTSupplyAfterBurn;
        return false;
    }

    /// @dev Returns whether to use the exists bitmap for more efficient
    /// scanning of an empty token ID slot.
    /// Recommended for collections that do not use the burn pool,
    /// and are expected to have nearly all possible NFTs materialized.
    ///
    /// Note: The returned value must be constant after initialization.
    function _useExistsLookup() internal view virtual returns (bool) {
        return true;
    }

    /// @dev Hook that is called after a batch of NFT transfers.
    /// The lengths of `from`, `to`, and `ids` are guaranteed to be the same.
    function _afterNFTTransfers(address[] memory from, address[] memory to, uint256[] memory ids)
        internal
        virtual
    {}

    /// @dev Override this function to return true if `_afterNFTTransfers` is used.
    /// This is to help the compiler avoid producing dead bytecode.
    function _useAfterNFTTransfers() internal virtual returns (bool) {}

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      ERC20 OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the decimals places of the token. Defaults to 18.
    /// Does not affect DN404's internal calculations.
    /// Will only affect the frontend UI on most protocols.
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /// @dev Returns the amount of tokens in existence.
    function totalSupply() public view virtual returns (uint256) {
        return uint256(_getDN404Storage().totalSupply);
    }

    /// @dev Returns the amount of tokens owned by `owner`.
    function balanceOf(address owner) public view virtual returns (uint256) {
        return _getDN404Storage().addressData[owner].balance;
    }

    /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
    function allowance(address owner, address spender) public view returns (uint256) {
        if (_givePermit2DefaultInfiniteAllowance() && spender == _PERMIT2) {
            uint8 flags = _getDN404Storage().addressData[owner].flags;
            if ((flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG) == uint256(0)) {
                return type(uint256).max;
            }
        }
        return _ref(_getDN404Storage().allowance, owner, spender).value;
    }

    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    ///
    /// Emits a {Approval} event.
    function approve(address spender, uint256 amount) public virtual returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    /// @dev Transfer `amount` tokens from the caller to `to`.
    ///
    /// Will burn sender NFTs if balance after transfer is less than
    /// the amount required to support the current NFT balance.
    ///
    /// Will mint NFTs to `to` if the recipient's new balance supports
    /// additional NFTs ***AND*** the `to` address's skipNFT flag is
    /// set to false.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    ///
    /// Emits a {Transfer} event.
    function transfer(address to, uint256 amount) public virtual returns (bool) {
        _transfer(msg.sender, to, amount);
        return true;
    }

    /// @dev Transfers `amount` tokens from `from` to `to`.
    ///
    /// Note: Does not update the allowance if it is the maximum uint256 value.
    ///
    /// Will burn sender NFTs if balance after transfer is less than
    /// the amount required to support the current NFT balance.
    ///
    /// Will mint NFTs to `to` if the recipient's new balance supports
    /// additional NFTs ***AND*** the `to` address's skipNFT flag is
    /// set to false.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
        Uint256Ref storage a = _ref(_getDN404Storage().allowance, from, msg.sender);

        uint256 allowed = _givePermit2DefaultInfiniteAllowance() && msg.sender == _PERMIT2
            && (_getDN404Storage().addressData[from].flags & _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG)
                == uint256(0) ? type(uint256).max : a.value;

        if (allowed != type(uint256).max) {
            if (amount > allowed) revert InsufficientAllowance();
            unchecked {
                a.value = allowed - amount;
            }
        }
        _transfer(from, to, amount);
        return true;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          PERMIT2                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Whether Permit2 has infinite allowances by default for all owners.
    /// For signature-based allowance granting for single transaction ERC20 `transferFrom`.
    /// To enable, override this function to return true.
    ///
    /// Note: The returned value SHOULD be kept constant.
    /// If the returned value changes from false to true,
    /// it can override the user customized allowances for Permit2 to infinity.
    function _givePermit2DefaultInfiniteAllowance() internal view virtual returns (bool) {
        return false;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                  INTERNAL MINT FUNCTIONS                   */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Mints `amount` tokens to `to`, increasing the total supply.
    ///
    /// Will mint NFTs to `to` if the recipient's new balance supports
    /// additional NFTs ***AND*** the `to` address's skipNFT flag is set to false.
    ///
    /// Note:
    /// - May mint more NFTs than `amount / _unit()`.
    ///   The number of NFTs minted is what is needed to make `to`'s NFT balance whole.
    /// - Token IDs may wrap around `totalSupply / _unit()` back to 1.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 amount) internal virtual {
        if (to == address(0)) revert TransferToZeroAddress();

        DN404Storage storage $ = _getDN404Storage();
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();
        AddressData storage toAddressData = $.addressData[to];

        _DNMintTemps memory t;
        unchecked {
            {
                uint256 toBalance = uint256(toAddressData.balance) + amount;
                toAddressData.balance = uint96(toBalance);
                t.toEnd = toBalance / _unit();
            }
            uint256 maxId;
            {
                uint256 newTotalSupply = uint256($.totalSupply) + amount;
                $.totalSupply = uint96(newTotalSupply);
                uint256 overflows = _toUint(_totalSupplyOverflows(newTotalSupply));
                if (overflows | _toUint(newTotalSupply < amount) != 0) revert TotalSupplyOverflow();
                maxId = newTotalSupply / _unit();
            }
            while (!getSkipNFT(to)) {
                Uint32Map storage toOwned = $.owned[to];
                Uint32Map storage oo = $.oo;
                uint256 toIndex = toAddressData.ownedLength;
                if ((t.numNFTMints = _zeroFloorSub(t.toEnd, toIndex)) == uint256(0)) break;

                t.packedLogs = _packedLogsMalloc(t.numNFTMints);
                _packedLogsSet(t.packedLogs, to, 0);
                $.totalNFTSupply += uint32(t.numNFTMints);
                toAddressData.ownedLength = uint32(t.toEnd);
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                uint32 burnedPoolHead = $.burnedPoolHead;
                t.burnedPoolTail = $.burnedPoolTail;
                t.nextTokenId = _wrapNFTId($.nextTokenId, maxId);
                // Mint loop.
                do {
                    uint256 id;
                    if (burnedPoolHead != t.burnedPoolTail) {
                        id = _get($.burnedPool, burnedPoolHead++);
                    } else {
                        id = t.nextTokenId;
                        while (_get(oo, _ownershipIndex(id)) != 0) {
                            id = _useExistsLookup()
                                ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId), maxId)
                                : _wrapNFTId(id + 1, maxId);
                        }
                        t.nextTokenId = _wrapNFTId(id + 1, maxId);
                    }
                    if (_useExistsLookup()) _set($.exists, id, true);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));
                    _packedLogsAppend(t.packedLogs, id);
                } while (toIndex != t.toEnd);

                $.nextTokenId = uint32(t.nextTokenId);
                $.burnedPoolHead = burnedPoolHead;
                _packedLogsSend(t.packedLogs, $);
                break;
            }
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)))
        }
        if (_useAfterNFTTransfers()) {
            _afterNFTTransfers(
                _zeroAddresses(t.numNFTMints),
                _filled(t.numNFTMints, to),
                _packedLogsIds(t.packedLogs)
            );
        }
    }

    /// @dev Mints `amount` tokens to `to`, increasing the total supply.
    /// This variant mints NFT tokens starting from ID `preTotalSupply / _unit() + 1`.
    /// The `nextTokenId` will not be changed.
    /// If any NFTs are minted, the burned pool will be invalidated (emptied).
    ///
    /// Will mint NFTs to `to` if the recipient's new balance supports
    /// additional NFTs ***AND*** the `to` address's skipNFT flag is set to false.
    ///
    /// Note:
    /// - May mint more NFTs than `amount / _unit()`.
    ///   The number of NFTs minted is what is needed to make `to`'s NFT balance whole.
    /// - Token IDs may wrap around `totalSupply / _unit()` back to 1.
    ///
    /// Emits a {Transfer} event.
    function _mintNext(address to, uint256 amount) internal virtual {
        if (to == address(0)) revert TransferToZeroAddress();

        DN404Storage storage $ = _getDN404Storage();
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();
        AddressData storage toAddressData = $.addressData[to];

        _DNMintTemps memory t;
        unchecked {
            {
                uint256 toBalance = uint256(toAddressData.balance) + amount;
                toAddressData.balance = uint96(toBalance);
                t.toEnd = toBalance / _unit();
            }
            uint256 id;
            uint256 maxId;
            {
                uint256 preTotalSupply = uint256($.totalSupply);
                uint256 newTotalSupply = uint256(preTotalSupply) + amount;
                $.totalSupply = uint96(newTotalSupply);
                uint256 overflows = _toUint(_totalSupplyOverflows(newTotalSupply));
                if (overflows | _toUint(newTotalSupply < amount) != 0) revert TotalSupplyOverflow();
                maxId = newTotalSupply / _unit();
                id = _wrapNFTId(preTotalSupply / _unit() + 1, maxId);
            }
            while (!getSkipNFT(to)) {
                Uint32Map storage toOwned = $.owned[to];
                Uint32Map storage oo = $.oo;
                uint256 toIndex = toAddressData.ownedLength;
                if ((t.numNFTMints = _zeroFloorSub(t.toEnd, toIndex)) == uint256(0)) break;

                t.packedLogs = _packedLogsMalloc(t.numNFTMints);
                // Invalidate (empty) the burned pool.
                $.burnedPoolHead = 0;
                $.burnedPoolTail = 0;
                _packedLogsSet(t.packedLogs, to, 0);
                $.totalNFTSupply += uint32(t.numNFTMints);
                toAddressData.ownedLength = uint32(t.toEnd);
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                // Mint loop.
                do {
                    while (_get(oo, _ownershipIndex(id)) != 0) {
                        id = _useExistsLookup()
                            ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId), maxId)
                            : _wrapNFTId(id + 1, maxId);
                    }
                    if (_useExistsLookup()) _set($.exists, id, true);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));
                    _packedLogsAppend(t.packedLogs, id);
                    id = _wrapNFTId(id + 1, maxId);
                } while (toIndex != t.toEnd);

                _packedLogsSend(t.packedLogs, $);
                break;
            }
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)))
        }
        if (_useAfterNFTTransfers()) {
            _afterNFTTransfers(
                _zeroAddresses(t.numNFTMints),
                _filled(t.numNFTMints, to),
                _packedLogsIds(t.packedLogs)
            );
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                  INTERNAL BURN FUNCTIONS                   */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Burns `amount` tokens from `from`, reducing the total supply.
    ///
    /// Will burn sender NFTs if balance after transfer is less than
    /// the amount required to support the current NFT balance.
    ///
    /// Emits a {Transfer} event.
    function _burn(address from, uint256 amount) internal virtual {
        DN404Storage storage $ = _getDN404Storage();
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();

        AddressData storage fromAddressData = $.addressData[from];
        _DNBurnTemps memory t;

        unchecked {
            t.fromBalance = fromAddressData.balance;
            if (amount > t.fromBalance) revert InsufficientBalance();

            fromAddressData.balance = uint96(t.fromBalance -= amount);
            t.totalSupply = uint256($.totalSupply) - amount;
            $.totalSupply = uint96(t.totalSupply);

            Uint32Map storage fromOwned = $.owned[from];
            uint256 fromIndex = fromAddressData.ownedLength;
            t.numNFTBurns = _zeroFloorSub(fromIndex, t.fromBalance / _unit());

            if (t.numNFTBurns != 0) {
                t.packedLogs = _packedLogsMalloc(t.numNFTBurns);
                _packedLogsSet(t.packedLogs, from, 1);
                bool addToBurnedPool;
                {
                    uint256 totalNFTSupply = uint256($.totalNFTSupply) - t.numNFTBurns;
                    $.totalNFTSupply = uint32(totalNFTSupply);
                    addToBurnedPool = _addToBurnedPool(totalNFTSupply, t.totalSupply);
                }

                Uint32Map storage oo = $.oo;
                uint256 fromEnd = fromIndex - t.numNFTBurns;
                fromAddressData.ownedLength = uint32(fromEnd);
                uint32 burnedPoolTail = $.burnedPoolTail;
                // Burn loop.
                do {
                    uint256 id = _get(fromOwned, --fromIndex);
                    _setOwnerAliasAndOwnedIndex(oo, id, 0, 0);
                    _packedLogsAppend(t.packedLogs, id);
                    if (_useExistsLookup()) _set($.exists, id, false);
                    if (addToBurnedPool) _set($.burnedPool, burnedPoolTail++, uint32(id));
                    if (_get($.mayHaveNFTApproval, id)) {
                        _set($.mayHaveNFTApproval, id, false);
                        delete $.nftApprovals[id];
                    }
                } while (fromIndex != fromEnd);

                if (addToBurnedPool) $.burnedPoolTail = burnedPoolTail;
                _packedLogsSend(t.packedLogs, $);
            }
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
        }
        if (_useAfterNFTTransfers()) {
            _afterNFTTransfers(
                _filled(t.numNFTBurns, from),
                _zeroAddresses(t.numNFTBurns),
                _packedLogsIds(t.packedLogs)
            );
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                INTERNAL TRANSFER FUNCTIONS                 */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Moves `amount` of tokens from `from` to `to`.
    ///
    /// Will burn sender NFTs if balance after transfer is less than
    /// the amount required to support the current NFT balance.
    ///
    /// Will mint NFTs to `to` if the recipient's new balance supports
    /// additional NFTs ***AND*** the `to` address's skipNFT flag is
    /// set to false.
    ///
    /// Emits a {Transfer} event.
    function _transfer(address from, address to, uint256 amount) internal virtual {
        if (to == address(0)) revert TransferToZeroAddress();

        DN404Storage storage $ = _getDN404Storage();
        AddressData storage fromAddressData = $.addressData[from];
        AddressData storage toAddressData = $.addressData[to];
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();

        _DNTransferTemps memory t;
        t.fromOwnedLength = fromAddressData.ownedLength;
        t.toOwnedLength = toAddressData.ownedLength;

        unchecked {
            {
                uint256 fromBalance = fromAddressData.balance;
                if (amount > fromBalance) revert InsufficientBalance();
                fromAddressData.balance = uint96(fromBalance -= amount);

                uint256 toBalance = uint256(toAddressData.balance) + amount;
                toAddressData.balance = uint96(toBalance);
                t.numNFTBurns = _zeroFloorSub(t.fromOwnedLength, fromBalance / _unit());

                if (!getSkipNFT(to)) {
                    if (from == to) t.toOwnedLength = t.fromOwnedLength - t.numNFTBurns;
                    t.numNFTMints = _zeroFloorSub(toBalance / _unit(), t.toOwnedLength);
                }
            }

            while (_useDirectTransfersIfPossible()) {
                uint256 n = _min(t.fromOwnedLength, _min(t.numNFTBurns, t.numNFTMints));
                if (n == uint256(0)) break;
                t.numNFTBurns -= n;
                t.numNFTMints -= n;
                if (from == to) {
                    t.toOwnedLength += n;
                    break;
                }
                t.directLogs = _directLogsMalloc(n, from, to);
                Uint32Map storage fromOwned = $.owned[from];
                Uint32Map storage toOwned = $.owned[to];
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                uint256 toIndex = t.toOwnedLength;
                n = toIndex + n;
                // Direct transfer loop.
                do {
                    uint256 id = _get(fromOwned, --t.fromOwnedLength);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex($.oo, id, t.toAlias, uint32(toIndex));
                    _directLogsAppend(t.directLogs, id);
                    if (_get($.mayHaveNFTApproval, id)) {
                        _set($.mayHaveNFTApproval, id, false);
                        delete $.nftApprovals[id];
                    }
                } while (++toIndex != n);

                toAddressData.ownedLength = uint32(t.toOwnedLength = toIndex);
                fromAddressData.ownedLength = uint32(t.fromOwnedLength);
                break;
            }

            t.totalNFTSupply = uint256($.totalNFTSupply) + t.numNFTMints - t.numNFTBurns;
            $.totalNFTSupply = uint32(t.totalNFTSupply);

            Uint32Map storage oo = $.oo;
            t.packedLogs = _packedLogsMalloc(t.numNFTBurns + t.numNFTMints);

            t.burnedPoolTail = $.burnedPoolTail;
            if (t.numNFTBurns != 0) {
                _packedLogsSet(t.packedLogs, from, 1);
                bool addToBurnedPool = _addToBurnedPool(t.totalNFTSupply, $.totalSupply);
                Uint32Map storage fromOwned = $.owned[from];
                uint256 fromIndex = t.fromOwnedLength;
                fromAddressData.ownedLength = uint32(t.fromEnd = fromIndex - t.numNFTBurns);
                uint32 burnedPoolTail = t.burnedPoolTail;
                // Burn loop.
                do {
                    uint256 id = _get(fromOwned, --fromIndex);
                    _setOwnerAliasAndOwnedIndex(oo, id, 0, 0);
                    _packedLogsAppend(t.packedLogs, id);
                    if (_useExistsLookup()) _set($.exists, id, false);
                    if (addToBurnedPool) _set($.burnedPool, burnedPoolTail++, uint32(id));
                    if (_get($.mayHaveNFTApproval, id)) {
                        _set($.mayHaveNFTApproval, id, false);
                        delete $.nftApprovals[id];
                    }
                } while (fromIndex != t.fromEnd);

                if (addToBurnedPool) $.burnedPoolTail = (t.burnedPoolTail = burnedPoolTail);
            }

            if (t.numNFTMints != 0) {
                _packedLogsSet(t.packedLogs, to, 0);
                Uint32Map storage toOwned = $.owned[to];
                t.toAlias = _registerAndResolveAlias(toAddressData, to);
                uint256 maxId = $.totalSupply / _unit();
                t.nextTokenId = _wrapNFTId($.nextTokenId, maxId);
                console.log("nextTokenId from in _transfer before mint - storage: ", $.nextTokenId);
                console.log("nextTokenId from in _transfer before mint - temp: ", t.nextTokenId);
                console.log("totalSupply from in _transfer before mint - storage: ", $.totalSupply);
                console.log("maxId from in _transfer before mint: ", maxId);
                uint256 toIndex = t.toOwnedLength;
                toAddressData.ownedLength = uint32(t.toEnd = toIndex + t.numNFTMints);
                uint32 burnedPoolHead = $.burnedPoolHead;
                // Mint loop.
                do {
                    uint256 id;
                    if (burnedPoolHead != t.burnedPoolTail) {
                        id = _get($.burnedPool, burnedPoolHead++);
                    } else {
                        id = t.nextTokenId;
                        while (_get(oo, _ownershipIndex(id)) != 0) {
                            id = _useExistsLookup()
                                ? _wrapNFTId(_findFirstUnset($.exists, id + 1, maxId), maxId)
                                : _wrapNFTId(id + 1, maxId);
                        }
                        t.nextTokenId = _wrapNFTId(id + 1, maxId);
                    }
                    if (_useExistsLookup()) _set($.exists, id, true);
                    _set(toOwned, toIndex, uint32(id));
                    _setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));
                    _packedLogsAppend(t.packedLogs, id);
                } while (toIndex != t.toEnd);

                $.burnedPoolHead = burnedPoolHead;
                console.log("nextTokenId after mint: ", t.nextTokenId);
                $.nextTokenId = uint32(t.nextTokenId);
            }

            if (t.directLogs != bytes32(0)) _directLogsSend(t.directLogs, $);
            if (t.packedLogs != bytes32(0)) _packedLogsSend(t.packedLogs, $);
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), shr(96, shl(96, to)))
        }
        if (_useAfterNFTTransfers()) {
            uint256[] memory ids = _directLogsIds(t.directLogs);
            unchecked {
                _afterNFTTransfers(
                    _concat(
                        _filled(ids.length + t.numNFTBurns, from), _zeroAddresses(t.numNFTMints)
                    ),
                    _concat(
                        _concat(_filled(ids.length, to), _zeroAddresses(t.numNFTBurns)),
                        _filled(t.numNFTMints, to)
                    ),
                    _concat(ids, _packedLogsIds(t.packedLogs))
                );
            }
        }
    }

    /// @dev Transfers token `id` from `from` to `to`.
    /// Also emits an ERC721 {Transfer} event on the `mirrorERC721`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - `msgSender` must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _initiateTransferFromNFT(address from, address to, uint256 id, address msgSender)
        internal
        virtual
    {
        // Emit ERC721 {Transfer} event.
        // We do this before the `_transferFromNFT`, as `_transferFromNFT` may use
        // the `_afterNFTTransfers` hook, which may trigger more transfers.
        // This helps keeps the sequence of emitted events consistent.
        // Since `mirrorERC721` is a trusted contract, we can do this.
        bytes32 directLogs = _directLogsMalloc(1, from, to);
        _directLogsAppend(directLogs, id);
        _directLogsSend(directLogs, _getDN404Storage());

        _transferFromNFT(from, to, id, msgSender);
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// This function will be called when a ERC721 transfer is made on the mirror contract.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - `msgSender` must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _transferFromNFT(address from, address to, uint256 id, address msgSender)
        internal
        virtual
    {
        if (to == address(0)) revert TransferToZeroAddress();

        DN404Storage storage $ = _getDN404Storage();
        if ($.mirrorERC721 == address(0)) revert DNNotInitialized();

        Uint32Map storage oo = $.oo;

        if (from != $.aliasToAddress[_get(oo, _ownershipIndex(_restrictNFTId(id)))]) {
            revert TransferFromIncorrectOwner();
        }

        if (msgSender != from) {
            if (!_isApprovedForAll(from, msgSender)) {
                if (_getApproved(id) != msgSender) {
                    revert TransferCallerNotOwnerNorApproved();
                }
            }
        }

        AddressData storage fromAddressData = $.addressData[from];
        AddressData storage toAddressData = $.addressData[to];

        uint256 unit = _unit();
        mapping(address => Uint32Map) storage owned = $.owned;

        unchecked {
            uint256 fromBalance = fromAddressData.balance;
            if (unit > fromBalance) revert InsufficientBalance();
            fromAddressData.balance = uint96(fromBalance - unit);
            toAddressData.balance += uint96(unit);
        }
        if (_get($.mayHaveNFTApproval, id)) {
            _set($.mayHaveNFTApproval, id, false);
            delete $.nftApprovals[id];
        }
        unchecked {
            Uint32Map storage fromOwned = owned[from];
            uint32 updatedId = _get(fromOwned, --fromAddressData.ownedLength);
            uint32 i = _get(oo, _ownedIndex(id));
            _set(fromOwned, i, updatedId);
            _set(oo, _ownedIndex(updatedId), i);
        }
        unchecked {
            uint32 n = toAddressData.ownedLength++;
            _set(owned[to], n, uint32(id));
            _setOwnerAliasAndOwnedIndex(oo, id, _registerAndResolveAlias(toAddressData, to), n);
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Transfer} event.
            mstore(0x00, unit)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), shr(96, shl(96, to)))
        }
        if (_useAfterNFTTransfers()) {
            _afterNFTTransfers(_filled(1, from), _filled(1, to), _filled(1, id));
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                 INTERNAL APPROVE FUNCTIONS                 */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
    ///
    /// Emits a {Approval} event.
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        if (_givePermit2DefaultInfiniteAllowance() && spender == _PERMIT2) {
            _getDN404Storage().addressData[owner].flags |= _ADDRESS_DATA_OVERRIDE_PERMIT2_FLAG;
        }
        _ref(_getDN404Storage().allowance, owner, spender).value = amount;
        /// @solidity memory-safe-assembly
        assembly {
            // Emit the {Approval} event.
            mstore(0x00, amount)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, shl(96, owner)), shr(96, shl(96, spender)))
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                 DATA HITCHHIKING FUNCTIONS                 */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the auxiliary data for `owner`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _getAux(address owner) internal view virtual returns (uint88) {
        return _getDN404Storage().addressData[owner].aux;
    }

    /// @dev Set the auxiliary data for `owner` to `value`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _setAux(address owner, uint88 value) internal virtual {
        _getDN404Storage().addressData[owner].aux = value;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                     SKIP NFT FUNCTIONS                     */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns true if minting and transferring ERC20s to `owner` will skip minting NFTs.
    /// Returns false otherwise.
    function getSkipNFT(address owner) public view virtual returns (bool result) {
        uint8 flags = _getDN404Storage().addressData[owner].flags;
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(iszero(and(flags, _ADDRESS_DATA_SKIP_NFT_FLAG)))
            if iszero(and(flags, _ADDRESS_DATA_SKIP_NFT_INITIALIZED_FLAG)) {
                result := iszero(iszero(extcodesize(owner)))
            }
        }
    }

    /// @dev Sets the caller's skipNFT flag to `skipNFT`. Returns true.
    ///
    /// Emits a {SkipNFTSet} event.
    function setSkipNFT(bool skipNFT) public virtual returns (bool) {
        _setSkipNFT(msg.sender, skipNFT);
        return true;
    }

    /// @dev Internal function to set account `owner` skipNFT flag to `state`
    ///
    /// Initializes account `owner` AddressData if it is not currently initialized.
    ///
    /// Emits a {SkipNFTSet} event.
    function _setSkipNFT(address owner, bool state) internal virtual {
        AddressData storage d = _getDN404Storage().addressData[owner];
        uint8 flags = d.flags;
        /// @solidity memory-safe-assembly
        assembly {
            let s := xor(iszero(and(flags, _ADDRESS_DATA_SKIP_NFT_FLAG)), iszero(state))
            flags := xor(mul(_ADDRESS_DATA_SKIP_NFT_FLAG, s), flags)
            flags := or(_ADDRESS_DATA_SKIP_NFT_INITIALIZED_FLAG, flags)
            mstore(0x00, iszero(iszero(state)))
            log2(0x00, 0x20, _SKIP_NFT_SET_EVENT_SIGNATURE, shr(96, shl(96, owner)))
        }
        d.flags = flags;
    }

    /// @dev Returns the `addressAlias` of account `to`.
    ///
    /// Assigns and registers the next alias if `to` alias was not previously registered.
    function _registerAndResolveAlias(AddressData storage toAddressData, address to)
        internal
        virtual
        returns (uint32 addressAlias)
    {
        DN404Storage storage $ = _getDN404Storage();
        addressAlias = toAddressData.addressAlias;
        if (addressAlias == uint256(0)) {
            unchecked {
                addressAlias = ++$.numAliases;
            }
            toAddressData.addressAlias = addressAlias;
            $.aliasToAddress[addressAlias] = to;
            if (addressAlias == uint256(0)) revert(); // Overflow.
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                     MIRROR OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the address of the mirror NFT contract.
    function mirrorERC721() public view virtual returns (address) {
        return _getDN404Storage().mirrorERC721;
    }

    /// @dev Returns the total NFT supply.
    function _totalNFTSupply() internal view virtual returns (uint256) {
        return _getDN404Storage().totalNFTSupply;
    }

    /// @dev Returns `owner` NFT balance.
    function _balanceOfNFT(address owner) internal view virtual returns (uint256) {
        return _getDN404Storage().addressData[owner].ownedLength;
    }

    /// @dev Returns the owner of token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _ownerAt(uint256 id) internal view virtual returns (address) {
        DN404Storage storage $ = _getDN404Storage();
        return $.aliasToAddress[_get($.oo, _ownershipIndex(_restrictNFTId(id)))];
    }

    /// @dev Returns the owner of token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function _ownerOf(uint256 id) internal view virtual returns (address) {
        if (!_exists(id)) revert TokenDoesNotExist();
        return _ownerAt(id);
    }

    /// @dev Returns whether `operator` is approved to manage the NFT tokens of `owner`.
    function _isApprovedForAll(address owner, address operator)
        internal
        view
        virtual
        returns (bool)
    {
        return _ref(_getDN404Storage().operatorApprovals, owner, operator).value != 0;
    }

    /// @dev Returns if token `id` exists.
    function _exists(uint256 id) internal view virtual returns (bool) {
        return _ownerAt(id) != address(0);
    }

    /// @dev Returns the account approved to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function _getApproved(uint256 id) internal view virtual returns (address) {
        if (!_exists(id)) revert TokenDoesNotExist();
        return _getDN404Storage().nftApprovals[id];
    }

    /// @dev Sets `spender` as the approved account to manage token `id`, using `msgSender`.
    ///
    /// Requirements:
    /// - `msgSender` must be the owner or an approved operator for the token owner.
    function _approveNFT(address spender, uint256 id, address msgSender)
        internal
        virtual
        returns (address owner)
    {
        DN404Storage storage $ = _getDN404Storage();

        owner = $.aliasToAddress[_get($.oo, _ownershipIndex(_restrictNFTId(id)))];

        if (msgSender != owner) {
            if (!_isApprovedForAll(owner, msgSender)) {
                revert ApprovalCallerNotOwnerNorApproved();
            }
        }

        $.nftApprovals[id] = spender;
        _set($.mayHaveNFTApproval, id, spender != address(0));
    }

    /// @dev Approve or remove the `operator` as an operator for `msgSender`,
    /// without authorization checks.
    function _setApprovalForAll(address operator, bool approved, address msgSender)
        internal
        virtual
    {
        // For efficiency, we won't check if `operator` isn't `address(0)` (practically a no-op).
        _ref(_getDN404Storage().operatorApprovals, msgSender, operator).value = _toUint(approved);
    }

    /// @dev Returns the NFT IDs of `owner` in the range `[begin..end)` (exclusive of `end`).
    /// `begin` and `end` are indices in the owner's token ID array, not the entire token range.
    /// Optimized for smaller bytecode size, as this function is intended for off-chain calling.
    function _ownedIds(address owner, uint256 begin, uint256 end)
        internal
        view
        virtual
        returns (uint256[] memory ids)
    {
        DN404Storage storage $ = _getDN404Storage();
        Uint32Map storage owned = $.owned[owner];
        end = _min($.addressData[owner].ownedLength, end);
        /// @solidity memory-safe-assembly
        assembly {
            ids := mload(0x40)
            let i := begin
            for {} lt(i, end) { i := add(i, 1) } {
                let s := add(shl(96, owned.slot), shr(3, i)) // Storage slot.
                let id := and(0xffffffff, shr(shl(5, and(i, 7)), sload(s)))
                mstore(add(add(ids, 0x20), shl(5, sub(i, begin))), id) // Append to.
            }
            mstore(ids, sub(i, begin)) // Store the length.
            mstore(0x40, add(add(ids, 0x20), shl(5, sub(i, begin)))) // Allocate memory.
        }
    }

    /// @dev Fallback modifier to dispatch calls from the mirror NFT contract
    /// to internal functions in this contract.
    modifier dn404Fallback() virtual {
        DN404Storage storage $ = _getDN404Storage();

        uint256 fnSelector = _calldataload(0x00) >> 224;

        // `transferFromNFT(address,address,uint256,address)`.
        if (fnSelector == 0xe5eb36c8) {
            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
            _transferFromNFT(
                address(uint160(_calldataload(0x04))), // `from`.
                address(uint160(_calldataload(0x24))), // `to`.
                _calldataload(0x44), // `id`.
                address(uint160(_calldataload(0x64))) // `msgSender`.
            );
            _return(1);
        }
        // `setApprovalForAll(address,bool,address)`.
        if (fnSelector == 0x813500fc) {
            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
            _setApprovalForAll(
                address(uint160(_calldataload(0x04))), // `spender`.
                _calldataload(0x24) != 0, // `status`.
                address(uint160(_calldataload(0x44))) // `msgSender`.
            );
            _return(1);
        }
        // `isApprovedForAll(address,address)`.
        if (fnSelector == 0xe985e9c5) {
            bool result = _isApprovedForAll(
                address(uint160(_calldataload(0x04))), // `owner`.
                address(uint160(_calldataload(0x24))) // `operator`.
            );
            _return(_toUint(result));
        }
        // `ownerOf(uint256)`.
        if (fnSelector == 0x6352211e) {
            _return(uint160(_ownerOf(_calldataload(0x04))));
        }
        // `ownerAt(uint256)`.
        if (fnSelector == 0x24359879) {
            _return(uint160(_ownerAt(_calldataload(0x04))));
        }
        // `approveNFT(address,uint256,address)`.
        if (fnSelector == 0xd10b6e0c) {
            if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
            address owner = _approveNFT(
                address(uint160(_calldataload(0x04))), // `spender`.
                _calldataload(0x24), // `id`.
                address(uint160(_calldataload(0x44))) // `msgSender`.
            );
            _return(uint160(owner));
        }
        // `getApproved(uint256)`.
        if (fnSelector == 0x081812fc) {
            _return(uint160(_getApproved(_calldataload(0x04))));
        }
        // `balanceOfNFT(address)`.
        if (fnSelector == 0xf5b100ea) {
            _return(_balanceOfNFT(address(uint160(_calldataload(0x04)))));
        }
        // `totalNFTSupply()`.
        if (fnSelector == 0xe2c79281) {
            _return(_totalNFTSupply());
        }
        // `tokenURI(uint256)`.
        if (fnSelector == 0xc87b56dd) {
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x40, add(mload(0x40), 0x20))
            }
            string memory uri = _tokenURI(_calldataload(0x04));
            /// @solidity memory-safe-assembly
            assembly {
                // Memory safe, as we've advanced the free memory pointer by a word.
                let o := sub(uri, 0x20) // Start of the returndata.
                let z := add(mload(uri), 0x40) // Unpadded length of returndata.
                mstore(add(o, z), 0) // Zeroize the word after the end of the string.
                mstore(o, 0x20) // Store the offset of `uri`.
                return(o, and(not(0x1f), add(0x1f, z)))
            }
        }
        // `implementsDN404()`.
        if (fnSelector == 0xb7a94eb8) {
            _return(1);
        }
        _;
    }

    /// @dev Fallback function for calls from mirror NFT contract.
    /// Override this if you need to implement your custom
    /// fallback with utilities like Solady's `LibZip.cdFallback()`.
    /// And always remember to always wrap the fallback with `dn404Fallback`.
    fallback() external payable virtual dn404Fallback {
        revert FnSelectorNotRecognized(); // Not mandatory. Just for quality of life.
    }

    /// @dev This is to silence the compiler warning.
    /// Override and remove the revert if you want your contract to receive ETH via receive.
    receive() external payable virtual {
        if (msg.value != 0) revert();
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                 INTERNAL / PRIVATE HELPERS                 */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns `(i - 1) << 1`.
    function _ownershipIndex(uint256 i) internal pure returns (uint256) {
        unchecked {
            return (i - 1) << 1; // Minus 1 as token IDs start from 1.
        }
    }

    /// @dev Returns `((i - 1) << 1) + 1`.
    function _ownedIndex(uint256 i) internal pure returns (uint256) {
        unchecked {
            return ((i - 1) << 1) + 1; // Minus 1 as token IDs start from 1.
        }
    }

    /// @dev Returns the uint32 value at `index` in `map`.
    function _get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := add(shl(96, map.slot), shr(3, index)) // Storage slot.
            result := and(0xffffffff, shr(shl(5, and(index, 7)), sload(s)))
        }
    }

    /// @dev Updates the uint32 value at `index` in `map`.
    function _set(Uint32Map storage map, uint256 index, uint32 value) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let s := add(shl(96, map.slot), shr(3, index)) // Storage slot.
            let o := shl(5, and(index, 7)) // Storage slot offset (bits).
            let v := sload(s) // Storage slot value.
            sstore(s, xor(v, shl(o, and(0xffffffff, xor(value, shr(o, v))))))
        }
    }

    /// @dev Sets the owner alias and the owned index together.
    function _setOwnerAliasAndOwnedIndex(
        Uint32Map storage map,
        uint256 id,
        uint32 ownership,
        uint32 ownedIndex
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let i := sub(id, 1) // Index of the uint64 combined value.
            let s := add(shl(96, map.slot), shr(2, i)) // Storage slot.
            let v := sload(s) // Storage slot value.
            let o := shl(6, and(i, 3)) // Storage slot offset (bits).
            let combined := or(shl(32, ownedIndex), and(0xffffffff, ownership))
            sstore(s, xor(v, shl(o, and(0xffffffffffffffff, xor(shr(o, v), combined)))))
        }
    }

    /// @dev Returns the boolean value of the bit at `index` in `bitmap`.
    function _get(Bitmap storage bitmap, uint256 index) internal view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := add(shl(96, bitmap.slot), shr(8, index)) // Storage slot.
            result := and(1, shr(and(0xff, index), sload(s)))
        }
    }

    /// @dev Updates the bit at `index` in `bitmap` to `value`.
    function _set(Bitmap storage bitmap, uint256 index, bool value) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let s := add(shl(96, bitmap.slot), shr(8, index)) // Storage slot.
            let o := and(0xff, index) // Storage slot offset (bits).
            sstore(s, or(and(sload(s), not(shl(o, 1))), shl(o, iszero(iszero(value)))))
        }
    }

    /// @dev Returns the index of the least significant unset bit in `[begin..upTo]`.
    /// If no unset bit is found, returns `type(uint256).max`.
    function _findFirstUnset(Bitmap storage bitmap, uint256 begin, uint256 upTo)
        internal
        view
        returns (uint256 unsetBitIndex)
    {
        /// @solidity memory-safe-assembly
        assembly {
            unsetBitIndex := not(0) // Initialize to `type(uint256).max`.
            let s := shl(96, bitmap.slot) // Storage offset of the bitmap.
            let bucket := add(s, shr(8, begin))
            let negBits := shl(and(0xff, begin), shr(and(0xff, begin), not(sload(bucket))))
            if iszero(negBits) {
                let lastBucket := add(s, shr(8, upTo))
                for {} 1 {} {
                    bucket := add(bucket, 1)
                    negBits := not(sload(bucket))
                    if or(negBits, gt(bucket, lastBucket)) { break }
                }
                if gt(bucket, lastBucket) {
                    negBits := shr(and(0xff, not(upTo)), shl(and(0xff, not(upTo)), negBits))
                }
            }
            if negBits {
                // Find-first-set routine.
                // From: https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol
                let b := and(negBits, add(not(negBits), 1)) // Isolate the least significant bit.
                // For the upper 3 bits of the result, use a De Bruijn-like lookup.
                // Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
                // forgefmt: disable-next-item
                let r := shl(5, shr(252, shl(shl(2, shr(250, mul(b,
                    0x2aaaaaaaba69a69a6db6db6db2cb2cb2ce739ce73def7bdeffffffff))),
                    0x1412563212c14164235266736f7425221143267a45243675267677)))
                // For the lower 5 bits of the result, use a De Bruijn lookup.
                // forgefmt: disable-next-item
                r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f),
                    0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
                r := or(shl(8, sub(bucket, s)), r)
                unsetBitIndex := or(r, sub(0, or(gt(r, upTo), lt(r, begin))))
            }
        }
    }

    /// @dev Returns a storage reference to the value at (`a0`, `a1`) in `map`.
    function _ref(AddressPairToUint256RefMap storage map, address a0, address a1)
        internal
        pure
        returns (Uint256Ref storage ref)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x28, a1)
            mstore(0x14, a0)
            mstore(0x00, map.slot)
            ref.slot := keccak256(0x00, 0x48)
            // Clear the part of the free memory pointer that was overwritten.
            mstore(0x28, 0x00)
        }
    }

    /// @dev Wraps the NFT ID.
    function _wrapNFTId(uint256 id, uint256 maxId) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := or(mul(iszero(gt(id, maxId)), id), gt(id, maxId))
        }
    }

    /// @dev Returns `id > type(uint32).max ? 0 : id`.
    function _restrictNFTId(uint256 id) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mul(id, lt(id, 0x100000000))
        }
    }

    /// @dev Returns whether `amount` is an invalid `totalSupply`.
    function _totalSupplyOverflows(uint256 amount) internal view returns (bool result) {
        uint256 unit = _unit();
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(iszero(or(shr(96, amount), lt(0xfffffffe, div(amount, unit)))))
        }
    }

    /// @dev Returns `max(0, x - y)`.
    function _zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Returns `x < y ? x : y`.
    function _min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /// @dev Returns `b ? 1 : 0`.
    function _toUint(bool b) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(iszero(b))
        }
    }

    /// @dev Initiates memory allocation for direct logs with `n` log items.
    function _directLogsMalloc(uint256 n, address from, address to)
        internal
        pure
        returns (bytes32 p)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // `p`'s layout:
            //    uint256 offset;
            //    uint256[] logs;
            p := mload(0x40)
            let m := add(p, 0x40)
            mstore(m, 0x144027d3) // `logDirectTransfer(address,address,uint256[])`.
            mstore(add(m, 0x20), shr(96, shl(96, from)))
            mstore(add(m, 0x40), shr(96, shl(96, to)))
            mstore(add(m, 0x60), 0x60) // Offset of `logs` in the calldata to send.
            // Skip 4 words: `fnSelector`, `from`, `to`, `calldataLogsOffset`.
            let logs := add(0x80, m)
            mstore(logs, n) // Store the length.
            let offset := add(0x20, logs) // Skip the word for `p.logs.length`.
            mstore(0x40, add(offset, shl(5, n))) // Allocate memory.
            mstore(add(0x20, p), logs) // Set `p.logs`.
            mstore(p, offset) // Set `p.offset`.
        }
    }

    /// @dev Adds a direct log item to `p` with token `id`.
    function _directLogsAppend(bytes32 p, uint256 id) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let offset := mload(p)
            mstore(offset, id)
            mstore(p, add(offset, 0x20))
        }
    }

    /// @dev Calls the `mirror` NFT contract to emit {Transfer} events for packed logs `p`.
    function _directLogsSend(bytes32 p, DN404Storage storage $) internal {
        address mirror = $.mirrorERC721;
        /// @solidity memory-safe-assembly
        assembly {
            let logs := mload(add(p, 0x20))
            let n := add(0x84, shl(5, mload(logs))) // Length of calldata to send.
            let o := sub(logs, 0x80) // Start of calldata to send.
            if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) {
                revert(o, 0x00)
            }
        }
    }

    /// @dev Returns the token IDs of the direct logs.
    function _directLogsIds(bytes32 p) internal pure returns (uint256[] memory ids) {
        /// @solidity memory-safe-assembly
        assembly {
            if p { ids := mload(add(p, 0x20)) }
        }
    }

    /// @dev Initiates memory allocation for packed logs with `n` log items.
    function _packedLogsMalloc(uint256 n) internal pure returns (bytes32 p) {
        /// @solidity memory-safe-assembly
        assembly {
            // `p`'s layout:
            //     uint256 offset;
            //     uint256 addressAndBit;
            //     uint256[] logs;
            p := mload(0x40)
            let logs := add(p, 0xa0)
            mstore(logs, n) // Store the length.
            let offset := add(0x20, logs) // Skip the word for `p.logs.length`.
            mstore(0x40, add(offset, shl(5, n))) // Allocate memory.
            mstore(add(0x40, p), logs) // Set `p.logs`.
            mstore(p, offset) // Set `p.offset`.
        }
    }

    /// @dev Set the current address and the burn bit.
    function _packedLogsSet(bytes32 p, address a, uint256 burnBit) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(p, 0x20), or(shl(96, a), burnBit)) // Set `p.addressAndBit`.
        }
    }

    /// @dev Adds a packed log item to `p` with token `id`.
    function _packedLogsAppend(bytes32 p, uint256 id) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let offset := mload(p)
            mstore(offset, or(mload(add(p, 0x20)), shl(8, id))) // `p.addressAndBit | (id << 8)`.
            mstore(p, add(offset, 0x20))
        }
    }

    /// @dev Calls the `mirror` NFT contract to emit {Transfer} events for packed logs `p`.
    function _packedLogsSend(bytes32 p, DN404Storage storage $) internal {
        address mirror = $.mirrorERC721;
        /// @solidity memory-safe-assembly
        assembly {
            let logs := mload(add(p, 0x40))
            let o := sub(logs, 0x40) // Start of calldata to send.
            mstore(o, 0x263c69d6) // `logTransfer(uint256[])`.
            mstore(add(o, 0x20), 0x20) // Offset of `logs` in the calldata to send.
            let n := add(0x44, shl(5, mload(logs))) // Length of calldata to send.
            if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) {
                revert(o, 0x00)
            }
        }
    }

    /// @dev Returns the token IDs of the packed logs (destructively).
    function _packedLogsIds(bytes32 p) internal pure returns (uint256[] memory ids) {
        /// @solidity memory-safe-assembly
        assembly {
            if p {
                ids := mload(add(p, 0x40))
                let o := add(ids, 0x20)
                let end := add(o, shl(5, mload(ids)))
                for {} iszero(eq(o, end)) { o := add(o, 0x20) } {
                    mstore(o, shr(168, shl(160, mload(o))))
                }
            }
        }
    }

    /// @dev Returns an array of zero addresses.
    function _zeroAddresses(uint256 n) internal pure returns (address[] memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            mstore(0x40, add(add(result, 0x20), shl(5, n)))
            mstore(result, n)
            codecopy(add(result, 0x20), codesize(), shl(5, n))
        }
    }

    /// @dev Returns an array each set to `value`.
    function _filled(uint256 n, uint256 value) private pure returns (uint256[] memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let o := add(result, 0x20)
            let end := add(o, shl(5, n))
            mstore(0x40, end)
            mstore(result, n)
            for {} iszero(eq(o, end)) { o := add(o, 0x20) } { mstore(o, value) }
        }
    }

    /// @dev Returns an array each set to `value`.
    function _filled(uint256 n, address value) internal pure returns (address[] memory result) {
        result = _toAddresses(_filled(n, uint160(value)));
    }

    /// @dev Concatenates the arrays.
    function _concat(uint256[] memory a, uint256[] memory b)
        internal
        view
        returns (uint256[] memory result)
    {
        uint256 aN = a.length;
        uint256 bN = b.length;
        if (aN == uint256(0)) return b;
        if (bN == uint256(0)) return a;
        /// @solidity memory-safe-assembly
        assembly {
            let n := add(aN, bN)
            if n {
                result := mload(0x40)
                mstore(result, n)
                let o := add(result, 0x20)
                mstore(0x40, add(o, shl(5, n)))
                let aL := shl(5, aN)
                pop(staticcall(gas(), 4, add(a, 0x20), aL, o, aL))
                pop(staticcall(gas(), 4, add(b, 0x20), shl(5, bN), add(o, aL), shl(5, bN)))
            }
        }
    }

    /// @dev Concatenates the arrays.
    function _concat(address[] memory a, address[] memory b)
        internal
        view
        returns (address[] memory result)
    {
        result = _toAddresses(_concat(_toUints(a), _toUints(b)));
    }

    /// @dev Reinterpret cast to an uint array.
    function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an address array.
    function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Struct of temporary variables for transfers.
    struct _DNTransferTemps {
        uint256 numNFTBurns;
        uint256 numNFTMints;
        uint256 fromOwnedLength;
        uint256 toOwnedLength;
        uint256 totalNFTSupply;
        uint256 fromEnd;
        uint256 toEnd;
        uint32 toAlias;
        uint256 nextTokenId;
        uint32 burnedPoolTail;
        bytes32 directLogs;
        bytes32 packedLogs;
    }

    /// @dev Struct of temporary variables for mints.
    struct _DNMintTemps {
        uint256 nextTokenId;
        uint32 burnedPoolTail;
        uint256 toEnd;
        uint32 toAlias;
        uint256 numNFTMints;
        bytes32 packedLogs;
    }

    /// @dev Struct of temporary variables for burns.
    struct _DNBurnTemps {
        uint256 fromBalance;
        uint256 totalSupply;
        uint256 numNFTBurns;
        bytes32 packedLogs;
    }

    /// @dev Returns the calldata value at `offset`.
    function _calldataload(uint256 offset) private pure returns (uint256 value) {
        /// @solidity memory-safe-assembly
        assembly {
            value := calldataload(offset)
        }
    }

    /// @dev Executes a return opcode to return `x` and end the current call frame.
    function _return(uint256 x) private pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, x)
            return(0x00, 0x20)
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @title DN404Mirror
/// @notice DN404Mirror provides an interface for interacting with the
/// NFT tokens in a DN404 implementation.
///
/// @author vectorized.eth (@optimizoor)
/// @author Quit (@0xQuit)
/// @author Michael Amadi (@AmadiMichaels)
/// @author cygaar (@0xCygaar)
/// @author Thomas (@0xjustadev)
/// @author Harrison (@PopPunkOnChain)
///
/// @dev Note:
/// - The ERC721 data is stored in the base DN404 contract.
contract DN404Mirror {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                           EVENTS                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Emitted when token `id` is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    /// @dev Emitted when `owner` enables `account` to manage the `id` token.
    event Approval(address indexed owner, address indexed account, uint256 indexed id);

    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This is for marketplace signaling purposes. This contract has a `pullOwner()`
    /// function that will sync the owner from the base contract.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
    uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        CUSTOM ERRORS                       */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Thrown when a call for an NFT function did not originate
    /// from the base DN404 contract.
    error SenderNotBase();

    /// @dev Thrown when a call for an NFT function did not originate from the deployer.
    error SenderNotDeployer();

    /// @dev Thrown when transferring an NFT to a contract address that
    /// does not implement ERC721Receiver.
    error TransferToNonERC721ReceiverImplementer();

    /// @dev Thrown when a linkMirrorContract call is received and the
    /// NFT mirror contract has already been linked to a DN404 base contract.
    error AlreadyLinked();

    /// @dev Thrown when retrieving the base DN404 address when a link has not
    /// been established.
    error NotLinked();

    /// @dev The function selector is not recognized.
    error FnSelectorNotRecognized();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Struct contain the NFT mirror contract storage.
    struct DN404NFTStorage {
        // Address of the ERC20 base contract.
        address baseERC20;
        // The deployer, if provided. If non-zero, the initialization of the
        // ERC20 <-> ERC721 link can only be done by the deployer via the ERC20 base contract.
        address deployer;
        // The owner of the ERC20 base contract. For marketplace signaling.
        address owner;
    }

    /// @dev Returns a storage pointer for DN404NFTStorage.
    function _getDN404NFTStorage() internal pure virtual returns (DN404NFTStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `uint72(bytes9(keccak256("DN404_MIRROR_STORAGE")))`.
            $.slot := 0x3602298b8c10b01230 // Truncate to 9 bytes to reduce bytecode size.
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        CONSTRUCTOR                         */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    constructor(address deployer) {
        // For non-proxies, we will store the deployer so that only the deployer can
        // link the base contract.
        _getDN404NFTStorage().deployer = deployer;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                     ERC721 OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the token collection name from the base DN404 contract.
    function name() public view virtual returns (string memory) {
        return _readString(0x06fdde03, 0); // `name()`.
    }

    /// @dev Returns the token collection symbol from the base DN404 contract.
    function symbol() public view virtual returns (string memory) {
        return _readString(0x95d89b41, 0); // `symbol()`.
    }

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id` from
    /// the base DN404 contract.
    function tokenURI(uint256 id) public view virtual returns (string memory) {
        ownerOf(id); // `ownerOf` reverts if the token does not exist.
        // We'll leave if optional for `_tokenURI` to revert for non-existent token
        // on the ERC20 side, since this is only recommended by the ERC721 standard.
        return _readString(0xc87b56dd, id); // `tokenURI(uint256)`.
    }

    /// @dev Returns the total NFT supply from the base DN404 contract.
    function totalSupply() public view virtual returns (uint256) {
        return _readWord(0xe2c79281, 0, 0); // `totalNFTSupply()`.
    }

    /// @dev Returns the number of NFT tokens owned by `nftOwner` from the base DN404 contract.
    ///
    /// Requirements:
    /// - `nftOwner` must not be the zero address.
    function balanceOf(address nftOwner) public view virtual returns (uint256) {
        return _readWord(0xf5b100ea, uint160(nftOwner), 0); // `balanceOfNFT(address)`.
    }

    /// @dev Returns the owner of token `id` from the base DN404 contract.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function ownerOf(uint256 id) public view virtual returns (address) {
        return address(uint160(_readWord(0x6352211e, id, 0))); // `ownerOf(uint256)`.
    }

    /// @dev Returns the owner of token `id` from the base DN404 contract.
    /// Returns `address(0)` instead of reverting if the token does not exist.
    function ownerAt(uint256 id) public view virtual returns (address) {
        return address(uint160(_readWord(0x24359879, id, 0))); // `ownerAt(uint256)`.
    }

    /// @dev Sets `spender` as the approved account to manage token `id` in
    /// the base DN404 contract.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - The caller must be the owner of the token,
    ///   or an approved operator for the token owner.
    ///
    /// Emits an {Approval} event.
    function approve(address spender, uint256 id) public payable virtual {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            spender := shr(96, shl(96, spender))
            let m := mload(0x40)
            mstore(0x00, 0xd10b6e0c) // `approveNFT(address,uint256,address)`.
            mstore(0x20, spender)
            mstore(0x40, id)
            mstore(0x60, caller())
            if iszero(
                and( // Arguments of `and` are evaluated last to first.
                    gt(returndatasize(), 0x1f), // The call must return at least 32 bytes.
                    call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
            // Emit the {Approval} event.
            log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x0c)), spender, id)
        }
    }

    /// @dev Returns the account approved to manage token `id` from
    /// the base DN404 contract.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function getApproved(uint256 id) public view virtual returns (address) {
        return address(uint160(_readWord(0x081812fc, id, 0))); // `getApproved(uint256)`.
    }

    /// @dev Sets whether `operator` is approved to manage the tokens of the caller in
    /// the base DN404 contract.
    ///
    /// Emits an {ApprovalForAll} event.
    function setApprovalForAll(address operator, bool approved) public virtual {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            operator := shr(96, shl(96, operator))
            let m := mload(0x40)
            mstore(0x00, 0x813500fc) // `setApprovalForAll(address,bool,address)`.
            mstore(0x20, operator)
            mstore(0x40, iszero(iszero(approved)))
            mstore(0x60, caller())
            if iszero(
                and( // Arguments of `and` are evaluated last to first.
                    eq(mload(0x00), 1), // The call must return 1.
                    call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            // Emit the {ApprovalForAll} event.
            // The `approved` value is already at 0x40.
            log3(0x40, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), operator)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Returns whether `operator` is approved to manage the tokens of `nftOwner` from
    /// the base DN404 contract.
    function isApprovedForAll(address nftOwner, address operator)
        public
        view
        virtual
        returns (bool)
    {
        // `isApprovedForAll(address,address)`.
        return _readWord(0xe985e9c5, uint160(nftOwner), uint160(operator)) != 0;
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 id) public payable virtual {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            from := shr(96, shl(96, from))
            to := shr(96, shl(96, to))
            let m := mload(0x40)
            mstore(m, 0xe5eb36c8) // `transferFromNFT(address,address,uint256,address)`.
            mstore(add(m, 0x20), from)
            mstore(add(m, 0x40), to)
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), caller())
            if iszero(
                and( // Arguments of `and` are evaluated last to first.
                    eq(mload(m), 1), // The call must return 1.
                    call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20)
                )
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
    }

    /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
    function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
        public
        payable
        virtual
    {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                  OWNER SYNCING OPERATIONS                  */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the `owner` of the contract, for marketplace signaling purposes.
    function owner() public view virtual returns (address) {
        return _getDN404NFTStorage().owner;
    }

    /// @dev Permissionless function to pull the owner from the base DN404 contract
    /// if it implements ownable, for marketplace signaling purposes.
    function pullOwner() public virtual returns (bool) {
        address newOwner;
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x8da5cb5b) // `owner()`.
            let success := staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)
            newOwner := mul(shr(96, mload(0x0c)), and(gt(returndatasize(), 0x1f), success))
        }
        DN404NFTStorage storage $ = _getDN404NFTStorage();
        address oldOwner = $.owner;
        if (oldOwner != newOwner) {
            $.owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
        return true;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                     MIRROR OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns the address of the base DN404 contract.
    function baseERC20() public view virtual returns (address base) {
        base = _getDN404NFTStorage().baseERC20;
        if (base == address(0)) revert NotLinked();
    }

    /// @dev Fallback modifier to execute calls from the base DN404 contract.
    modifier dn404NFTFallback() virtual {
        DN404NFTStorage storage $ = _getDN404NFTStorage();

        uint256 fnSelector = _calldataload(0x00) >> 224;

        // `logTransfer(uint256[])`.
        if (fnSelector == 0x263c69d6) {
            if (msg.sender != $.baseERC20) revert SenderNotBase();
            /// @solidity memory-safe-assembly
            assembly {
                let o := add(0x24, calldataload(0x04)) // Packed logs offset.
                let end := add(o, shl(5, calldataload(sub(o, 0x20))))
                for {} iszero(eq(o, end)) { o := add(0x20, o) } {
                    let d := calldataload(o) // Entry in the packed logs.
                    let a := shr(96, d) // The address.
                    let b := and(1, d) // Whether it is a burn.
                    log4(
                        codesize(),
                        0x00,
                        _TRANSFER_EVENT_SIGNATURE,
                        mul(a, b), // `from`.
                        mul(a, iszero(b)), // `to`.
                        shr(168, shl(160, d)) // `id`.
                    )
                }
                mstore(0x00, 0x01)
                return(0x00, 0x20)
            }
        }
        // `logDirectTransfer(address,address,uint256[])`.
        if (fnSelector == 0x144027d3) {
            if (msg.sender != $.baseERC20) revert SenderNotBase();
            /// @solidity memory-safe-assembly
            assembly {
                let from := calldataload(0x04)
                let to := calldataload(0x24)
                let o := add(0x24, calldataload(0x44)) // Direct logs offset.
                let end := add(o, shl(5, calldataload(sub(o, 0x20))))
                for {} iszero(eq(o, end)) { o := add(0x20, o) } {
                    log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, calldataload(o))
                }
                mstore(0x00, 0x01)
                return(0x00, 0x20)
            }
        }
        // `linkMirrorContract(address)`.
        if (fnSelector == 0x0f4599e5) {
            if ($.deployer != address(0)) {
                if (address(uint160(_calldataload(0x04))) != $.deployer) {
                    revert SenderNotDeployer();
                }
            }
            if ($.baseERC20 != address(0)) revert AlreadyLinked();
            $.baseERC20 = msg.sender;
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x00, 0x01)
                return(0x00, 0x20)
            }
        }
        _;
    }

    /// @dev Fallback function for calls from base DN404 contract.
    /// Override this if you need to implement your custom
    /// fallback with utilities like Solady's `LibZip.cdFallback()`.
    /// And always remember to always wrap the fallback with `dn404NFTFallback`.
    fallback() external payable virtual dn404NFTFallback {
        revert FnSelectorNotRecognized(); // Not mandatory. Just for quality of life.
    }

    /// @dev This is to silence the compiler warning.
    /// Override and remove the revert if you want your contract to receive ETH via receive.
    receive() external payable virtual {
        if (msg.value != 0) revert();
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      PRIVATE HELPERS                       */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Helper to read a string from the base DN404 contract.
    function _readString(uint256 fnSelector, uint256 arg0)
        private
        view
        returns (string memory result)
    {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            mstore(0x00, fnSelector)
            mstore(0x20, arg0)
            if iszero(staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x00)) {
                returndatacopy(result, 0x00, returndatasize())
                revert(result, returndatasize())
            }
            returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the string in returndata.
            returndatacopy(result, mload(0x00), 0x20) // Copy the length of the string.
            returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) // Copy the string.
            let end := add(add(result, 0x20), mload(result))
            mstore(end, 0) // Zeroize the word after the string.
            mstore(0x40, add(end, 0x20)) // Allocate memory.
        }
    }

    /// @dev Helper to read a word from the base DN404 contract.
    function _readWord(uint256 fnSelector, uint256 arg0, uint256 arg1)
        private
        view
        returns (uint256 result)
    {
        address base = baseERC20();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(0x00, fnSelector)
            mstore(0x20, arg0)
            mstore(0x40, arg1)
            if iszero(
                and( // Arguments of `and` are evaluated last to first.
                    gt(returndatasize(), 0x1f), // The call must return at least 32 bytes.
                    staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20)
                )
            ) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x40, m) // Restore the free memory pointer.
            result := mload(0x00)
        }
    }

    /// @dev Returns the calldata value at `offset`.
    function _calldataload(uint256 offset) private pure returns (uint256 value) {
        /// @solidity memory-safe-assembly
        assembly {
            value := calldataload(offset)
        }
    }

    /// @dev Returns if `a` has bytecode of non-zero length.
    function _hasCode(address a) private view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := extcodesize(a) // Can handle dirty upper bits.
        }
    }

    /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
    /// Reverts if the target does not support the function correctly.
    function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
        private
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the calldata.
            let m := mload(0x40)
            let onERC721ReceivedSelector := 0x150b7a02
            mstore(m, onERC721ReceivedSelector)
            mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
            mstore(add(m, 0x40), shr(96, shl(96, from)))
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), 0x80)
            let n := mload(data)
            mstore(add(m, 0xa0), n)
            if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
            // Revert if the call reverts.
            if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
                if returndatasize() {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
            // Load the returndata and compare it.
            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 11 of 11 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS =
        0x000000000000000000636F6e736F6c652e6c6f67;

    function _sendLogPayloadImplementation(bytes memory payload) internal view {
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            pop(
                staticcall(
                    gas(),
                    consoleAddress,
                    add(payload, 32),
                    mload(payload),
                    0,
                    0
                )
            )
        }
    }

    function _castToPure(
      function(bytes memory) internal view fnIn
    ) internal pure returns (function(bytes memory) pure fnOut) {
        assembly {
            fnOut := fnIn
        }
    }

    function _sendLogPayload(bytes memory payload) internal pure {
        _castToPure(_sendLogPayloadImplementation)(payload);
    }

    function log() internal pure {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }
    function logInt(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function logUint(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function logString(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function log(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint256 p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
    }

    function log(uint256 p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
    }

    function log(uint256 p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
    }

    function log(uint256 p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
    }

    function log(string memory p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
    }

    function log(bool p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
    }

    function log(address p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "metadata": {
    "useLiteralContent": true
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"lpTokenReserve","type":"address"},{"internalType":"address","name":"teamReserve","type":"address"}],"internalType":"struct ConstructorConfig","name":"config_","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"DNAlreadyInitialized","type":"error"},{"inputs":[],"name":"DNNotInitialized","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FnSelectorNotRecognized","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidUnit","type":"error"},{"inputs":[],"name":"LinkMirrorContractFailed","type":"error"},{"inputs":[],"name":"MirrorAddressIsZero","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"SenderNotMirror","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","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":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SkipNFTSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MAX_COIN_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_lpTokenReserve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_teamReserve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"quantity","type":"uint32"}],"name":"adminAddToBurnPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"},{"internalType":"uint8","name":"drop_","type":"uint8"}],"name":"adminChangePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Louder.State","name":"state_","type":"uint8"}],"name":"adminChangeState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"adminSetLpTokenReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_skipNFT","type":"bool"}],"name":"adminSetSkipNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"adminSetTeamReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"payee","type":"address"}],"name":"adminWithdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"lock_","type":"bool"}],"name":"changeLockState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentDrop","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentState","outputs":[{"internalType":"enum Louder.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"dropData","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"drop_","type":"uint8"}],"name":"getDropSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"getOwnedNFTs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getSkipNFT","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"quantity","type":"uint64"},{"internalType":"uint8","name":"drop_","type":"uint8"}],"name":"mintPresale","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mirrorERC721","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"internalType":"struct TransferTo[]","name":"transfers_","type":"tuple[]"}],"name":"multiTransferToEOA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_canTransfer","type":"bool"}],"name":"setCanAlwaysTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"skipNFT","type":"bool"}],"name":"setSkipNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"dropSupply","type":"uint256"}],"name":"startDrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","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":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin_","type":"address"}],"name":"transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlockForever","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526b033b2e3c9fd0803ce80000006002556006805462ffff00191690553480156200002d57600080fd5b5060405162005be738038062005be7833981016040819052620000509162000d40565b60608101516001600160a01b0381166200008557604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6200009081620001d1565b506007805460ff60a01b191690556040810151620000ae9062000221565b6060810151620000be90620001d1565b8051600390620000cf908262000ea9565b506020810151600490620000e4908262000ea9565b506006805461ffff191660019081179091556040808301516001600160a01b03166000908152600960205220805460ff1916909117905560808101516200012b9062000273565b60a08101516200013b90620002c8565b6000336040516200014c9062000c19565b6001600160a01b039091168152602001604051809103906000f08015801562000179573d6000803e3d6000fd5b509050620001946000836040015183620002f060201b60201c565b6040820151620001a690600162000491565b600754620001c9906001600160a01b03166a084595161401484a00000062000533565b505062000f9d565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a35050565b600680546301000000600160b81b03191663010000006001600160a01b03841602179055620002a481600162000491565b6001600160a01b03166000908152600960205260409020805460ff19166001179055565b600780546001600160a01b0319166001600160a01b038316179055620002a481600162000491565b68a20d6e21d0e52553095468a20d6e21d0e5255308906001600160a01b0316156200032e57604051633ab534b960e21b815260040160405180910390fd5b6001600160a01b03821662000356576040516339a84a7b60e01b815260040160405180910390fd5b630f4599e560005233602052602060006024601c6000865af160016000511416620003895763d125259c6000526004601cfd5b805463ffffffff60201b19166401000000001781556001810180546001600160a01b0384166001600160a01b031990911617905583156200048b576001600160a01b038316620003ec57604051633a954ecd60e21b815260040160405180910390fd5b606084901c69021e19e0c9bab2400000850463fffffffe101715620004245760405163e5cfe95760e01b815260040160405180910390fd5b80546001600160601b038516600160a01b026001600160a01b03918216811783558482166000818152600b850160209081526040822080549095169093178455878152909160008051602062005bc78339815191529082a36200048984600162000491565b505b50505050565b600068a20d6e21d0e52553086001600160a01b0384166000818152600b92909201602090815260408320805486158015865291955060ff6b0100000000000000000000009091049081166002918216159092180218600117927fb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d64203939190a2815460ff9091166b0100000000000000000000000260ff60581b199091161790555050565b6001600160a01b0382166200055b57604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553095468a20d6e21d0e5255308906001600160a01b0316620005985760405163040739bf60e41b815260040160405180910390fd5b6001600160a01b0383166000908152600b8201602052604081208254909190620005d4908590600160a01b90046001600160601b031662000f75565b9050600254811115620006415760405162461bcd60e51b815260206004820152602e60248201527f546f74616c20737570706c79206f6620636f696e732063616e206e6f7420657860448201526d31b2b2b21018903134b63634b7b760911b60648201526084016200007c565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915282546001600160601b03600160a01b80830482168801918216026001600160a01b0390921691909117845569021e19e0c9bab2400000810460408301525083546001600160601b038316600160a01b026001600160a01b03909116178455600080620006f8606085901c69021e19e0c9bab2400000860463fffffffe10171515151590565b90508684108117156200071e5760405163e5cfe95760e01b815260040160405180910390fd5b505069021e19e0c9bab24000008204620007388762000979565b62000941576001600160a01b03871660009081526008860160205260408082208654918501519092600a890192600160801b900463ffffffff169162000782908380821191030290565b6080870181905203620007985750505062000941565b60808501516040805160a0810183815260059390931b810160c09081018352918101929092528101815260a0860181905260608b901b6020909101526080850151885463ffffffff600160801b80830482169093018116830263ffffffff60801b19928316178b5560408801518a54911690920291161787556200081d878b620009ca565b63ffffffff9081166060870152885464010000000090041684811180159091021785525b84515b6200087583600019830160011b60008160031c8360601b0180546007841660051b1c63ffffffff1691505092915050565b63ffffffff1615620008935760010184811180159091021762000844565b600181018581118015909102178652600382901c606085901b018054600584901b60e01681811c841863ffffffff16901b189055620008e5838288606001518580600101965062000b3f60201b60201c565b60a08601518051602080830151600885901b178252019052508460400151810362000841578451885463ffffffff9091166401000000000263ffffffff60201b1990911617885560a08501516200093d908962000b81565b5050505b5060008581526001600160a01b0387169060008051602062005bc7833981519152602082a362000971565b505050565b505050505050565b6001600160a01b038116600090815268a20d6e21d0e525531360205260409020546b01000000000000000000000090046002811615159060ff811690600116620009c457823b151591505b50919050565b81546c01000000000000000000000000900463ffffffff1668a20d6e21d0e52553088162000a6457805463ffffffff198116600163ffffffff928316019182169081178355855463ffffffff60601b19166c0100000000000000000000000082021786556000818152600284016020526040902080546001600160a01b0319166001600160a01b03871617905590925062000a6457600080fd5b5092915050565b600183019250825419915080831182171562000a6b578083111562000a975760ff86191691821b90911c905b50801562000b355782820360081b7e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405821960010183166101e07a1412563212c14164235266736f7425221143267a4524367526767760fc7b2aaaaaaaba69a69a6db6db6db2cb2cb2ce739ce73def7bdeffffffff840260f81c161b60f71c1690811c63d76453e004601f169190911a1717858111878210176000031793505b5050509392505050565b600183038060021c8560601b0180546003831660061b92508463ffffffff168460201b178082851c186001600160401b0316841b821883555050505050505050565b6001810154604083015163263c69d6603f1982019081526020601f19830181905282516001600160a01b039094169360051b6044019282908490602319016000875af16001825114166200048957600081fd5b80821462000bf257815160a01b60a81c825260208201915062000bd4565b50505b919050565b80821462000c115783825260208201915062000bfa565b505092915050565b610d5f8062004e6883390190565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b038111828210171562000c625762000c6262000c27565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000c935762000c9362000c27565b604052919050565b600082601f83011262000cad57600080fd5b81516001600160401b0381111562000cc95762000cc962000c27565b602062000cdf601f8301601f1916820162000c68565b828152858284870101111562000cf457600080fd5b60005b8381101562000d1457858101830151828201840152820162000cf7565b506000928101909101919091529392505050565b80516001600160a01b038116811462000bf557600080fd5b60006020828403121562000d5357600080fd5b81516001600160401b038082111562000d6b57600080fd5b9083019060c0828603121562000d8057600080fd5b62000d8a62000c3d565b82518281111562000d9a57600080fd5b62000da88782860162000c9b565b82525060208301518281111562000dbe57600080fd5b62000dcc8782860162000c9b565b60208301525062000de06040840162000d28565b604082015262000df36060840162000d28565b606082015262000e066080840162000d28565b608082015262000e1960a0840162000d28565b60a082015295945050505050565b600181811c9082168062000e3c57607f821691505b602082108103620009c457634e487b7160e01b600052602260045260246000fd5b601f8211156200096c576000816000526020600020601f850160051c8101602086101562000e885750805b601f850160051c820191505b81811015620009715782815560010162000e94565b81516001600160401b0381111562000ec55762000ec562000c27565b62000edd8162000ed6845462000e27565b8462000e5d565b602080601f83116001811462000f15576000841562000efc5750858301515b600019600386901b1c1916600185901b17855562000971565b600085815260208120601f198616915b8281101562000f465788860151825594840194600190910190840162000f25565b508582101562000f655787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111562000f9757634e487b7160e01b600052601160045260246000fd5b92915050565b613ebb8062000fad6000396000f3fe6080604052600436106102555760003560e01c806370a0823111610139578063a9059cbb116100b6578063e3163ee51161007a578063e3163ee5146109e9578063ea5cb2a414610a09578063f10e737314610a29578063f2fde38b14610a49578063f851a44014610a69578063fc46a07614610a8957610267565b8063a9059cbb14610934578063b6e6e3aa14610954578063ba486f3514610974578063c1a2c2171461098a578063dd62ed3e146109aa57610267565b80638da5cb5b116100fd5780638da5cb5b1461088357806395d89b41146108a157806398d5fdca146108b65780639b58d54c146108cb578063a79f5b15146108eb57610267565b806370a08231146107f9578063715018a61461081957806372b03ef31461082e57806375829def1461084e57806375be58461461086e57610267565b806330f33395116101d25780634508d6ff116101965780634508d6ff1461073857806348fc03361461074d57806349b01efd1461076d5780634ef41efc146107a05780634fc75ad9146107c657806355f804b3146107d957610267565b806330f3339514610690578063313ce567146106c457806334d7d378146106d857806336d0c1be146106f8578063449a52f81461071857610267565b806318148f1b1161021957806318148f1b146105cc57806318160ddd146105f957806323b872dd14610630578063274e430b146106505780632a6a935d1461067057610267565b806306fdde0314610503578063095ea7b31461052e5780630c3f6acf1461055e5780631245c65314610580578063134f81c5146105ac57610267565b3661026757341561026557600080fd5b005b68a20d6e21d0e525530860003560e01c63e5eb36c88190036102ce5760018201546001600160a01b031633146102b05760405163ce5a776b60e01b815260040160405180910390fd5b6102c4600435602435604435606435610aa9565b6102ce6001610df4565b8063813500fc0361033a5760018201546001600160a01b031633146103065760405163ce5a776b60e01b815260040160405180910390fd5b600435602890815260443560145268a20d6e21d0e525530b60009081526048812091526024351515905561033a6001610df4565b8063e985e9c503610364576000610355600435602435610dfe565b9050610362811515610df4565b505b80636352211e0361038b5761038b61037d600435610e27565b6001600160a01b0316610df4565b806324359879036103a4576103a461037d600435610e54565b8063d10b6e0c036104055760018201546001600160a01b031633146103dc5760405163ce5a776b60e01b815260040160405180910390fd5b60006103ef600435602435604435610eb0565b9050610403816001600160a01b0316610df4565b505b8063081812fc0361041e5761041e61037d600435610f7e565b8063f5b100ea03610462576001600160a01b0360043516600090815268a20d6e21d0e5255313602052604090205461046290600160801b900463ffffffff16610df4565b8063e2c792810361048e5768a20d6e21d0e52553085461048e90600160801b900463ffffffff16610df4565b8063c87b56dd036104d55760206040510160405260006104b56104b060043590565b610fca565b90506020810360408251016000818301526020825280601f01601f191682f35b8063b7a94eb8036104ea576104ea6001610df4565b604051631e085ca760e11b815260040160405180910390fd5b34801561050f57600080fd5b50610518611013565b60405161052591906136db565b60405180910390f35b34801561053a57600080fd5b5061054e610549366004613723565b6110a5565b6040519015158152602001610525565b34801561056a57600080fd5b506105736110bb565b6040516105259190613765565b34801561058c57600080fd5b5060065462010000900460ff165b60405160ff9091168152602001610525565b3480156105b857600080fd5b506102656105c736600461378d565b6110cb565b3480156105d857600080fd5b506105ec6105e73660046137b3565b61110a565b60405161052591906137d0565b34801561060557600080fd5b5068a20d6e21d0e525530854600160a01b90046001600160601b03165b604051908152602001610525565b34801561063c57600080fd5b5061054e61064b366004613814565b61115a565b34801561065c57600080fd5b5061054e61066b3660046137b3565b6111b6565b34801561067c57600080fd5b5061054e61068b366004613865565b6111fe565b34801561069c57600080fd5b506006546106b790630100000090046001600160a01b031681565b6040516105259190613880565b3480156106d057600080fd5b50601261059a565b3480156106e457600080fd5b506102656106f3366004613894565b611212565b34801561070457600080fd5b506007546106b7906001600160a01b031681565b34801561072457600080fd5b50610265610733366004613723565b6114d2565b34801561074457600080fd5b5061026561150a565b34801561075957600080fd5b506102656107683660046137b3565b611695565b34801561077957600080fd5b506106226107883660046138c7565b60ff1660009081526008602052604090206001015490565b3480156107ac57600080fd5b5068a20d6e21d0e5255309546001600160a01b03166106b7565b6102656107d43660046138e2565b61171a565b3480156107e557600080fd5b506102656107f4366004613923565b6119f7565b34801561080557600080fd5b506106226108143660046137b3565b611a2e565b34801561082557600080fd5b50610265611a61565b34801561083a57600080fd5b50610265610849366004613994565b611a75565b34801561085a57600080fd5b506102656108693660046137b3565b611bae565b34801561087a57600080fd5b50610265611c48565b34801561088f57600080fd5b506000546001600160a01b03166106b7565b3480156108ad57600080fd5b50610518611c83565b3480156108c257600080fd5b50610622611c92565b3480156108d757600080fd5b506102656108e63660046137b3565b611cc4565b3480156108f757600080fd5b5061091f6109063660046138c7565b6008602052600090815260409020805460019091015482565b60408051928352602083019190915201610525565b34801561094057600080fd5b5061054e61094f366004613723565b611d01565b34801561096057600080fd5b5061026561096f3660046139c0565b611d52565b34801561098057600080fd5b5061062260025481565b34801561099657600080fd5b506102656109a53660046139e3565b611da1565b3480156109b657600080fd5b506106226109c5366004613a04565b602890815260149190915268a20d6e21d0e525530f60009081526048812091525490565b3480156109f557600080fd5b50610265610a04366004613a3d565b611df8565b348015610a1557600080fd5b50610265610a24366004613865565b611e7d565b348015610a3557600080fd5b50610265610a443660046137b3565b611f48565b348015610a5557600080fd5b50610265610a643660046137b3565b611f8e565b348015610a7557600080fd5b506001546106b7906001600160a01b031681565b348015610a9557600080fd5b50610265610aa4366004613994565b611fc9565b6001600160a01b038316610ad057604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553095468a20d6e21d0e5255308906001600160a01b0316610b0c5760405163040739bf60e41b815260040160405180910390fd5b600a8101600282016000610b3083610b2b600160201b8910890261201e565b612028565b63ffffffff1681526020810191909152604001600020546001600160a01b03878116911614610b715760405162a1148160e81b815260040160405180910390fd5b856001600160a01b0316836001600160a01b031614610bd257610b948684610dfe565b610bd257826001600160a01b0316610bab85610f7e565b6001600160a01b031614610bd257604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038681166000908152600b8401602052604080822092881682529020815469021e19e0c9bab2400000906008860190600160a01b90046001600160601b031680831115610c3957604051631e9acf1760e31b815260040160405180910390fd5b84546001600160601b03918490038216600160a01b9081026001600160a01b039283161787558554818104841686019093160291161783556005860160601b600889901c015460ff89161c60011615610cba57610c9b8660050189600061204c565b6000888152600487016020526040902080546001600160a01b03191690555b6001600160a01b038a166000908152602082905260408120855463ffffffff60801b198116600160801b9182900463ffffffff9081166000190116918202178755909190610d09908390612028565b90506000610d21886000198d01600190811b01612028565b9050610d34838263ffffffff1684612070565b610d4f8860001963ffffffff851601600190811b0183612070565b5050835463ffffffff60801b198116600160801b9182900463ffffffff908116600181019091169092021785556001600160a01b038b166000908152602084905260409020909150610da290828b612070565b610db7868a610db1878e61209b565b84612128565b50816000528860601b60601c8a60601b60601c600080516020613e6683398151915260206000a3610de8565b505050565b50505050505050505050565b8060005260206000f35b6028818152601483905268a20d6e21d0e525530b60009081526048812091525415155b92915050565b6000610e3282612187565b610e4f5760405163677510db60e11b815260040160405180910390fd5b610e21825b600068a20d6e21d0e525530868a20d6e21d0e525530a82610e8968a20d6e21d0e5255312610b2b600160201b8810880261201e565b63ffffffff1681526020810191909152604001600020546001600160a01b03169392505050565b600068a20d6e21d0e525530868a20d6e21d0e525530a82610ee568a20d6e21d0e5255312610b2b600160201b8910890261201e565b63ffffffff1681526020810191909152604001600020546001600160a01b03908116925083168214610f3857610f1b8284610dfe565b610f38576040516367d9dca160e11b815260040160405180910390fd5b6000848152600482016020526040902080546001600160a01b0319166001600160a01b038716908117909155610f769060058301908690151561204c565b509392505050565b6000610f8982612187565b610fa65760405163677510db60e11b815260040160405180910390fd5b50600090815268a20d6e21d0e525530c60205260409020546001600160a01b031690565b606060058054610fd990613a9f565b15905061100e576005610feb836121a4565b604051602001610ffc929190613ad3565b60405160208183030381529060405290505b919050565b60606003805461102290613a9f565b80601f016020809104026020016040519081016040528092919081815260200182805461104e90613a9f565b801561109b5780601f106110705761010080835404028352916020019161109b565b820191906000526020600020905b81548152906001019060200180831161107e57829003601f168201915b5050505050905090565b60006110b2338484612236565b50600192915050565b600754600160a01b900460ff1690565b6001546001600160a01b031633146110fe5760405162461bcd60e51b81526004016110f590613b5a565b60405180910390fd5b61110781612298565b50565b6001600160a01b038116600090815268a20d6e21d0e5255313602052604081205460609168a20d6e21d0e525530891600160801b900463ffffffff16611151858383612437565b95945050505050565b60065460009060ff16158061118757506001600160a01b03841660009081526009602052604090205460ff165b6111a35760405162461bcd60e51b81526004016110f590613b9c565b6111ae8484846124ed565b949350505050565b6001600160a01b038116600090815268a20d6e21d0e52553136020526040902054600160581b90046002811615159060ff8116906001166111f857823b151591505b50919050565b600061120a338361255b565b506001919050565b6001546001600160a01b0316331461123c5760405162461bcd60e51b81526004016110f590613b5a565b60016112466110bb565b60028111156112575761125761374f565b0361129f5760405162461bcd60e51b8152602060048201526018602482015277412064726f7020697320616c72656164792061637469766560401b60448201526064016110f5565b6006805462010000900460ff169060026112b883613be9565b91906101000a81548160ff021916908360ff160217905550506000600860006001600660029054906101000a900460ff166112f39190613c08565b60ff1681526020810191909152604001600020600101546113149083613c21565b905060025481111561137b5760405162461bcd60e51b815260206004820152602a60248201527f546f74616c20737570706c792063616e6e6f742065786365656420312062696c6044820152696c696f6e20636f696e7360b01b60648201526084016110f5565b600061139169021e19e0c9bab240000084613c4a565b9050600081116114035760405162461bcd60e51b815260206004820152603760248201527f44726f7020737570706c7920746f6f206c6f772c206e656564206174206c656160448201527673742031204e465420776f727468206f6620636f696e7360481b60648201526084016110f5565b60065462010000900460ff1660009081526008602052604081208581556001810184905590806114348660056125ed565b915091508161144557611445613c6c565b60065461146290630100000090046001600160a01b031682612621565b6000806114708860036129f9565b915091508161148157611481613c6c565b61148c8160146125ed565b90945092508361149e5761149e613c6c565b6007546114b4906001600160a01b031684612621565b50506007805460ff60a01b1916600160a01b17905550505050505050565b6001546001600160a01b031633146114fc5760405162461bcd60e51b81526004016110f590613b5a565b6115068282612621565b5050565b6001546001600160a01b031633146115345760405162461bcd60e51b81526004016110f590613b5a565b600061153e6110bb565b600281111561154f5761154f61374f565b0361156c5760405162461bcd60e51b81526004016110f590613c82565b60026115766110bb565b60028111156115875761158761374f565b036115cd5760405162461bcd60e51b8152602060048201526016602482015275111c9bdc081a185cc8185b1c9958591e48195b99195960521b60448201526064016110f5565b68a20d6e21d0e5255308805460065462010000900460ff16600090815260086020526040812060010154600160201b90920463ffffffff16919069021e19e0c9bab240000061161c9083613c4a565b9050600061162a8483613cab565b905061163581612298565b8454600160a01b90046001600160601b031683111561167b57845460009061166d90600160a01b90046001600160601b031685613cc8565b90506116793382612621565b505b50506007805460ff60a01b1916600160a11b179055505050565b6001546001600160a01b031633146116bf5760405162461bcd60e51b81526004016110f590613b5a565b6007546001600160a01b03166116d482612a42565b60006116df82611a2e565b90506116ec828483612a8c565b6116f782600061255b565b506001600160a01b03166000908152600960205260409020805460ff1916905550565b60006117246110bb565b60028111156117355761173561374f565b036117825760405162461bcd60e51b815260206004820152601a60248201527f50726573616c65206861736e277420737461727465642079657400000000000060448201526064016110f5565b600261178c6110bb565b600281111561179d5761179d61374f565b036117de5760405162461bcd60e51b8152602060048201526011602482015270141c995cd85b19481a185cc8195b991959607a1b60448201526064016110f5565b60065460ff82811662010000909204161461183b5760405162461bcd60e51b815260206004820152601c60248201527f57726f6e672070726573616c652073746167652073656c65637465640000000060448201526064016110f5565b816001600160401b03166000036118895760405162461bcd60e51b815260206004820152601260248201527143616e2774206d696e74203020636f696e7360701b60448201526064016110f5565b60006118a66001600160401b038416670de0b6b3a7640000613cdb565b68a20d6e21d0e52553088054919250906000906118d4908490600160a01b90046001600160601b0316613c21565b9050600860006118ed60065460ff620100009091041690565b60ff1660ff1681526020019081526020016000206001015481111561194c5760405162461bcd60e51b8152602060048201526015602482015274139bdd08195b9bdd59da0818dbda5b9cc81b19599d605a1b60448201526064016110f5565b60008061198d876001600160401b03166008600061197360065460ff620100009091041690565b60ff168152602081019190915260400160002054906129f9565b915091508161199e5761199e613c6c565b348111156119e45760405162461bcd60e51b8152602060048201526013602482015272139bdd08195b9bdd59da08115512081cd95b9d606a1b60448201526064016110f5565b6119ee3386612621565b50505050505050565b6001546001600160a01b03163314611a215760405162461bcd60e51b81526004016110f590613b5a565b6005610de3828483613d50565b6001600160a01b0316600090815268a20d6e21d0e52553136020526040902054600160a01b90046001600160601b031690565b611a696132ac565b611a7360006132d9565b565b6001546001600160a01b03163314611a9f5760405162461bcd60e51b81526004016110f590613b5a565b6006546001600160a01b03838116630100000090920416148015611ac1575080155b611b275760405162461bcd60e51b815260206004820152603160248201527f4c5020546f6b656e20526573657276652063616e206e6f742062652061626c65604482015270103a37903932b1b2b4bb329027232a399760791b60648201526084016110f5565b6007546001600160a01b038381169116148015611b42575080155b611ba45760405162461bcd60e51b815260206004820152602d60248201527f5465616d20526573657276652063616e206e6f742062652061626c6520746f2060448201526c3932b1b2b4bb329027232a399760991b60648201526084016110f5565b611506828261255b565b6001546001600160a01b03163314611bd85760405162461bcd60e51b81526004016110f590613b5a565b6001600160a01b038116611c3f5760405162461bcd60e51b815260206004820152602860248201527f41646d696e61626c653a206e65772061646d696e20697320746865207a65726f604482015267206164647265737360c01b60648201526084016110f5565b61110781613329565b6001546001600160a01b03163314611c725760405162461bcd60e51b81526004016110f590613b5a565b6006805461ffff1916610100179055565b60606004805461102290613a9f565b600060086000611cab60065460ff620100009091041690565b60ff168152602081019190915260400160002054919050565b6001546001600160a01b03163314611cee5760405162461bcd60e51b81526004016110f590613b5a565b6111076001600160a01b0382164761337b565b60065460009060ff161580611d2557503360009081526009602052604090205460ff165b611d415760405162461bcd60e51b81526004016110f590613b9c565b611d4b8383613412565b9392505050565b6001546001600160a01b03163314611d7c5760405162461bcd60e51b81526004016110f590613b5a565b611d8a82633b9aca00613cdb565b60ff90911660009081526008602052604090205550565b6001546001600160a01b03163314611dcb5760405162461bcd60e51b81526004016110f590613b5a565b6007805482919060ff60a01b1916600160a01b836002811115611df057611df061374f565b021790555050565b60008060005b83811015611e7657848482818110611e1857611e18613e0f565b9050604002016020016020810190611e3091906137b3565b9250848482818110611e4457611e44613e0f565b905060400201600001359150826001600160a01b03163b600003611e6e57611e6c8383611d01565b505b600101611dfe565b5050505050565b6001546001600160a01b03163314611ea75760405162461bcd60e51b81526004016110f590613b5a565b600654610100900460ff1615611f355760405162461bcd60e51b815260206004820152604760248201527f5472616e73666572732063616e206e6f74206265206c6f636b6564206167616960448201527f6e2c206f6e636520746865792068617665206265656e20756e6c6f636b6564206064820152663337b932bb32b960c91b608482015260a4016110f5565b6006805460ff1916911515919091179055565b6001546001600160a01b03163314611f725760405162461bcd60e51b81526004016110f590613b5a565b600654630100000090046001600160a01b03166116d48261341f565b611f966132ac565b6001600160a01b038116611fc0576000604051631e4fbdf760e01b81526004016110f59190613880565b611107816132d9565b6001546001600160a01b03163314611ff35760405162461bcd60e51b81526004016110f590613b5a565b6001600160a01b03919091166000908152600960205260409020805460ff1916911515919091179055565b6000190160011b90565b60008160031c8360601b0180546007841660051b1c63ffffffff1691505092915050565b8160081c8360601b018260ff16821515811b6001821b198354161782555050505050565b8160031c8360601b016007831660051b815480821c841863ffffffff16821b81188355505050505050565b8154600160601b900463ffffffff1668a20d6e21d0e52553088161212157805463ffffffff198116600163ffffffff928316019182169081178355855463ffffffff60601b1916600160601b82021786556000818152600284016020526040902080546001600160a01b0319166001600160a01b03871617905590925061212157600080fd5b5092915050565b600183038060021c8560601b0180546003831660061b92508463ffffffff168460201b178082851c186001600160401b0316841b821883555050505050505050565b80821461217f5783825260208201915061216a565b505092915050565b60008061219383610e54565b6001600160a01b0316141592915050565b606060006121b18361344e565b60010190506000816001600160401b038111156121d0576121d0613cf2565b6040519080825280601f01601f1916602001820160405280156121fa576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461220457509392505050565b6028828152601484905268a20d6e21d0e525530f600090815260488120915281905560008181526001600160a01b0380841691908516907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590602090a3505050565b60016122a26110bb565b60028111156122b3576122b361374f565b146122d05760405162461bcd60e51b81526004016110f590613c82565b60065462010000900460ff1660009081526008602052604081206001015468a20d6e21d0e52553089169021e19e0c9bab240000061230e9083613c4a565b8354909150600160201b900463ffffffff16600061232c8683613e25565b9050828163ffffffff1611156123a05760405162461bcd60e51b815260206004820152603360248201527f43616e2774206164642074686174206d616e79204e46547320746f206275726e604482015272020706f6f6c20666f7220746869732064726f7606c1b60648201526084016110f5565b8454600160601b900463ffffffff165b6123da60098701826123c181613e42565b935063ffffffff16856123d381613e42565b9650612070565b8163ffffffff168363ffffffff1611156123b05785546fffffffff00000000ffffffff000000001916600160601b63ffffffff9283160267ffffffff00000000191617600160201b93909116929092029190911790935550505050565b6001600160a01b038316600090815268a20d6e21d0e52553106020908152604080832068a20d6e21d0e525531390925291829020549151600160801b90920463ffffffff16838111938118939093029092189168a20d6e21d0e525530890845b848110156124d3578060031c8260601b0180546007831660051b1c63ffffffff1690508087830360051b60208701015250600181019050612497565b9490940380835260051b8201602001604052509392505050565b336028908152601484905268a20d6e21d0e525530f6000908152604881209181905281549091906000198114612544578084111561253e576040516313be252b60e01b815260040160405180910390fd5b83810382555b61254f868686612a8c565b50600195945050505050565b600068a20d6e21d0e52553086001600160a01b0384166000818152600b92909201602090815260408320805486158015865291955060ff600160581b9091049081166002918216159092180218600117927fb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d64203939190a2815460ff909116600160581b0260ff60581b199091161790555050565b600080826000036126035750600090508061261a565b600183858161261457612614613c34565b04915091505b9250929050565b6001600160a01b03821661264857604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553095468a20d6e21d0e5255308906001600160a01b03166126845760405163040739bf60e41b815260040160405180910390fd5b6001600160a01b0383166000908152600b82016020526040812082549091906126be908590600160a01b90046001600160601b0316613c21565b90506002548111156127295760405162461bcd60e51b815260206004820152602e60248201527f546f74616c20737570706c79206f6620636f696e732063616e206e6f7420657860448201526d31b2b2b21018903134b63634b7b760911b60648201526084016110f5565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915282546001600160601b03600160a01b80830482168801918216026001600160a01b0390921691909117845569021e19e0c9bab2400000810460408301525083546001600160601b038316600160a01b026001600160a01b039091161784556000806127df606085901c69021e19e0c9bab2400000860463fffffffe10171515151590565b90508684108117156128045760405163e5cfe95760e01b815260040160405180910390fd5b505069021e19e0c9bab2400000820461281c876111b6565b6129cc576001600160a01b03871660009081526008860160205260408082208654918501519092600a890192600160801b900463ffffffff1691828103908310026080870181905203612871575050506129cc565b60808501516040805160a0810183815260059390931b810160c09081018352918101929092528101815260a0860181905260608b901b6020909101526080850151885463ffffffff600160801b80830482169093018116830263ffffffff60801b19928316178b5560408801518a54911690920291161787556128f4878b61209b565b63ffffffff90811660608701528854600160201b90041684811180159091021785525b84515b61292783610b2b8361201e565b63ffffffff16156129435760010184811180159091021761291a565b60018101858111801590910217865261295d848383612070565b6129738382886060015185806001019650612128565b60a08601518051602080830151600885901b1782520190525084604001518103612917578451885463ffffffff909116600160201b0267ffffffff000000001990911617885560a08501516129c890896135f7565b5050505b5060008581526001600160a01b03871690600080516020613e66833981519152602082a35b505050505050565b60008083600003612a10575060019050600061261a565b83830283858281612a2357612a23613c34565b0414612a3657600080925092505061261a565b60019590945092505050565b600780546001600160a01b0319166001600160a01b038316179055612a6881600161255b565b6001600160a01b03166000908152600960205260409020805460ff19166001179055565b6001600160a01b038216612ab357604051633a954ecd60e21b815260040160405180910390fd5b6001600160a01b03838116600090815268a20d6e21d0e525531360205260408082208584168352912068a20d6e21d0e52553095468a20d6e21d0e52553089316612b105760405163040739bf60e41b815260040160405180910390fd5b612b8660405180610180016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff16815260200160008019168152602001600080191681525090565b825463ffffffff600160801b808304821660408501528454041660608301526001600160601b03600160a01b9091041680861115612bd757604051631e9acf1760e31b815260040160405180910390fd5b83546001600160601b0391879003828116600160a01b9081026001600160a01b03938416178755855481810485168a0194851690910292169190911784556040830151909190612c4a90612c3269021e19e0c9bab240000090565b8481612c4057612c40613c34565b0480821191030290565b8352612c55886111b6565b612ca457876001600160a01b0316896001600160a01b031603612c8057825160408401510360608401525b612c9e69021e19e0c9bab24000008204846060015180821191030290565b60208401525b5050612cae600190565b15612e99576000612ce08260400151612cd584600001518560200151808218908211021890565b808218908211021890565b905080612ced5750612e99565b8151819003825260208201805182900390526001600160a01b0380881690891603612d22576060820180519091019052612e99565b6040805163144027d3818301526001600160a01b038a8116606080840191909152908a16608083015260a082015260c0810183815260e0600585901b83018101909352602082015290810181526101408301526001600160a01b038089166000908152600887016020526040808220928a1682529020612da2858a61209b565b63ffffffff1660e08501526060840151928301925b6000612dd184876040018051600190039081815250612028565b63ffffffff169050612de4838383612070565b612df789600a01828860e0015185612128565b61014086015180518281526020019052600881901c60058a0160601b015460ff82161c60011615612e5057612e318960050182600061204c565b600081815260048a016020526040902080546001600160a01b03191690555b50838160010191508103612db75760608501819052855463ffffffff918216600160801b90810263ffffffff60801b199283161788556040870151895493160291161786555050505b805160208201518554600160801b80820463ffffffff90811684018590036080870181905263ffffffff60801b19909316921602178655604080519190920160a0820181815260059190911b820160c09081018452928201529081018152600a8501906101608301528454600160601b900463ffffffff1661012083015281511561307057610160820151600160608a901b81176020928301526001600160a01b038a16600090815260088801909252604091829020918401518451810360a08601819052875463ffffffff60801b1916600160801b63ffffffff909216919091021787556101208501519192915b600019909101906000612f9b8484612028565b63ffffffff169050612fb08682600080612128565b6101608701518051602080830151600885901b1782520190528415612fe957612fe98a6009018380600101945063ffffffff1683612070565b600881901c60058b0160601b015460ff82161c60011615613032576130138a60050182600061204c565b600081815260048b016020526040902080546001600160a01b03191690555b508560a001518203612f8857831561306b5763ffffffff81166101208701819052895463ffffffff60601b1916600160601b9091021789555b505050505b60208201511561324c57610160820151606088901b6020909101526001600160a01b038716600090815260088601602052604090206130af848961209b565b63ffffffff1660e0840152600069021e19e0c9bab24000008754600160a01b90046001600160601b0316816130e6576130e6613c34565b885463ffffffff600160201b909104811661010088015260608701516020880151810160c089018190528954908316600160801b0263ffffffff60801b199091161789558a549390920493509091600160401b9004165b600086610120015163ffffffff168263ffffffff161461317d576131708a6009018380600101945063ffffffff16612028565b63ffffffff1690506131c2565b506101008601515b61319286610b2b8361201e565b63ffffffff16156131ae57600101838111801590910217613185565b600181018481118015909102176101008801525b6131cd858483612070565b6131e386828960e0015186806001019750612128565b6101608701518051602080830151600885901b178252019052508560c00151820361313d57885461010087015163ffffffff908116600160201b0267ffffffff000000001991909316600160401b02166bffffffffffffffff0000000019909116171788555050505b61014082015115613266576132668261014001518661366c565b6101608201511561328057613280826101600151866135f7565b50846000528560601b60601c8760601b60601c600080516020613e6683398151915260206000a36119ee565b6000546001600160a01b03163314611a73573360405163118cdaa760e01b81526004016110f59190613880565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a35050565b8047101561339e573060405163cd78605960e01b81526004016110f59190613880565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146133eb576040519150601f19603f3d011682016040523d82523d6000602084013e6133f0565b606091505b5050905080610de357604051630a12f52160e11b815260040160405180910390fd5b60006110b2338484612a8c565b600680546301000000600160b81b03191663010000006001600160a01b03841602179055612a6881600161255b565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061348d5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106134b9576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106134d757662386f26fc10000830492506010015b6305f5e10083106134ef576305f5e100830492506008015b612710831061350357612710830492506004015b60648310613515576064830492506002015b600a8310610e215760010192915050565b600183019250825419915080831182171561352657808311156135505760ff86191691821b90911c905b5080156135ed5782820360081b7e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405821960010183166101e07a1412563212c14164235266736f7425221143267a4524367526767760fc7b2aaaaaaaba69a69a6db6db6db2cb2cb2ce739ce73def7bdeffffffff840260f81c161b60f71c1690811c63d76453e004601f169190911a1717858111878210176000031793505b5050509392505050565b6001810154604083015163263c69d6603f1982019081526020601f19830181905282516001600160a01b039094169360051b6044019282908490602319016000875af1600182511416611e7657600081fd5b80821461366557815160a01b60a81c8252602082019150613649565b5050919050565b60008160010160009054906101000a90046001600160a01b031690506020830151805160051b60840160808203915060208282601c85016000875af1600183511416611e7657600082fd5b60005b838110156136d25781810151838201526020016136ba565b50506000910152565b60208152600082518060208401526136fa8160408501602087016136b7565b601f01601f19169190910160400192915050565b6001600160a01b038116811461110757600080fd5b6000806040838503121561373657600080fd5b82356137418161370e565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b602081016003831061378757634e487b7160e01b600052602160045260246000fd5b91905290565b60006020828403121561379f57600080fd5b813563ffffffff81168114611d4b57600080fd5b6000602082840312156137c557600080fd5b8135611d4b8161370e565b6020808252825182820181905260009190848201906040850190845b81811015613808578351835292840192918401916001016137ec565b50909695505050505050565b60008060006060848603121561382957600080fd5b83356138348161370e565b925060208401356138448161370e565b929592945050506040919091013590565b8035801515811461100e57600080fd5b60006020828403121561387757600080fd5b611d4b82613855565b6001600160a01b0391909116815260200190565b600080604083850312156138a757600080fd5b50508035926020909101359150565b803560ff8116811461100e57600080fd5b6000602082840312156138d957600080fd5b611d4b826138b6565b600080604083850312156138f557600080fd5b82356001600160401b038116811461390c57600080fd5b915061391a602084016138b6565b90509250929050565b6000806020838503121561393657600080fd5b82356001600160401b038082111561394d57600080fd5b818501915085601f83011261396157600080fd5b81358181111561397057600080fd5b86602082850101111561398257600080fd5b60209290920196919550909350505050565b600080604083850312156139a757600080fd5b82356139b28161370e565b915061391a60208401613855565b600080604083850312156139d357600080fd5b8235915061391a602084016138b6565b6000602082840312156139f557600080fd5b813560038110611d4b57600080fd5b60008060408385031215613a1757600080fd5b8235613a228161370e565b91506020830135613a328161370e565b809150509250929050565b60008060208385031215613a5057600080fd5b82356001600160401b0380821115613a6757600080fd5b818501915085601f830112613a7b57600080fd5b813581811115613a8a57600080fd5b8660208260061b850101111561398257600080fd5b600181811c90821680613ab357607f821691505b6020821081036111f857634e487b7160e01b600052602260045260246000fd5b6000808454613ae181613a9f565b60018281168015613af95760018114613b0e57613b3d565b60ff1984168752821515830287019450613b3d565b8860005260208060002060005b85811015613b345781548a820152908401908201613b1b565b50505082870194505b505050508351613b518183602088016136b7565b01949350505050565b60208082526022908201527f41646d696e61626c653a2063616c6c6572206973206e6f74207468652061646d60408201526134b760f11b606082015260800190565b6020808252601f908201527f5472616e7366657273206172652063757272656e746c79206c6f636b65642e00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600060ff821660ff8103613bff57613bff613bd3565b60010192915050565b60ff8281168282160390811115610e2157610e21613bd3565b80820180821115610e2157610e21613bd3565b634e487b7160e01b600052601260045260246000fd5b600082613c6757634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052600160045260246000fd5b6020808252600f908201526e4e6f206163746976652044726f707360881b604082015260600190565b63ffffffff82811682821603908082111561212157612121613bd3565b81810381811115610e2157610e21613bd3565b8082028115828204841417610e2157610e21613bd3565b634e487b7160e01b600052604160045260246000fd5b601f821115610de3576000816000526020600020601f850160051c81016020861015613d315750805b601f850160051c820191505b818110156129f157828155600101613d3d565b6001600160401b03831115613d6757613d67613cf2565b613d7b83613d758354613a9f565b83613d08565b6000601f841160018114613daf5760008515613d975750838201355b600019600387901b1c1916600186901b178355611e76565b600083815260209020601f19861690835b82811015613de05786850135825560209485019460019092019101613dc0565b5086821015613dfd5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b634e487b7160e01b600052603260045260246000fd5b63ffffffff81811683821601908082111561212157612121613bd3565b600063ffffffff808316818103613e5b57613e5b613bd3565b600101939250505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212203b1c163230b7c31bd7b2494d4c96b2dba27abeff5081be3170a81f18d290610c64736f6c63430008180033608060405234801561001057600080fd5b50604051610d5f380380610d5f83398101604081905261002f9161005c565b683602298b8c10b0123180546001600160a01b0319166001600160a01b039290921691909117905561008c565b60006020828403121561006e57600080fd5b81516001600160a01b038116811461008557600080fd5b9392505050565b610cc48061009b6000396000f3fe6080604052600436106100ed5760003560e01c80636cef16e6116100855780636cef16e61461042357806370a08231146104385780638da5cb5b1461045857806395d89b411461047e57806397e5311c14610493578063a22cb465146104a8578063b88d4fde146104c8578063c87b56dd146104db578063e985e9c5146104fb576100ff565b806301ffc9a7146102db57806306fdde031461032d578063081812fc1461034f578063095ea7b31461038757806318160ddd1461039a57806323b872dd146103bd57806324359879146103d057806342842e0e146103f05780636352211e14610403576100ff565b366100ff5734156100fd57600080fd5b005b683602298b8c10b0123060003560e01c63263c69d68190036101a35781546001600160a01b0316331461014557604051631b1e598960e11b815260040160405180910390fd5b600435602401602081033560051b81015b8082146101965781358060601c816001168260a01b60a81c81158302828402600080516020610c6f833981519152600038a4505050816020019150610156565b5050600160005260206000f35b8063144027d3036102275781546001600160a01b031633146101d857604051631b1e598960e11b815260040160405180910390fd5b600435602435604435602401602081033560051b81015b8082146102185781358385600080516020610c6f833981519152600038a48160200191506101ef565b50505050600160005260206000f35b80630f4599e5036102c25760018201546001600160a01b03161561027d5760018201546001600160a01b03166004356001600160a01b03161461027d576040516362cf623d60e11b815260040160405180910390fd5b81546001600160a01b0316156102a657604051635fb2b52360e11b815260040160405180910390fd5b81546001600160a01b0319163317825560016000908152602090f35b604051631e085ca760e11b815260040160405180910390fd5b3480156102e757600080fd5b506103186102f6366004610a2e565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561033957600080fd5b5061034261051b565b6040516103249190610a5f565b34801561035b57600080fd5b5061036f61036a366004610aae565b610531565b6040516001600160a01b039091168152602001610324565b6100fd610395366004610ae3565b610549565b3480156103a657600080fd5b506103af6105cf565b604051908152602001610324565b6100fd6103cb366004610b0d565b6105e1565b3480156103dc57600080fd5b5061036f6103eb366004610aae565b61065e565b6100fd6103fe366004610b0d565b610670565b34801561040f57600080fd5b5061036f61041e366004610aae565b6106a2565b34801561042f57600080fd5b506103186106b4565b34801561044457600080fd5b506103af610453366004610b49565b61076f565b34801561046457600080fd5b50683602298b8c10b01232546001600160a01b031661036f565b34801561048a57600080fd5b5061034261078a565b34801561049f57600080fd5b5061036f61079b565b3480156104b457600080fd5b506100fd6104c3366004610b64565b6107d0565b6100fd6104d6366004610ba0565b610853565b3480156104e757600080fd5b506103426104f6366004610aae565b6108ae565b34801561050757600080fd5b50610318610516366004610c3b565b6108c8565b606061052c6306fdde0360006108f4565b905090565b600061054363081812fc83600061095a565b92915050565b600061055361079b565b90508260601b60601c925060405163d10b6e0c600052836020528260405233606052602060006064601c34865af1601f3d1116610593573d6000823e3d81fd5b806040525060006060528183600c5160601c7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a4505050565b600061052c63e2c7928160008061095a565b60006105eb61079b565b90508360601b60601c93508260601b60601c925060405163e5eb36c881528460208201528360408201528260608201523360808201526020816084601c840134865af1600182511416610641573d6000823e3d81fd5b50818385600080516020610c6f833981519152600038a450505050565b6000610543632435987983600061095a565b61067b8383836105e1565b813b1561069d5761069d838383604051806020016040528060008152506109a2565b505050565b6000610543636352211e83600061095a565b60008060006106c161079b565b9050638da5cb5b600052602060006004601c845afa600c51683602298b8c10b0123254601f3d119290921660609190911c029250683602298b8c10b01230906001600160a01b039081169084168114610764576002820180546001600160a01b0319166001600160a01b0386811691821790925560405190918316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35b600194505050505090565b600061054363f5b100ea836001600160a01b0316600061095a565b606061052c6395d89b4160006108f4565b683602298b8c10b01230546001600160a01b0316806107cd57604051632d9523d760e11b815260040160405180910390fd5b90565b60006107da61079b565b90508260601b60601c925060405163813500fc6000528360205282151560405233606052602060006064601c34865af16001600051141661081e573d6000823e3d81fd5b83337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206040a36040525050600060605250565b61085e8585856105e1565b833b156108a7576108a785858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506109a292505050565b5050505050565b60606108b9826106a2565b5061054363c87b56dd836108f4565b60006108eb63e985e9c5846001600160a01b0316846001600160a01b031661095a565b15159392505050565b6060600061090061079b565b9050604051915083600052826020526000806024601c845afa610926573d6000833e3d82fd5b60206000803e6020600051833e8151602060005101602084013e815160208301016000815260208101604052505092915050565b60008061096561079b565b9050604051856000528460205283604052602060006044601c855afa601f3d1116610993573d6000823e3d81fd5b60405250506000519392505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a084015280156109e9578060c08401826020870160045afa505b60208360a48301601c860160008a5af1610a0c573d15610a0c573d6000843e3d83fd5b508060e01b825114610a265763d1a57ed66000526004601cfd5b505050505050565b600060208284031215610a4057600080fd5b81356001600160e01b031981168114610a5857600080fd5b9392505050565b60006020808352835180602085015260005b81811015610a8d57858101830151858201604001528201610a71565b506000604082860101526040601f19601f8301168501019250505092915050565b600060208284031215610ac057600080fd5b5035919050565b80356001600160a01b0381168114610ade57600080fd5b919050565b60008060408385031215610af657600080fd5b610aff83610ac7565b946020939093013593505050565b600080600060608486031215610b2257600080fd5b610b2b84610ac7565b9250610b3960208501610ac7565b9150604084013590509250925092565b600060208284031215610b5b57600080fd5b610a5882610ac7565b60008060408385031215610b7757600080fd5b610b8083610ac7565b915060208301358015158114610b9557600080fd5b809150509250929050565b600080600080600060808688031215610bb857600080fd5b610bc186610ac7565b9450610bcf60208701610ac7565b935060408601359250606086013567ffffffffffffffff80821115610bf357600080fd5b818801915088601f830112610c0757600080fd5b813581811115610c1657600080fd5b896020828501011115610c2857600080fd5b9699959850939650602001949392505050565b60008060408385031215610c4e57600080fd5b610c5783610ac7565b9150610c6560208401610ac7565b9050925092905056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122075d9dd627cf493a8c3d709a1ff261f6f267246b831b12e78fe5a146a852196a164736f6c63430008180033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000007c7391247c0d16b90b3e340bcf85a3d5e7f1714500000000000000000000000058feb550bf08c4c04d239882bce23f56c567d3c900000000000000000000000058ebfb5811825cb2dbb2c3dac4e7e343e543f0b0000000000000000000000000f50720fb4675ef5e68ad95f31b27005a73192e3b00000000000000000000000000000000000000000000000000000000000000064c4f55444552000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064c4f554445520000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106102555760003560e01c806370a0823111610139578063a9059cbb116100b6578063e3163ee51161007a578063e3163ee5146109e9578063ea5cb2a414610a09578063f10e737314610a29578063f2fde38b14610a49578063f851a44014610a69578063fc46a07614610a8957610267565b8063a9059cbb14610934578063b6e6e3aa14610954578063ba486f3514610974578063c1a2c2171461098a578063dd62ed3e146109aa57610267565b80638da5cb5b116100fd5780638da5cb5b1461088357806395d89b41146108a157806398d5fdca146108b65780639b58d54c146108cb578063a79f5b15146108eb57610267565b806370a08231146107f9578063715018a61461081957806372b03ef31461082e57806375829def1461084e57806375be58461461086e57610267565b806330f33395116101d25780634508d6ff116101965780634508d6ff1461073857806348fc03361461074d57806349b01efd1461076d5780634ef41efc146107a05780634fc75ad9146107c657806355f804b3146107d957610267565b806330f3339514610690578063313ce567146106c457806334d7d378146106d857806336d0c1be146106f8578063449a52f81461071857610267565b806318148f1b1161021957806318148f1b146105cc57806318160ddd146105f957806323b872dd14610630578063274e430b146106505780632a6a935d1461067057610267565b806306fdde0314610503578063095ea7b31461052e5780630c3f6acf1461055e5780631245c65314610580578063134f81c5146105ac57610267565b3661026757341561026557600080fd5b005b68a20d6e21d0e525530860003560e01c63e5eb36c88190036102ce5760018201546001600160a01b031633146102b05760405163ce5a776b60e01b815260040160405180910390fd5b6102c4600435602435604435606435610aa9565b6102ce6001610df4565b8063813500fc0361033a5760018201546001600160a01b031633146103065760405163ce5a776b60e01b815260040160405180910390fd5b600435602890815260443560145268a20d6e21d0e525530b60009081526048812091526024351515905561033a6001610df4565b8063e985e9c503610364576000610355600435602435610dfe565b9050610362811515610df4565b505b80636352211e0361038b5761038b61037d600435610e27565b6001600160a01b0316610df4565b806324359879036103a4576103a461037d600435610e54565b8063d10b6e0c036104055760018201546001600160a01b031633146103dc5760405163ce5a776b60e01b815260040160405180910390fd5b60006103ef600435602435604435610eb0565b9050610403816001600160a01b0316610df4565b505b8063081812fc0361041e5761041e61037d600435610f7e565b8063f5b100ea03610462576001600160a01b0360043516600090815268a20d6e21d0e5255313602052604090205461046290600160801b900463ffffffff16610df4565b8063e2c792810361048e5768a20d6e21d0e52553085461048e90600160801b900463ffffffff16610df4565b8063c87b56dd036104d55760206040510160405260006104b56104b060043590565b610fca565b90506020810360408251016000818301526020825280601f01601f191682f35b8063b7a94eb8036104ea576104ea6001610df4565b604051631e085ca760e11b815260040160405180910390fd5b34801561050f57600080fd5b50610518611013565b60405161052591906136db565b60405180910390f35b34801561053a57600080fd5b5061054e610549366004613723565b6110a5565b6040519015158152602001610525565b34801561056a57600080fd5b506105736110bb565b6040516105259190613765565b34801561058c57600080fd5b5060065462010000900460ff165b60405160ff9091168152602001610525565b3480156105b857600080fd5b506102656105c736600461378d565b6110cb565b3480156105d857600080fd5b506105ec6105e73660046137b3565b61110a565b60405161052591906137d0565b34801561060557600080fd5b5068a20d6e21d0e525530854600160a01b90046001600160601b03165b604051908152602001610525565b34801561063c57600080fd5b5061054e61064b366004613814565b61115a565b34801561065c57600080fd5b5061054e61066b3660046137b3565b6111b6565b34801561067c57600080fd5b5061054e61068b366004613865565b6111fe565b34801561069c57600080fd5b506006546106b790630100000090046001600160a01b031681565b6040516105259190613880565b3480156106d057600080fd5b50601261059a565b3480156106e457600080fd5b506102656106f3366004613894565b611212565b34801561070457600080fd5b506007546106b7906001600160a01b031681565b34801561072457600080fd5b50610265610733366004613723565b6114d2565b34801561074457600080fd5b5061026561150a565b34801561075957600080fd5b506102656107683660046137b3565b611695565b34801561077957600080fd5b506106226107883660046138c7565b60ff1660009081526008602052604090206001015490565b3480156107ac57600080fd5b5068a20d6e21d0e5255309546001600160a01b03166106b7565b6102656107d43660046138e2565b61171a565b3480156107e557600080fd5b506102656107f4366004613923565b6119f7565b34801561080557600080fd5b506106226108143660046137b3565b611a2e565b34801561082557600080fd5b50610265611a61565b34801561083a57600080fd5b50610265610849366004613994565b611a75565b34801561085a57600080fd5b506102656108693660046137b3565b611bae565b34801561087a57600080fd5b50610265611c48565b34801561088f57600080fd5b506000546001600160a01b03166106b7565b3480156108ad57600080fd5b50610518611c83565b3480156108c257600080fd5b50610622611c92565b3480156108d757600080fd5b506102656108e63660046137b3565b611cc4565b3480156108f757600080fd5b5061091f6109063660046138c7565b6008602052600090815260409020805460019091015482565b60408051928352602083019190915201610525565b34801561094057600080fd5b5061054e61094f366004613723565b611d01565b34801561096057600080fd5b5061026561096f3660046139c0565b611d52565b34801561098057600080fd5b5061062260025481565b34801561099657600080fd5b506102656109a53660046139e3565b611da1565b3480156109b657600080fd5b506106226109c5366004613a04565b602890815260149190915268a20d6e21d0e525530f60009081526048812091525490565b3480156109f557600080fd5b50610265610a04366004613a3d565b611df8565b348015610a1557600080fd5b50610265610a24366004613865565b611e7d565b348015610a3557600080fd5b50610265610a443660046137b3565b611f48565b348015610a5557600080fd5b50610265610a643660046137b3565b611f8e565b348015610a7557600080fd5b506001546106b7906001600160a01b031681565b348015610a9557600080fd5b50610265610aa4366004613994565b611fc9565b6001600160a01b038316610ad057604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553095468a20d6e21d0e5255308906001600160a01b0316610b0c5760405163040739bf60e41b815260040160405180910390fd5b600a8101600282016000610b3083610b2b600160201b8910890261201e565b612028565b63ffffffff1681526020810191909152604001600020546001600160a01b03878116911614610b715760405162a1148160e81b815260040160405180910390fd5b856001600160a01b0316836001600160a01b031614610bd257610b948684610dfe565b610bd257826001600160a01b0316610bab85610f7e565b6001600160a01b031614610bd257604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038681166000908152600b8401602052604080822092881682529020815469021e19e0c9bab2400000906008860190600160a01b90046001600160601b031680831115610c3957604051631e9acf1760e31b815260040160405180910390fd5b84546001600160601b03918490038216600160a01b9081026001600160a01b039283161787558554818104841686019093160291161783556005860160601b600889901c015460ff89161c60011615610cba57610c9b8660050189600061204c565b6000888152600487016020526040902080546001600160a01b03191690555b6001600160a01b038a166000908152602082905260408120855463ffffffff60801b198116600160801b9182900463ffffffff9081166000190116918202178755909190610d09908390612028565b90506000610d21886000198d01600190811b01612028565b9050610d34838263ffffffff1684612070565b610d4f8860001963ffffffff851601600190811b0183612070565b5050835463ffffffff60801b198116600160801b9182900463ffffffff908116600181019091169092021785556001600160a01b038b166000908152602084905260409020909150610da290828b612070565b610db7868a610db1878e61209b565b84612128565b50816000528860601b60601c8a60601b60601c600080516020613e6683398151915260206000a3610de8565b505050565b50505050505050505050565b8060005260206000f35b6028818152601483905268a20d6e21d0e525530b60009081526048812091525415155b92915050565b6000610e3282612187565b610e4f5760405163677510db60e11b815260040160405180910390fd5b610e21825b600068a20d6e21d0e525530868a20d6e21d0e525530a82610e8968a20d6e21d0e5255312610b2b600160201b8810880261201e565b63ffffffff1681526020810191909152604001600020546001600160a01b03169392505050565b600068a20d6e21d0e525530868a20d6e21d0e525530a82610ee568a20d6e21d0e5255312610b2b600160201b8910890261201e565b63ffffffff1681526020810191909152604001600020546001600160a01b03908116925083168214610f3857610f1b8284610dfe565b610f38576040516367d9dca160e11b815260040160405180910390fd5b6000848152600482016020526040902080546001600160a01b0319166001600160a01b038716908117909155610f769060058301908690151561204c565b509392505050565b6000610f8982612187565b610fa65760405163677510db60e11b815260040160405180910390fd5b50600090815268a20d6e21d0e525530c60205260409020546001600160a01b031690565b606060058054610fd990613a9f565b15905061100e576005610feb836121a4565b604051602001610ffc929190613ad3565b60405160208183030381529060405290505b919050565b60606003805461102290613a9f565b80601f016020809104026020016040519081016040528092919081815260200182805461104e90613a9f565b801561109b5780601f106110705761010080835404028352916020019161109b565b820191906000526020600020905b81548152906001019060200180831161107e57829003601f168201915b5050505050905090565b60006110b2338484612236565b50600192915050565b600754600160a01b900460ff1690565b6001546001600160a01b031633146110fe5760405162461bcd60e51b81526004016110f590613b5a565b60405180910390fd5b61110781612298565b50565b6001600160a01b038116600090815268a20d6e21d0e5255313602052604081205460609168a20d6e21d0e525530891600160801b900463ffffffff16611151858383612437565b95945050505050565b60065460009060ff16158061118757506001600160a01b03841660009081526009602052604090205460ff165b6111a35760405162461bcd60e51b81526004016110f590613b9c565b6111ae8484846124ed565b949350505050565b6001600160a01b038116600090815268a20d6e21d0e52553136020526040902054600160581b90046002811615159060ff8116906001166111f857823b151591505b50919050565b600061120a338361255b565b506001919050565b6001546001600160a01b0316331461123c5760405162461bcd60e51b81526004016110f590613b5a565b60016112466110bb565b60028111156112575761125761374f565b0361129f5760405162461bcd60e51b8152602060048201526018602482015277412064726f7020697320616c72656164792061637469766560401b60448201526064016110f5565b6006805462010000900460ff169060026112b883613be9565b91906101000a81548160ff021916908360ff160217905550506000600860006001600660029054906101000a900460ff166112f39190613c08565b60ff1681526020810191909152604001600020600101546113149083613c21565b905060025481111561137b5760405162461bcd60e51b815260206004820152602a60248201527f546f74616c20737570706c792063616e6e6f742065786365656420312062696c6044820152696c696f6e20636f696e7360b01b60648201526084016110f5565b600061139169021e19e0c9bab240000084613c4a565b9050600081116114035760405162461bcd60e51b815260206004820152603760248201527f44726f7020737570706c7920746f6f206c6f772c206e656564206174206c656160448201527673742031204e465420776f727468206f6620636f696e7360481b60648201526084016110f5565b60065462010000900460ff1660009081526008602052604081208581556001810184905590806114348660056125ed565b915091508161144557611445613c6c565b60065461146290630100000090046001600160a01b031682612621565b6000806114708860036129f9565b915091508161148157611481613c6c565b61148c8160146125ed565b90945092508361149e5761149e613c6c565b6007546114b4906001600160a01b031684612621565b50506007805460ff60a01b1916600160a01b17905550505050505050565b6001546001600160a01b031633146114fc5760405162461bcd60e51b81526004016110f590613b5a565b6115068282612621565b5050565b6001546001600160a01b031633146115345760405162461bcd60e51b81526004016110f590613b5a565b600061153e6110bb565b600281111561154f5761154f61374f565b0361156c5760405162461bcd60e51b81526004016110f590613c82565b60026115766110bb565b60028111156115875761158761374f565b036115cd5760405162461bcd60e51b8152602060048201526016602482015275111c9bdc081a185cc8185b1c9958591e48195b99195960521b60448201526064016110f5565b68a20d6e21d0e5255308805460065462010000900460ff16600090815260086020526040812060010154600160201b90920463ffffffff16919069021e19e0c9bab240000061161c9083613c4a565b9050600061162a8483613cab565b905061163581612298565b8454600160a01b90046001600160601b031683111561167b57845460009061166d90600160a01b90046001600160601b031685613cc8565b90506116793382612621565b505b50506007805460ff60a01b1916600160a11b179055505050565b6001546001600160a01b031633146116bf5760405162461bcd60e51b81526004016110f590613b5a565b6007546001600160a01b03166116d482612a42565b60006116df82611a2e565b90506116ec828483612a8c565b6116f782600061255b565b506001600160a01b03166000908152600960205260409020805460ff1916905550565b60006117246110bb565b60028111156117355761173561374f565b036117825760405162461bcd60e51b815260206004820152601a60248201527f50726573616c65206861736e277420737461727465642079657400000000000060448201526064016110f5565b600261178c6110bb565b600281111561179d5761179d61374f565b036117de5760405162461bcd60e51b8152602060048201526011602482015270141c995cd85b19481a185cc8195b991959607a1b60448201526064016110f5565b60065460ff82811662010000909204161461183b5760405162461bcd60e51b815260206004820152601c60248201527f57726f6e672070726573616c652073746167652073656c65637465640000000060448201526064016110f5565b816001600160401b03166000036118895760405162461bcd60e51b815260206004820152601260248201527143616e2774206d696e74203020636f696e7360701b60448201526064016110f5565b60006118a66001600160401b038416670de0b6b3a7640000613cdb565b68a20d6e21d0e52553088054919250906000906118d4908490600160a01b90046001600160601b0316613c21565b9050600860006118ed60065460ff620100009091041690565b60ff1660ff1681526020019081526020016000206001015481111561194c5760405162461bcd60e51b8152602060048201526015602482015274139bdd08195b9bdd59da0818dbda5b9cc81b19599d605a1b60448201526064016110f5565b60008061198d876001600160401b03166008600061197360065460ff620100009091041690565b60ff168152602081019190915260400160002054906129f9565b915091508161199e5761199e613c6c565b348111156119e45760405162461bcd60e51b8152602060048201526013602482015272139bdd08195b9bdd59da08115512081cd95b9d606a1b60448201526064016110f5565b6119ee3386612621565b50505050505050565b6001546001600160a01b03163314611a215760405162461bcd60e51b81526004016110f590613b5a565b6005610de3828483613d50565b6001600160a01b0316600090815268a20d6e21d0e52553136020526040902054600160a01b90046001600160601b031690565b611a696132ac565b611a7360006132d9565b565b6001546001600160a01b03163314611a9f5760405162461bcd60e51b81526004016110f590613b5a565b6006546001600160a01b03838116630100000090920416148015611ac1575080155b611b275760405162461bcd60e51b815260206004820152603160248201527f4c5020546f6b656e20526573657276652063616e206e6f742062652061626c65604482015270103a37903932b1b2b4bb329027232a399760791b60648201526084016110f5565b6007546001600160a01b038381169116148015611b42575080155b611ba45760405162461bcd60e51b815260206004820152602d60248201527f5465616d20526573657276652063616e206e6f742062652061626c6520746f2060448201526c3932b1b2b4bb329027232a399760991b60648201526084016110f5565b611506828261255b565b6001546001600160a01b03163314611bd85760405162461bcd60e51b81526004016110f590613b5a565b6001600160a01b038116611c3f5760405162461bcd60e51b815260206004820152602860248201527f41646d696e61626c653a206e65772061646d696e20697320746865207a65726f604482015267206164647265737360c01b60648201526084016110f5565b61110781613329565b6001546001600160a01b03163314611c725760405162461bcd60e51b81526004016110f590613b5a565b6006805461ffff1916610100179055565b60606004805461102290613a9f565b600060086000611cab60065460ff620100009091041690565b60ff168152602081019190915260400160002054919050565b6001546001600160a01b03163314611cee5760405162461bcd60e51b81526004016110f590613b5a565b6111076001600160a01b0382164761337b565b60065460009060ff161580611d2557503360009081526009602052604090205460ff165b611d415760405162461bcd60e51b81526004016110f590613b9c565b611d4b8383613412565b9392505050565b6001546001600160a01b03163314611d7c5760405162461bcd60e51b81526004016110f590613b5a565b611d8a82633b9aca00613cdb565b60ff90911660009081526008602052604090205550565b6001546001600160a01b03163314611dcb5760405162461bcd60e51b81526004016110f590613b5a565b6007805482919060ff60a01b1916600160a01b836002811115611df057611df061374f565b021790555050565b60008060005b83811015611e7657848482818110611e1857611e18613e0f565b9050604002016020016020810190611e3091906137b3565b9250848482818110611e4457611e44613e0f565b905060400201600001359150826001600160a01b03163b600003611e6e57611e6c8383611d01565b505b600101611dfe565b5050505050565b6001546001600160a01b03163314611ea75760405162461bcd60e51b81526004016110f590613b5a565b600654610100900460ff1615611f355760405162461bcd60e51b815260206004820152604760248201527f5472616e73666572732063616e206e6f74206265206c6f636b6564206167616960448201527f6e2c206f6e636520746865792068617665206265656e20756e6c6f636b6564206064820152663337b932bb32b960c91b608482015260a4016110f5565b6006805460ff1916911515919091179055565b6001546001600160a01b03163314611f725760405162461bcd60e51b81526004016110f590613b5a565b600654630100000090046001600160a01b03166116d48261341f565b611f966132ac565b6001600160a01b038116611fc0576000604051631e4fbdf760e01b81526004016110f59190613880565b611107816132d9565b6001546001600160a01b03163314611ff35760405162461bcd60e51b81526004016110f590613b5a565b6001600160a01b03919091166000908152600960205260409020805460ff1916911515919091179055565b6000190160011b90565b60008160031c8360601b0180546007841660051b1c63ffffffff1691505092915050565b8160081c8360601b018260ff16821515811b6001821b198354161782555050505050565b8160031c8360601b016007831660051b815480821c841863ffffffff16821b81188355505050505050565b8154600160601b900463ffffffff1668a20d6e21d0e52553088161212157805463ffffffff198116600163ffffffff928316019182169081178355855463ffffffff60601b1916600160601b82021786556000818152600284016020526040902080546001600160a01b0319166001600160a01b03871617905590925061212157600080fd5b5092915050565b600183038060021c8560601b0180546003831660061b92508463ffffffff168460201b178082851c186001600160401b0316841b821883555050505050505050565b80821461217f5783825260208201915061216a565b505092915050565b60008061219383610e54565b6001600160a01b0316141592915050565b606060006121b18361344e565b60010190506000816001600160401b038111156121d0576121d0613cf2565b6040519080825280601f01601f1916602001820160405280156121fa576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461220457509392505050565b6028828152601484905268a20d6e21d0e525530f600090815260488120915281905560008181526001600160a01b0380841691908516907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590602090a3505050565b60016122a26110bb565b60028111156122b3576122b361374f565b146122d05760405162461bcd60e51b81526004016110f590613c82565b60065462010000900460ff1660009081526008602052604081206001015468a20d6e21d0e52553089169021e19e0c9bab240000061230e9083613c4a565b8354909150600160201b900463ffffffff16600061232c8683613e25565b9050828163ffffffff1611156123a05760405162461bcd60e51b815260206004820152603360248201527f43616e2774206164642074686174206d616e79204e46547320746f206275726e604482015272020706f6f6c20666f7220746869732064726f7606c1b60648201526084016110f5565b8454600160601b900463ffffffff165b6123da60098701826123c181613e42565b935063ffffffff16856123d381613e42565b9650612070565b8163ffffffff168363ffffffff1611156123b05785546fffffffff00000000ffffffff000000001916600160601b63ffffffff9283160267ffffffff00000000191617600160201b93909116929092029190911790935550505050565b6001600160a01b038316600090815268a20d6e21d0e52553106020908152604080832068a20d6e21d0e525531390925291829020549151600160801b90920463ffffffff16838111938118939093029092189168a20d6e21d0e525530890845b848110156124d3578060031c8260601b0180546007831660051b1c63ffffffff1690508087830360051b60208701015250600181019050612497565b9490940380835260051b8201602001604052509392505050565b336028908152601484905268a20d6e21d0e525530f6000908152604881209181905281549091906000198114612544578084111561253e576040516313be252b60e01b815260040160405180910390fd5b83810382555b61254f868686612a8c565b50600195945050505050565b600068a20d6e21d0e52553086001600160a01b0384166000818152600b92909201602090815260408320805486158015865291955060ff600160581b9091049081166002918216159092180218600117927fb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d64203939190a2815460ff909116600160581b0260ff60581b199091161790555050565b600080826000036126035750600090508061261a565b600183858161261457612614613c34565b04915091505b9250929050565b6001600160a01b03821661264857604051633a954ecd60e21b815260040160405180910390fd5b68a20d6e21d0e52553095468a20d6e21d0e5255308906001600160a01b03166126845760405163040739bf60e41b815260040160405180910390fd5b6001600160a01b0383166000908152600b82016020526040812082549091906126be908590600160a01b90046001600160601b0316613c21565b90506002548111156127295760405162461bcd60e51b815260206004820152602e60248201527f546f74616c20737570706c79206f6620636f696e732063616e206e6f7420657860448201526d31b2b2b21018903134b63634b7b760911b60648201526084016110f5565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915282546001600160601b03600160a01b80830482168801918216026001600160a01b0390921691909117845569021e19e0c9bab2400000810460408301525083546001600160601b038316600160a01b026001600160a01b039091161784556000806127df606085901c69021e19e0c9bab2400000860463fffffffe10171515151590565b90508684108117156128045760405163e5cfe95760e01b815260040160405180910390fd5b505069021e19e0c9bab2400000820461281c876111b6565b6129cc576001600160a01b03871660009081526008860160205260408082208654918501519092600a890192600160801b900463ffffffff1691828103908310026080870181905203612871575050506129cc565b60808501516040805160a0810183815260059390931b810160c09081018352918101929092528101815260a0860181905260608b901b6020909101526080850151885463ffffffff600160801b80830482169093018116830263ffffffff60801b19928316178b5560408801518a54911690920291161787556128f4878b61209b565b63ffffffff90811660608701528854600160201b90041684811180159091021785525b84515b61292783610b2b8361201e565b63ffffffff16156129435760010184811180159091021761291a565b60018101858111801590910217865261295d848383612070565b6129738382886060015185806001019650612128565b60a08601518051602080830151600885901b1782520190525084604001518103612917578451885463ffffffff909116600160201b0267ffffffff000000001990911617885560a08501516129c890896135f7565b5050505b5060008581526001600160a01b03871690600080516020613e66833981519152602082a35b505050505050565b60008083600003612a10575060019050600061261a565b83830283858281612a2357612a23613c34565b0414612a3657600080925092505061261a565b60019590945092505050565b600780546001600160a01b0319166001600160a01b038316179055612a6881600161255b565b6001600160a01b03166000908152600960205260409020805460ff19166001179055565b6001600160a01b038216612ab357604051633a954ecd60e21b815260040160405180910390fd5b6001600160a01b03838116600090815268a20d6e21d0e525531360205260408082208584168352912068a20d6e21d0e52553095468a20d6e21d0e52553089316612b105760405163040739bf60e41b815260040160405180910390fd5b612b8660405180610180016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600063ffffffff16815260200160008152602001600063ffffffff16815260200160008019168152602001600080191681525090565b825463ffffffff600160801b808304821660408501528454041660608301526001600160601b03600160a01b9091041680861115612bd757604051631e9acf1760e31b815260040160405180910390fd5b83546001600160601b0391879003828116600160a01b9081026001600160a01b03938416178755855481810485168a0194851690910292169190911784556040830151909190612c4a90612c3269021e19e0c9bab240000090565b8481612c4057612c40613c34565b0480821191030290565b8352612c55886111b6565b612ca457876001600160a01b0316896001600160a01b031603612c8057825160408401510360608401525b612c9e69021e19e0c9bab24000008204846060015180821191030290565b60208401525b5050612cae600190565b15612e99576000612ce08260400151612cd584600001518560200151808218908211021890565b808218908211021890565b905080612ced5750612e99565b8151819003825260208201805182900390526001600160a01b0380881690891603612d22576060820180519091019052612e99565b6040805163144027d3818301526001600160a01b038a8116606080840191909152908a16608083015260a082015260c0810183815260e0600585901b83018101909352602082015290810181526101408301526001600160a01b038089166000908152600887016020526040808220928a1682529020612da2858a61209b565b63ffffffff1660e08501526060840151928301925b6000612dd184876040018051600190039081815250612028565b63ffffffff169050612de4838383612070565b612df789600a01828860e0015185612128565b61014086015180518281526020019052600881901c60058a0160601b015460ff82161c60011615612e5057612e318960050182600061204c565b600081815260048a016020526040902080546001600160a01b03191690555b50838160010191508103612db75760608501819052855463ffffffff918216600160801b90810263ffffffff60801b199283161788556040870151895493160291161786555050505b805160208201518554600160801b80820463ffffffff90811684018590036080870181905263ffffffff60801b19909316921602178655604080519190920160a0820181815260059190911b820160c09081018452928201529081018152600a8501906101608301528454600160601b900463ffffffff1661012083015281511561307057610160820151600160608a901b81176020928301526001600160a01b038a16600090815260088801909252604091829020918401518451810360a08601819052875463ffffffff60801b1916600160801b63ffffffff909216919091021787556101208501519192915b600019909101906000612f9b8484612028565b63ffffffff169050612fb08682600080612128565b6101608701518051602080830151600885901b1782520190528415612fe957612fe98a6009018380600101945063ffffffff1683612070565b600881901c60058b0160601b015460ff82161c60011615613032576130138a60050182600061204c565b600081815260048b016020526040902080546001600160a01b03191690555b508560a001518203612f8857831561306b5763ffffffff81166101208701819052895463ffffffff60601b1916600160601b9091021789555b505050505b60208201511561324c57610160820151606088901b6020909101526001600160a01b038716600090815260088601602052604090206130af848961209b565b63ffffffff1660e0840152600069021e19e0c9bab24000008754600160a01b90046001600160601b0316816130e6576130e6613c34565b885463ffffffff600160201b909104811661010088015260608701516020880151810160c089018190528954908316600160801b0263ffffffff60801b199091161789558a549390920493509091600160401b9004165b600086610120015163ffffffff168263ffffffff161461317d576131708a6009018380600101945063ffffffff16612028565b63ffffffff1690506131c2565b506101008601515b61319286610b2b8361201e565b63ffffffff16156131ae57600101838111801590910217613185565b600181018481118015909102176101008801525b6131cd858483612070565b6131e386828960e0015186806001019750612128565b6101608701518051602080830151600885901b178252019052508560c00151820361313d57885461010087015163ffffffff908116600160201b0267ffffffff000000001991909316600160401b02166bffffffffffffffff0000000019909116171788555050505b61014082015115613266576132668261014001518661366c565b6101608201511561328057613280826101600151866135f7565b50846000528560601b60601c8760601b60601c600080516020613e6683398151915260206000a36119ee565b6000546001600160a01b03163314611a73573360405163118cdaa760e01b81526004016110f59190613880565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a35050565b8047101561339e573060405163cd78605960e01b81526004016110f59190613880565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146133eb576040519150601f19603f3d011682016040523d82523d6000602084013e6133f0565b606091505b5050905080610de357604051630a12f52160e11b815260040160405180910390fd5b60006110b2338484612a8c565b600680546301000000600160b81b03191663010000006001600160a01b03841602179055612a6881600161255b565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061348d5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106134b9576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106134d757662386f26fc10000830492506010015b6305f5e10083106134ef576305f5e100830492506008015b612710831061350357612710830492506004015b60648310613515576064830492506002015b600a8310610e215760010192915050565b600183019250825419915080831182171561352657808311156135505760ff86191691821b90911c905b5080156135ed5782820360081b7e1f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405821960010183166101e07a1412563212c14164235266736f7425221143267a4524367526767760fc7b2aaaaaaaba69a69a6db6db6db2cb2cb2ce739ce73def7bdeffffffff840260f81c161b60f71c1690811c63d76453e004601f169190911a1717858111878210176000031793505b5050509392505050565b6001810154604083015163263c69d6603f1982019081526020601f19830181905282516001600160a01b039094169360051b6044019282908490602319016000875af1600182511416611e7657600081fd5b80821461366557815160a01b60a81c8252602082019150613649565b5050919050565b60008160010160009054906101000a90046001600160a01b031690506020830151805160051b60840160808203915060208282601c85016000875af1600183511416611e7657600082fd5b60005b838110156136d25781810151838201526020016136ba565b50506000910152565b60208152600082518060208401526136fa8160408501602087016136b7565b601f01601f19169190910160400192915050565b6001600160a01b038116811461110757600080fd5b6000806040838503121561373657600080fd5b82356137418161370e565b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b602081016003831061378757634e487b7160e01b600052602160045260246000fd5b91905290565b60006020828403121561379f57600080fd5b813563ffffffff81168114611d4b57600080fd5b6000602082840312156137c557600080fd5b8135611d4b8161370e565b6020808252825182820181905260009190848201906040850190845b81811015613808578351835292840192918401916001016137ec565b50909695505050505050565b60008060006060848603121561382957600080fd5b83356138348161370e565b925060208401356138448161370e565b929592945050506040919091013590565b8035801515811461100e57600080fd5b60006020828403121561387757600080fd5b611d4b82613855565b6001600160a01b0391909116815260200190565b600080604083850312156138a757600080fd5b50508035926020909101359150565b803560ff8116811461100e57600080fd5b6000602082840312156138d957600080fd5b611d4b826138b6565b600080604083850312156138f557600080fd5b82356001600160401b038116811461390c57600080fd5b915061391a602084016138b6565b90509250929050565b6000806020838503121561393657600080fd5b82356001600160401b038082111561394d57600080fd5b818501915085601f83011261396157600080fd5b81358181111561397057600080fd5b86602082850101111561398257600080fd5b60209290920196919550909350505050565b600080604083850312156139a757600080fd5b82356139b28161370e565b915061391a60208401613855565b600080604083850312156139d357600080fd5b8235915061391a602084016138b6565b6000602082840312156139f557600080fd5b813560038110611d4b57600080fd5b60008060408385031215613a1757600080fd5b8235613a228161370e565b91506020830135613a328161370e565b809150509250929050565b60008060208385031215613a5057600080fd5b82356001600160401b0380821115613a6757600080fd5b818501915085601f830112613a7b57600080fd5b813581811115613a8a57600080fd5b8660208260061b850101111561398257600080fd5b600181811c90821680613ab357607f821691505b6020821081036111f857634e487b7160e01b600052602260045260246000fd5b6000808454613ae181613a9f565b60018281168015613af95760018114613b0e57613b3d565b60ff1984168752821515830287019450613b3d565b8860005260208060002060005b85811015613b345781548a820152908401908201613b1b565b50505082870194505b505050508351613b518183602088016136b7565b01949350505050565b60208082526022908201527f41646d696e61626c653a2063616c6c6572206973206e6f74207468652061646d60408201526134b760f11b606082015260800190565b6020808252601f908201527f5472616e7366657273206172652063757272656e746c79206c6f636b65642e00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600060ff821660ff8103613bff57613bff613bd3565b60010192915050565b60ff8281168282160390811115610e2157610e21613bd3565b80820180821115610e2157610e21613bd3565b634e487b7160e01b600052601260045260246000fd5b600082613c6757634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052600160045260246000fd5b6020808252600f908201526e4e6f206163746976652044726f707360881b604082015260600190565b63ffffffff82811682821603908082111561212157612121613bd3565b81810381811115610e2157610e21613bd3565b8082028115828204841417610e2157610e21613bd3565b634e487b7160e01b600052604160045260246000fd5b601f821115610de3576000816000526020600020601f850160051c81016020861015613d315750805b601f850160051c820191505b818110156129f157828155600101613d3d565b6001600160401b03831115613d6757613d67613cf2565b613d7b83613d758354613a9f565b83613d08565b6000601f841160018114613daf5760008515613d975750838201355b600019600387901b1c1916600186901b178355611e76565b600083815260209020601f19861690835b82811015613de05786850135825560209485019460019092019101613dc0565b5086821015613dfd5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b634e487b7160e01b600052603260045260246000fd5b63ffffffff81811683821601908082111561212157612121613bd3565b600063ffffffff808316818103613e5b57613e5b613bd3565b600101939250505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212203b1c163230b7c31bd7b2494d4c96b2dba27abeff5081be3170a81f18d290610c64736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000007c7391247c0d16b90b3e340bcf85a3d5e7f1714500000000000000000000000058feb550bf08c4c04d239882bce23f56c567d3c900000000000000000000000058ebfb5811825cb2dbb2c3dac4e7e343e543f0b0000000000000000000000000f50720fb4675ef5e68ad95f31b27005a73192e3b00000000000000000000000000000000000000000000000000000000000000064c4f55444552000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064c4f554445520000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : config_ (tuple):
Arg [1] : name (string): LOUDER
Arg [2] : symbol (string): LOUDER
Arg [3] : admin (address): 0x7c7391247C0d16b90B3e340bcf85a3D5E7f17145
Arg [4] : owner (address): 0x58fEB550bf08C4C04D239882BcE23f56C567d3C9
Arg [5] : lpTokenReserve (address): 0x58EbFb5811825Cb2dBB2c3DAc4e7E343e543F0B0
Arg [6] : teamReserve (address): 0xf50720fb4675Ef5E68aD95F31b27005a73192E3B


-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 0000000000000000000000007c7391247c0d16b90b3e340bcf85a3d5e7f17145
Arg [4] : 00000000000000000000000058feb550bf08c4c04d239882bce23f56c567d3c9
Arg [5] : 00000000000000000000000058ebfb5811825cb2dbb2c3dac4e7e343e543f0b0
Arg [6] : 000000000000000000000000f50720fb4675ef5e68ad95f31b27005a73192e3b
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [8] : 4c4f554445520000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [10] : 4c4f554445520000000000000000000000000000000000000000000000000000


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.