{"file_path":"project/contracts/Freezer.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport {OperatorLockable} from \"./OperatorLockable.sol\";\nimport {DexTreasury} from \"./DexTreasury.sol\";\nimport {IFreezeHook} from \"./interfaces/IFreezeHook.sol\";\nimport {ITokenSource} from \"./interfaces/ITokenSource.sol\";\n\ncontract Freezer is OperatorLockable, DexTreasury, ITokenSource {\n    using SafeERC20 for IERC20;\n    using SafeERC20 for IERC20Metadata;\n\n    struct Frost {\n        uint256 amount;\n        address owner;\n        uint8 tier;\n        uint256 frozenAt;\n        uint256 ownedAt;\n    }\n\n    struct Account {\n        uint256 accruedNum;\n        uint256 lastAccrualAt;\n        uint256 lastClaimAt;\n        uint256 firstFreezeAt;\n        uint256 frostCount;\n    }\n\n    struct AccountView {\n        uint256 accruedNum;\n        uint256 lastAccrualAt;\n        uint256 lastClaimAt;\n        uint256 firstFreezeAt;\n        uint256 frostCount;\n        uint256 frozenTotal;\n    }\n\n    struct TierInfo {\n        uint8 tier;\n        uint256 term;\n        uint256 weight;\n    }\n\n    struct FrostView {\n        uint256 id;\n        address owner;\n        uint8 tier;\n        uint256 amount;\n        uint256 frozenAt;\n        uint256 ownedAt;\n        uint256 unfreezeAt;\n        uint256 lockedTill;\n        address lockedFor;\n    }\n\n    uint256 public constant MAX_FROSTS = 100;\n    uint256 public constant CLAIM_COOLDOWN = 1 days;\n\n    uint256 public constant DENOM = 3650 days;\n    uint256 public constant YEAR = 365 days;\n    uint8 public constant TIERS = 3;\n\n    IERC20Metadata private immutable _token;\n\n    uint256 public immutable candidacyFee;\n\n    uint256 public nextFrostId = 1;\n    uint256 public totalFrozen;\n    uint256 public activeFrosts;\n    IFreezeHook private immutable _freezeHook;\n    address private immutable _freezerMarket;\n\n    mapping(uint8 tier => uint256) public totalFrozenIn;\n    mapping(uint8 tier => uint256) public activeFrostsIn;\n    mapping(address owner => Account) private _accounts;\n    mapping(address owner => mapping(uint8 tier => uint256)) private _tierTotal;\n    mapping(uint256 frostId => Frost) private _frosts;\n\n    event CandidacyFeeChanged(uint256 oldFee, uint256 newFee);\n    event FrostCreated(uint256 indexed id, address indexed owner);\n    event FrostChanged(uint256 indexed id);\n    event FrostRemoved(uint256 indexed id, address indexed owner);\n    event Frozen(uint256 indexed id, address indexed owner, uint8 tier, uint256 amount);\n    event Unfrozen(uint256 indexed id, address indexed owner, uint8 tier, uint256 amount, uint256 left);\n    event Merged(uint256 indexed id, uint256 indexed intoId, address indexed owner, uint8 tier);\n\n    event Upgraded(uint256 indexed id, address indexed owner, uint8 fromTier, uint8 toTier, uint256 amount, uint256 frozenAt);\n    event Transferred(\n        uint256 indexed id,\n        uint256 indexed remainderId,\n        address indexed from,\n        address to,\n        uint8 tier,\n        uint256 amount,\n        uint256 frozenAt,\n        uint256 lockedTill\n    );\n    event Returned(uint256 indexed id, address indexed from, address indexed to, uint8 tier, uint256 amount);\n    event Claimed(address indexed owner, uint256 claimAmount);\n\n    error InvalidTier(uint8 tier);\n    error ZeroAmount();\n    error ZeroAddress();\n    error InvalidReceiver(address to);\n    error NonexistentFrost(uint256 id);\n    error IncorrectOwner(uint256 id, address owner, address expected);\n    error FrostLocked(uint256 id, uint256 lockedTill);\n    error FrostNotLocked(uint256 id);\n    error StillFrozen(uint256 id, uint256 unfreezeAt);\n    error InsufficientFrost(uint256 id, uint256 balance, uint256 needed);\n    error TooManyFrosts(address owner, uint256 max);\n    error TierMismatch(uint256 id, uint8 tier, uint8 expected);\n    error NotAnUpgrade(uint256 id, uint8 tier, uint8 newTier);\n    error InvalidListLength(uint256 length, uint256 minimum);\n    error ClaimTooEarly(address owner, uint256 availableAt);\n    error NothingToClaim(address owner);\n    error RewardsDepleted();\n    error AddressWithoutCode(address address_);\n    error TreasuryBelowFrozen(uint256 balance, uint256 frozen);\n    error OnlyMarketAccess();\n\n    constructor(\n        IERC20Metadata token_,\n        uint256 dexSellCap_,\n        address freezeHook_,\n        address freezerMarket_,\n        address dexModule_,\n        Config memory dex\n    ) DexTreasury(dexModule_, address(token_), dexSellCap_, dex) {\n        require(address(token_) != address(0) && freezerMarket_ != address(0), ZeroAddress());\n        require(freezeHook_ == address(0) || freezeHook_.code.length != 0, AddressWithoutCode(freezeHook_));\n        require(freezerMarket_.code.length != 0, AddressWithoutCode(freezerMarket_));\n\n        _token = token_;\n        _freezeHook = IFreezeHook(freezeHook_);\n        _freezerMarket = freezerMarket_;\n        candidacyFee = 100 * 10 ** token_.decimals();\n\n        emit CandidacyFeeChanged(0, candidacyFee);\n    }\n\n    function freeze(uint8 tier, uint256 amount, address referrer) external returns (uint256 id) {\n        require(tier < TIERS, InvalidTier(tier));\n        require(amount != 0, ZeroAmount());\n\n        address sender = _msgSender();\n        _requireSlot(sender);\n\n        _token.safeTransferFrom(sender, address(this), amount);\n\n        id = _freeze(sender, tier, amount);\n        _notifyFreezeHook(sender, referrer, amount);\n    }\n\n    function unfreeze(uint256[] calldata ids) external returns (uint256 released) {\n        require(ids.length != 0, InvalidListLength(ids.length, 1));\n\n        released = 0;\n\n        address sender = _msgSender();\n        _settle(sender);\n\n        for (uint256 i = 0; i < ids.length; ++i) {\n            uint256 id = ids[i];\n            Frost memory frost = _requireFrostOf(sender, id);\n\n            _requireFree(id);\n\n            uint256 unfreezeAt = _unfreezeAt(frost);\n            require(unfreezeAt <= block.timestamp, StillFrozen(id, unfreezeAt));\n\n            released += frost.amount;\n\n            _tierTotal[sender][frost.tier] -= frost.amount;\n            totalFrozenIn[frost.tier] -= frost.amount;\n            _destroy(sender, id);\n\n            emit Unfrozen(id, sender, frost.tier, frost.amount, 0);\n        }\n\n        totalFrozen -= released;\n        _onStakeChanged(sender);\n\n        _token.safeTransfer(sender, released);\n    }\n\n    function unfreezeOne(uint256 id, uint256 amount) external {\n        require(amount != 0, ZeroAmount());\n\n        address sender = _msgSender();\n        Frost memory frost = _requireFrostOf(sender, id);\n\n        _requireFree(id);\n        require(amount <= frost.amount, InsufficientFrost(id, frost.amount, amount));\n\n        uint256 unfreezeAt = _unfreezeAt(frost);\n        require(unfreezeAt <= block.timestamp, StillFrozen(id, unfreezeAt));\n\n        _settle(sender);\n\n        uint256 left = frost.amount - amount;\n        if (left == 0) {\n            _destroy(sender, id);\n        } else {\n            _frosts[id].amount = left;\n            emit FrostChanged(id);\n        }\n\n        _tierTotal[sender][frost.tier] -= amount;\n        totalFrozen -= amount;\n        totalFrozenIn[frost.tier] -= amount;\n        _onStakeChanged(sender);\n\n        _token.safeTransfer(sender, amount);\n\n        emit Unfrozen(id, sender, frost.tier, amount, left);\n    }\n\n    function merge(uint256[] calldata ids) external returns (uint256 newId) {\n        require(ids.length >= 2, InvalidListLength(ids.length, 2));\n\n        address sender = _msgSender();\n        _settle(sender);\n\n        uint8 tier = _requireFrostOf(sender, ids[0]).tier;\n        uint256 mergedAmount;\n        uint256 mergedFrozenAt;\n\n        for (uint256 i = 0; i < ids.length; ++i) {\n            uint256 id = ids[i];\n            Frost memory frost = _requireFrostOf(sender, id);\n\n            _requireFree(id);\n            require(frost.tier == tier, TierMismatch(id, frost.tier, tier));\n\n            mergedAmount += frost.amount;\n            if (frost.frozenAt > mergedFrozenAt) {\n                mergedFrozenAt = frost.frozenAt;\n            }\n\n            _destroy(sender, id);\n        }\n\n        newId = _create(sender, tier, mergedAmount, mergedFrozenAt, block.timestamp);\n\n        for (uint256 i = 0; i < ids.length; ++i) {\n            emit Merged(ids[i], newId, sender, tier);\n        }\n    }\n\n    function upgrade(uint256 id, uint8 newTier) external {\n        require(newTier < TIERS, InvalidTier(newTier));\n\n        address sender = _msgSender();\n        Frost memory frost = _requireFrostOf(sender, id);\n        require(newTier > frost.tier, NotAnUpgrade(id, frost.tier, newTier));\n\n        _requireFree(id);\n\n        _settle(sender);\n\n        _tierTotal[sender][frost.tier] -= frost.amount;\n        _tierTotal[sender][newTier] += frost.amount;\n        totalFrozenIn[frost.tier] -= frost.amount;\n        totalFrozenIn[newTier] += frost.amount;\n        activeFrostsIn[frost.tier] -= 1;\n        activeFrostsIn[newTier] += 1;\n\n        _frosts[id].tier = newTier;\n        _frosts[id].frozenAt = block.timestamp;\n        _frosts[id].ownedAt = block.timestamp;\n\n        _onStakeChanged(sender);\n\n        emit Upgraded(id, sender, frost.tier, newTier, frost.amount, block.timestamp);\n        emit FrostChanged(id);\n    }\n\n    function claim() external {\n        address sender = _msgSender();\n\n        uint256 availableAt = _accounts[sender].lastClaimAt + CLAIM_COOLDOWN;\n        require(block.timestamp >= availableAt, ClaimTooEarly(sender, availableAt));\n        require(_pending(sender) != 0, NothingToClaim(sender));\n\n        _settle(sender);\n\n        Account storage account = _accounts[sender];\n        uint256 accrued = account.accruedNum / DENOM;\n        uint256 available = availableRewards();\n        uint256 claimAmount = accrued < available ? accrued : available;\n        require(claimAmount != 0, RewardsDepleted());\n\n        account.accruedNum -= claimAmount * DENOM;\n        account.lastClaimAt = block.timestamp;\n\n        _token.safeTransfer(sender, claimAmount);\n\n        emit Claimed(sender, claimAmount);\n    }\n\n    function lock(uint256 id, uint256 lockTill) public override {\n        super.lock(id, lockTill);\n\n        emit FrostChanged(id);\n    }\n\n    function unlock(uint256 id) public override {\n        bool wasLocked = isLocked(id);\n\n        super.unlock(id);\n\n        if (wasLocked) {\n            emit FrostChanged(id);\n        }\n    }\n\n    function transferPart(\n        address from,\n        uint256 id,\n        uint256 amount,\n        address to\n    ) external returns (uint256 remainderId) {\n        require(_msgSender() == _freezerMarket, OnlyMarketAccess());\n        require(to != address(0) && to != address(this) && to != from, InvalidReceiver(to));\n        require(amount != 0, ZeroAmount());\n\n        Frost memory frost = _requireFrostOf(from, id);\n        require(amount <= frost.amount, InsufficientFrost(id, frost.amount, amount));\n\n        address lockedFor = lockedForOf(id);\n        require(lockedFor == address(0) || lockedFor == from, FrostLocked(id, lockTillOf(id)));\n\n        _requireAllowance(from, _msgSender());\n        _requireSlot(to);\n\n        remainderId = _move(id, frost, amount, to);\n\n        emit Transferred(id, remainderId, from, to, frost.tier, amount, frost.frozenAt, lockTillOf(id));\n    }\n\n    function returnLocked(uint256 id) external {\n        require(_msgSender() == _freezerMarket, OnlyMarketAccess());\n        address to = lockedForOf(id);\n        require(to != address(0), FrostNotLocked(id));\n\n        _requireAllowance(to, _msgSender());\n\n        Frost memory frost = _requireFrost(id);\n\n        require(to != frost.owner, InvalidReceiver(to));\n\n        _requireSlot(to);\n\n        _move(id, frost, frost.amount, to);\n        _unlock(id);\n\n        emit Returned(id, frost.owner, to, frost.tier, frost.amount);\n    }\n\n    function token() public view override returns (IERC20) {\n        return _token;\n    }\n\n    function freezerMarket() external view returns (address) {\n        return _freezerMarket;\n    }\n\n    function freezeHook() external view returns (address) {\n        return address(_freezeHook);\n    }\n\n    function getAccount(address owner) external view returns (AccountView memory) {\n        Account memory account = _accounts[owner];\n\n        return AccountView({\n            accruedNum: account.accruedNum,\n            lastAccrualAt: account.lastAccrualAt,\n            lastClaimAt: account.lastClaimAt,\n            firstFreezeAt: account.firstFreezeAt,\n            frostCount: account.frostCount,\n            frozenTotal: frozenOf(owner)\n        });\n    }\n\n    function frozenOf(address owner) public view returns (uint256 total) {\n        total = 0;\n        for (uint8 tier = 0; tier < TIERS; ++tier) {\n            total += _tierTotal[owner][tier];\n        }\n    }\n\n    function frozenByTierOf(address owner) external view returns (uint256[] memory out) {\n        out = new uint256[](TIERS);\n        for (uint8 tier = 0; tier < TIERS; ++tier) {\n            out[tier] = _tierTotal[owner][tier];\n        }\n    }\n\n    function pendingOf(address owner) external view returns (uint256) {\n        return _pending(owner);\n    }\n\n    function tierTotalOf(address owner, uint8 tier) external view returns (uint256) {\n        return _tierTotal[owner][tier];\n    }\n\n    function tiers() external pure returns (TierInfo[] memory out) {\n        out = new TierInfo[](TIERS);\n        for (uint8 tier = 0; tier < TIERS; ++tier) {\n            out[tier] = TierInfo({tier: tier, term: _term(tier), weight: _weight(tier)});\n        }\n    }\n\n    function totalFrozenByTier() external view returns (uint256[] memory out) {\n        out = new uint256[](TIERS);\n        for (uint8 tier = 0; tier < TIERS; ++tier) {\n            out[tier] = totalFrozenIn[tier];\n        }\n    }\n\n    function activeFrostsByTier() external view returns (uint256[] memory out) {\n        out = new uint256[](TIERS);\n        for (uint8 tier = 0; tier < TIERS; ++tier) {\n            out[tier] = activeFrostsIn[tier];\n        }\n    }\n\n    function unfreezeAtOf(uint256 id) external view returns (uint256) {\n        Frost memory frost = _frosts[id];\n        return frost.owner == address(0) ? 0 : _unfreezeAt(frost);\n    }\n\n    function getFrost(uint256 id) external view returns (FrostView memory) {\n        return _frostView(id);\n    }\n\n    function getFrosts(uint256[] calldata ids) external view returns (FrostView[] memory out) {\n        out = new FrostView[](ids.length);\n        for (uint256 i = 0; i < ids.length; ++i) {\n            out[i] = _frostView(ids[i]);\n        }\n    }\n\n    function availableRewards() public view returns (uint256) {\n        uint256 balance = _token.balanceOf(address(this));\n        return balance > totalFrozen ? balance - totalFrozen : 0;\n    }\n\n    function isApprovedForAll(address owner, address operator) public view override returns (bool) {\n        return _operatorPermitted(operator) && super.isApprovedForAll(owner, operator);\n    }\n\n    function _freeze(address owner, uint8 tier, uint256 amount) private returns (uint256 id) {\n        _settle(owner);\n\n        Account storage account = _accounts[owner];\n        if (account.firstFreezeAt == 0) {\n            account.firstFreezeAt = block.timestamp;\n        }\n\n        id = _create(owner, tier, amount, block.timestamp, block.timestamp);\n\n        _tierTotal[owner][tier] += amount;\n        totalFrozen += amount;\n        totalFrozenIn[tier] += amount;\n        _onStakeChanged(owner);\n\n        emit Frozen(id, owner, tier, amount);\n    }\n\n    function _move(uint256 id, Frost memory frost, uint256 amount, address to) private returns (uint256 remainderId) {\n        remainderId = 0;\n\n        _settle(frost.owner);\n        _settle(to);\n\n        _tierTotal[frost.owner][frost.tier] -= amount;\n        _tierTotal[to][frost.tier] += amount;\n        _onStakeChanged(frost.owner);\n        _onStakeChanged(to);\n\n        _frosts[id].owner = to;\n        _frosts[id].ownedAt = block.timestamp;\n        _accounts[frost.owner].frostCount -= 1;\n        _accounts[to].frostCount += 1;\n\n        if (amount != frost.amount) {\n            _frosts[id].amount = amount;\n            remainderId = _create(frost.owner, frost.tier, frost.amount - amount, frost.frozenAt, frost.ownedAt);\n        }\n\n        emit FrostChanged(id);\n    }\n\n    function _create(\n        address owner,\n        uint8 tier,\n        uint256 amount,\n        uint256 frozenAt,\n        uint256 ownedAt\n    ) private returns (uint256 id) {\n        id = nextFrostId++;\n        _frosts[id] = Frost({amount: amount, owner: owner, tier: tier, frozenAt: frozenAt, ownedAt: ownedAt});\n        _accounts[owner].frostCount += 1;\n        activeFrosts += 1;\n        activeFrostsIn[tier] += 1;\n\n        emit FrostCreated(id, owner);\n    }\n\n    function _destroy(address owner, uint256 id) private {\n        uint8 tier = _frosts[id].tier;\n\n        delete _frosts[id];\n        _accounts[owner].frostCount -= 1;\n        activeFrosts -= 1;\n        activeFrostsIn[tier] -= 1;\n\n        _unlock(id);\n\n        emit FrostRemoved(id, owner);\n    }\n\n    function _settle(address owner) private {\n        Account storage account = _accounts[owner];\n        uint256 earned = _accruedNumSince(owner, account.lastAccrualAt);\n        if (earned != 0) {\n            account.accruedNum += earned;\n        }\n        account.lastAccrualAt = block.timestamp;\n    }\n\n    function _notifyFreezeHook(address owner, address referrer, uint256 amount) private {\n        IFreezeHook hook = _freezeHook;\n        if (address(hook) != address(0)) {\n            hook.onFreeze(owner, referrer, amount, _accounts[owner].firstFreezeAt);\n        }\n    }\n\n    function _requireSlot(address owner) private view {\n        require(_accounts[owner].frostCount < MAX_FROSTS, TooManyFrosts(owner, MAX_FROSTS));\n    }\n\n    function _requireFrost(uint256 id) private view returns (Frost memory frost) {\n        frost = _frosts[id];\n        require(frost.owner != address(0), NonexistentFrost(id));\n    }\n\n    function _requireFrostOf(address owner, uint256 id) private view returns (Frost memory frost) {\n        frost = _requireFrost(id);\n        require(frost.owner == owner, IncorrectOwner(id, frost.owner, owner));\n    }\n\n    function _requireFree(uint256 id) private view {\n        require(!isLocked(id), FrostLocked(id, lockTillOf(id)));\n    }\n\n    function _accruedNumSince(address owner, uint256 since) private view returns (uint256) {\n        if (since == 0 || since >= block.timestamp) {\n            return 0;\n        }\n\n        uint256 elapsed = block.timestamp - since;\n        uint256 weighted;\n        for (uint8 tier = 0; tier < TIERS; ++tier) {\n            uint256 total = _tierTotal[owner][tier];\n            if (total != 0) {\n                weighted += total * _weight(tier);\n            }\n        }\n        return weighted * elapsed;\n    }\n\n    function _pending(address owner) private view returns (uint256) {\n        Account storage account = _accounts[owner];\n        return (account.accruedNum + _accruedNumSince(owner, account.lastAccrualAt)) / DENOM;\n    }\n\n    function _frostView(uint256 id) private view returns (FrostView memory out) {\n        Frost memory frost = _frosts[id];\n        if (frost.owner == address(0)) {\n            return out;\n        }\n\n        out = FrostView({\n            id: id,\n            owner: frost.owner,\n            tier: frost.tier,\n            amount: frost.amount,\n            frozenAt: frost.frozenAt,\n            ownedAt: frost.ownedAt,\n            unfreezeAt: _unfreezeAt(frost),\n            lockedTill: lockTillOf(id),\n            lockedFor: lockedForOf(id)\n        });\n    }\n\n    function _ownerOf(uint256 id) internal view override returns (address) {\n        return _frosts[id].owner;\n    }\n\n    function _operatorPermitted(address operator) internal view override returns (bool) {\n        return operator == _freezerMarket;\n    }\n\n    function _requireAllowance(address owner, address operator) internal view override {\n        _requireOperatorPermitted(operator);\n        require(isApprovedForAll(owner, operator), NotApproved(owner, operator));\n    }\n\n    function _stakeOf(address account) internal view override returns (uint256) {\n        return frozenOf(account);\n    }\n\n    function _collectCandidacyFee(address payer) internal override {\n        _token.safeTransferFrom(payer, address(this), candidacyFee);\n    }\n\n    function _afterExecute(uint256) internal view override {\n        uint256 balance = _token.balanceOf(address(this));\n        require(balance >= totalFrozen, TreasuryBelowFrozen(balance, totalFrozen));\n    }\n\n    function _unfreezeAt(Frost memory frost) private pure returns (uint256) {\n        return frost.frozenAt + _term(frost.tier);\n    }\n\n    function _term(uint8 tier) private pure returns (uint256) {\n        return (uint256(tier) * 2 + 1) * YEAR;\n    }\n\n    function _weight(uint8 tier) private pure returns (uint256) {\n        return uint256(tier) + 1;\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f5ffd5b50600436106104bc575f3560e01c806381bfd06711610279578063d147b74111610156578063ea0217cf116100ca578063f7de0ee71161008f578063f7de0ee714610cfe578063fb6f049f14610d11578063fbcbc0f114610d19578063fc0c546a14610d77578063fe0d94c114610d9d578063fed2e7a414610db0575f5ffd5b8063ea0217cf14610c87578063f44136a114610c9a578063f5faa4f114610cad578063f6aacfb114610cc0578063f794062e14610cd3575f5ffd5b8063dd4670641161011b578063dd46706414610c01578063de62d84214610c14578063e1ddbb1f14610c27578063e3034a8e14610c4e578063e5e7f38014610c61578063e985e9c514610c74575f5ffd5b8063d147b74114610b75578063d6d7e82c14610ba8578063d96a8bf114610bcf578063da35c66414610be2578063dbd42da514610beb575f5ffd5b8063a64e024a116101ed578063c3c5a547116101b2578063c3c5a54714610ad2578063c7f758a814610afd578063c9d27afe14610b1d578063cbe230c314610b30578063cccb19b814610b43578063d0a9645a14610b56575f5ffd5b8063a64e024a14610a5a578063aa34c12014610a64578063b3dc7e0c14610a77578063b7f3b59714610a85578063bc307cf914610a98575f5ffd5b806391dd73461161023e57806391dd7346146109fb57806391e916a414610a1b5780639201ea0a14610a2e578063950ad27a14610a365780639f35eb3414610a3e578063a437635214610a47575f5ffd5b806381bfd0671461099357806383914540146109b9578063879d9090146109c45780638ad87cec146109cc5780638dd1db53146109f3575f5ffd5b80633724fc1c116103a75780634a95d9d51161031b5780635bbe0837116102e05780635bbe08371461081b5780636198e339146109385780636c53e3681461094b5780636e748f971461095e5780637657a03c146109785780637dfe5b9214610980575f5ffd5b80634a95d9d5146107d75780634c55f4f8146107ec5780634cbde58f146108015780634e71d92d1461080a57806355b78daf14610812575f5ffd5b80633e09a4ee1161036c5780633e09a4ee146107165780633e4f49e61461072957806340e58ee51461074957806345ddc85d1461075c578063490055c0146107a157806349403183146107c4575f5ffd5b80633724fc1c146106ad57806337c909ec1461063057806337f31e40146106d55780633bf0c3f5146106fb5780633c7a05081461070e575f5ffd5b806316343da41161043e5780631e7f87bc116104035780631e7f87bc14610627578063215809ca14610630578063242cae9f1461063a5780632735803b1461064d578063328a1c9514610687578063353fa4991461069a575f5ffd5b806316343da41461059b578063165f150a146105a65780631aec3867146105c65780631bb11313146105f45780631bf6e00d14610614575f5ffd5b80630afb0409116104845780630afb0409146105205780630e798e61146105355780631338736f1461053d578063144e4fc314610550578063150b7a0214610563575f5ffd5b806302a251a3146104c057806302d102a4146104dc578063040eaff0146104fb578063083a258a1461051057806309e51ade14610518575b5f5ffd5b6104c960045481565b6040519081526020015b60405180910390f35b6104c96104ea366004614d0a565b60126020525f908152604090205481565b610503610ddb565b6040516104d39190614d5d565b6104c9601581565b6104c9600381565b61053361052e366004614d85565b610e48565b005b6104c9610ea0565b61053361054b366004614d9e565b610eaf565b61053361055e366004614dbe565b610ed4565b610582610571366004614e33565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016104d3565b6104c96312cc030081565b6105b96105b4366004614e9c565b610f43565b6040516104d39190614f7c565b6105d96105d4366004614feb565b610ff0565b604080519384526020840192909252908201526060016104d3565b61060761060236600461504a565b611035565b6040516104d39190615061565b6104c9610622366004614d85565b61104c565b6104c9600f5481565b6104c96201518081565b610533610648366004614d85565b61109b565b7f000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a3255b6040516001600160a01b0390911681526020016104d3565b6104c9610695366004614e9c565b6110b0565b6104c96106a8366004615070565b6112a4565b6106c06106bb3660046150b3565b6114d2565b604080519283526020830191909152016104d3565b7f000000000000000000000000cd5762ac6013fa762782ac1797ab09152c1028e861066f565b61053361070936600461504a565b61150f565b61053361167a565b61066f61072436600461504a565b611685565b61073c61073736600461504a565b61168f565b6040516104d391906150f5565b61053361075736600461504a565b6116a1565b61079461076a366004615103565b5f918252600d602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6040516104d39190615124565b6107b46107af366004614d85565b6117a1565b60405190151581526020016104d3565b6107b46107d236600461504a565b61184f565b6107df611861565b6040516104d3919061513e565b6107f4611916565b6040516104d391906151cd565b6104c9600e5481565b6105336119e1565b6104c960035481565b61092b61082936600461504a565b60408051610120810182525f6080820181815260a0830182905260c0830182905260e0830182905261010083018290528252602082018190529181018290526060810191909152505f9081527f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62d4602090815260409182902082516101208101845281546001600160a01b0390811660808301908152600184015480831660a0850152600160a01b810462ffffff1660c0850152600160b81b9004600290810b60e0850152808501549092166101008401528252600383015480820b94830194909452630100000090930490920b92820192909252600490910154606082015290565b6040516104d391906151df565b61053361094636600461504a565b611b8a565b61053361095936600461504a565b611bc1565b610966600381565b60405160ff90911681526020016104d3565b6104c9611ca6565b61053361098e366004615266565b611d33565b7f000000000000000000000000fa9d2a61f80772baafdda87082ffcea0232df73861066f565b6104c96301e1338081565b6104c9611f9d565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c8546104c9565b610503612045565b610a0e610a09366004615287565b6120ae565b6040516104d391906152f3565b6104c9610a29366004615305565b6120b8565b6104c960ff81565b6104c9606481565b6104c960105481565b6104c9610a5536600461534c565b612164565b6104c962278d0081565b6104c9610a7236600461504a565b6121a5565b6105d96105d43660046153b7565b6104c9610a9336600461504a565b6121b8565b6104c9610aa63660046153fd565b6001600160a01b0382165f90815260146020908152604080832060ff8516845290915290205492915050565b6107b4610ae0366004614d85565b6001600160a01b03165f9081526006602052604090205460ff1690565b610b10610b0b36600461504a565b6121c2565b6040516104d39190615425565b610533610b2b3660046154ab565b61238e565b6107b4610b3e366004614d85565b6124d4565b6104c9610b513660046154cc565b612597565b6104c9610b64366004614d0a565b60116020525f908152604090205481565b610b88610b83366004615536565b6127b0565b6040805194855260208501939093529183015260608201526080016104d3565b6104c97f0000000000000000000000000000000000000000000000000000000005f5e10081565b610503610bdd366004614d85565b6127f6565b6104c960055481565b610bf3612874565b6040516104d3929190615574565b610533610c0f36600461504a565b6129c5565b6104c9610c22366004614e9c565b6129d0565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c7546104c9565b6104c9610c5c36600461504a565b612b7f565b6104c9610c6f366004615598565b612bf1565b6107b4610c82366004614dbe565b612c28565b610533610c9536600461504a565b612c6a565b6104c9610ca8366004614d85565b612d4f565b6106c0610cbb3660046155d9565b612d59565b6107b4610cce36600461504a565b612d9a565b6107b4610ce1366004614d85565b6001600160a01b03165f9081526007602052604090205460ff1690565b610533610d0c366004614d9e565b612da4565b600b546104c9565b610d2c610d27366004614d85565b612fbf565b6040516104d391905f60c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b7f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a10061066f565b610533610dab36600461504a565b6130a2565b6104c9610dbe366004614d85565b6001600160a01b03165f9081526008602052604090206002015490565b604080516003808252608082019092526060916020820183803683370190505090505f5b600360ff82161015610e445760ff81165f818152601260205260409020548351909184918110610e3157610e3161561c565b6020908102919091010152600101610dff565b5090565b6001600160a01b0381165f90815260066020526040902054819060ff16610e935760405163bfc6c33760e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b50610e9d816131cf565b50565b610eac60156004615644565b81565b610eb9828261347c565b60405182905f5160206159675f395f51905f52905f90a25050565b336001600160a01b038316811480610efd5750816001600160a01b0316816001600160a01b0316145b83839091610f3157604051630ca03e9b60e11b81526001600160a01b03928316600482015291166024820152604401610e8a565b5050610f3e83835f6134ff565b505050565b6060816001600160401b03811115610f5d57610f5d615608565b604051908082528060200260200182016040528015610f9657816020015b610f83614c9d565b815260200190600190039081610f7b5790505b5090505f5b82811015610fe957610fc4848483818110610fb857610fb861561c565b905060200201356135c0565b828281518110610fd657610fd661561c565b6020908102919091010152600101610f9b565b5092915050565b5f8080333081146110205760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b506110296136ae565b96509650969350505050565b61103d614c9d565b611046826135c0565b92915050565b5f805b600360ff82161015611095576001600160a01b0383165f90815260146020908152604080832060ff8516845290915290205461108b908361565b565b915060010161104f565b50919050565b6110a4816136ed565b610e9d338260016134ff565b5f816001816110db57604051631905fe7960e21b815260048101929092526024820152604401610e8a565b50505f90505f6110e83390565b90506110f381613748565b5f5b8381101561124f575f8585838181106111105761111061561c565b9050602002013590505f611124848361379d565b905061112f82613839565b5f61113982613875565b9050828142811115611167576040516306f3183360e41b815260048101929092526024820152604401610e8a565b50508151611175908761565b565b82516001600160a01b0387165f9081526014602090815260408083208188015160ff1684529091528120805493995091926111b190849061566e565b9091555050815160408084015160ff165f908152601160205290812080549091906111dd90849061566e565b909155506111ed90508584613892565b6040828101518351825160ff909216825260208201525f8183015290516001600160a01b0387169185917f594761400b83cf4c3878ee37d05e98add500ea3b6716a89da223580c847680b09181900360600190a35050508060010190506110f5565b5081600f5f828254611261919061566e565b909155506112709050816131cf565b610fe96001600160a01b037f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a100168284613984565b5f337f000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a3256001600160a01b0316146112ee57604051633c37181960e01b815260040160405180910390fd5b6001600160a01b0382161580159061130f57506001600160a01b0382163014155b801561132d5750846001600160a01b0316826001600160a01b031614155b829061135857604051639cfea58360e01b81526001600160a01b039091166004820152602401610e8a565b50825f0361137957604051631f2a200560e01b815260040160405180910390fd5b5f611384868661379d565b8051909150859085818111156113be5760405163fec7c07160e01b8152600481019390935260248301919091526044820152606401610e8a565b5050505f6113cb86611685565b90506001600160a01b03811615806113f45750866001600160a01b0316816001600160a01b0316145b866113fe886121a5565b90916114265760405163a582711f60e01b815260048101929092526024820152604401610e8a565b5050611438876114333390565b6139b9565b61144184613a00565b61144d86838787613a50565b9250866001600160a01b031683877f0c8571631232fd02cd7c4977095e95bbfafa3699ba05adec8d5cb6322e5012c18786604001518a88606001516114918e6121a5565b604080516001600160a01b03909616865260ff9094166020860152928401919091526060830152608082015260a00160405180910390a45050949350505050565b5f80333081146115015760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5061150a6136ae565b915091565b337f000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a3256001600160a01b03161461155857604051633c37181960e01b815260040160405180910390fd5b5f61156282611685565b9050816001600160a01b03821661158f576040516310919eab60e21b8152600401610e8a91815260200190565b5061159a81336139b9565b5f6115a483613bfa565b905080602001516001600160a01b0316826001600160a01b0316141582906115eb57604051639cfea58360e01b81526001600160a01b039091166004820152602401610e8a565b506115f582613a00565b6116048382835f015185613a50565b5061160e83613cac565b816001600160a01b031681602001516001600160a01b0316847fd186a9f6f913a9fbe33f3f86812678e0d9d23aa5d38669bf220157e476cb4bbd8460400151855f015160405161166d92919060ff929092168252602082015260400190565b60405180910390a4505050565b61168333613d1c565b565b5f61104682613dcb565b5f61104661169c83613dfc565b613e36565b335f6116ac83613dfc565b8054909150839083906001600160a01b0390811690821681146116fc576040516364a13eed60e01b815260048101939093526001600160a01b039182166024840152166044820152606401610e8a565b5050505f61170982613e36565b90505f81600381111561171e5761171e6150cd565b148061173b57506003816003811115611739576117396150cd565b145b8482909161175e57604051631494273360e21b8152600401610e8a929190615681565b505060038201805461ff00191661010017905560405184907f416e669c63d9a3a5e36ee7cc7e2104b8db28ccd286aa18966e98fa230c73b08c905f90a250505050565b6001600160a01b0381165f9081526007602052604081205460ff166117c757505f919050565b6009546001600160a01b03165f5b600354811080156117ee57506001600160a01b03821615155b1561184657836001600160a01b0316826001600160a01b031603611816575060019392505050565b6001600160a01b039182165f908152600860205260409020600101549091169061183f81615695565b90506117d5565b505f9392505050565b5f61104661185c836121b8565b613e7b565b60408051600380825260808201909252606091816020015b61189d60405180606001604052805f60ff1681526020015f81526020015f81525090565b8152602001906001900390816118795790505090505f5b600360ff82161015610e445760405180606001604052808260ff1681526020016118dd83613e92565b81526020016118eb83613ebb565b815250828260ff16815181106119035761190361561c565b60209081029190910101526001016118b4565b60605f600b546003541061192c57600b54611930565b6003545b9050806001600160401b0381111561194a5761194a615608565b604051908082528060200260200182016040528015611973578160200160208202803683370190505b506009549092506001600160a01b03165f5b828110156119db57818482815181106119a0576119a061561c565b6001600160a01b039283166020918202929092018101919091529281165f908152600890935260409092206001908101549092169101611985565b50505090565b335f81815260136020526040812060020154611a0190620151809061565b565b9050818142811115611a375760405163967c4a1d60e01b81526001600160a01b0390921660048301526024820152604401610e8a565b5050611a4282613eca565b8290611a6d576040516332559a3360e11b81526001600160a01b039091166004820152602401610e8a565b50611a7782613748565b6001600160a01b0382165f9081526013602052604081208054909190611aa2906312cc0300906156ad565b90505f611aad611f9d565b90505f818310611abd5781611abf565b825b9050805f03611ae157604051632aad581f60e01b815260040160405180910390fd5b611aef6312cc030082615644565b845f015f828254611b00919061566e565b9091555050426002850155611b3f6001600160a01b037f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a100168783613984565b856001600160a01b03167fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a82604051611b7a91815260200190565b60405180910390a2505050505050565b5f611b9482612d9a565b9050611b9f82613f0d565b8015611bbd5760405182905f5160206159675f395f51905f52905f90a25b5050565b33308114611bee5760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5060038110158015611c01575060158111155b8160036015909192611c37576040516348ca9d6d60e01b8152600481019390935260248301919091526044820152606401610e8a565b5050600354905081808203611c6257604051630455bbeb60e01b8152600401610e8a91815260200190565b50600382905560408051828152602081018490527f6202000939fed2067e5095bb4fed84b9f3c8471e45071e06840a83a154b1924c91015b60405180910390a15050565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c8547f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c7545f917f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c69111611d19575f611d2d565b80600201548160010154611d2d919061566e565b91505090565b80600360ff821610611d5e57604051635e50d4ab60e11b815260ff9091166004820152602401610e8a565b50335f611d6b828561379d565b604081015190915084908460ff80831690821611611db057604051632e9a46f560e01b8152600481019390935260ff9182166024840152166044820152606401610e8a565b505050611dbc84613839565b611dc582613748565b80516001600160a01b0383165f9081526014602090815260408083208186015160ff16845290915281208054909190611dff90849061566e565b909155505080516001600160a01b0383165f90815260146020908152604080832060ff8816845290915281208054909190611e3b90849061565b565b9091555050805160408083015160ff165f90815260116020529081208054909190611e6790849061566e565b9091555050805160ff84165f9081526011602052604081208054909190611e8f90849061565b565b909155505060408082015160ff165f9081526012602052908120805460019290611eba90849061566e565b909155505060ff83165f908152601260205260408120805460019290611ee190849061565b565b90915550505f84815260156020526040902060018101805460ff60a01b1916600160a01b60ff8716021790554260028201819055600390910155611f24826131cf565b6040818101518251825160ff928316815291861660208301528183015242606082015290516001600160a01b0384169186917f59605b01384e51f98f39b719b389a370c2b776755d561f35a0e64d35b0766e9c9181900360800190a360405184905f5160206159675f395f51905f52905f90a250505050565b6040516370a0823160e01b81523060048201525f9081906001600160a01b037f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a10016906370a0823190602401602060405180830381865afa158015612003573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061202791906156cc565b9050600f548111612038575f611d2d565b600f54611d2d908261566e565b604080516003808252608082019092526060916020820183803683370190505090505f5b600360ff82161015610e445760ff81165f81815260116020526040902054835190918491811061209b5761209b61561c565b6020908102919091010152600101612069565b60606110466136ae565b5f83600360ff8216106120e457604051635e50d4ab60e11b815260ff9091166004820152602401610e8a565b50825f0361210557604051631f2a200560e01b815260040160405180910390fd5b3361210f81613a00565b6121446001600160a01b037f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a10016823087613f3b565b61214f818686613f71565b915061215c81848661408a565b509392505050565b5f333081146121925760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5061219b6136ae565b9695505050505050565b5f81815260026020526040812054611046565b5f610fe982614140565b61220a6040518060e001604052805f6001600160a01b031681526020015f81526020015f81526020015f151581526020015f1515815260200160608152602001606081525090565b61221382613dfc565b6040805160e08101825282546001600160a01b0316815260018301546020820152600283015491810191909152600382015460ff80821615156060840152610100909104161515608082015260048201805491929160a084019190612277906156e3565b80601f01602080910402602001604051908101604052809291908181526020018280546122a3906156e3565b80156122ee5780601f106122c5576101008083540402835291602001916122ee565b820191905f5260205f20905b8154815290600101906020018083116122d157829003601f168201915b50505050508152602001600582018054612307906156e3565b80601f0160208091040260200160405190810160405280929190818152602001828054612333906156e3565b801561237e5780601f106123555761010080835404028352916020019161237e565b820191905f5260205f20905b81548152906001019060200180831161236157829003601f168201915b5050505050815250509050919050565b3361239883614264565b506123a2816117a1565b81906123cd5760405163dbed96b160e01b81526001600160a01b039091166004820152602401610e8a565b505f838152600d602090815260408083206001600160a01b038516845290915281205460ff166002811115612404576124046150cd565b1483829091612438576040516304f9da6360e01b815260048101929092526001600160a01b03166024820152604401610e8a565b505081612446576002612449565b60015b5f848152600d602090815260408083206001600160a01b03861684529091529020805460ff19166001836002811115612484576124846150cd565b0217905550806001600160a01b0316837ff2913dbe661ee2acc4a046d8fbcdc792373bda34c41c6086484b5345e5785e5f846040516124c7911515815260200190565b60405180910390a3505050565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c680545f91907f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c9906001600160a01b0385811691161480612541575080546001600160a01b038581169116145b8061255b575060018101546001600160a01b038581169116145b80612575575060028101546001600160a01b038581169116145b8061258f575060038101546001600160a01b038581169116145b949350505050565b5f336125a2816117a1565b81906125cd5760405163dbed96b160e01b81526001600160a01b039091166004820152602401610e8a565b5060048510156125f057604051638129bbcd60e01b815260040160405180910390fd5b8260ff8082111561261d576040516371a24cf360e01b815260048101929092526024820152604401610e8a565b505f905061262e600482888a615715565b6126379161573c565b9050612642816142bb565b819061266e5760405163f556f5dd60e01b81526001600160e01b03199091166004820152602401610e8a565b5060055f815461267d90615695565b91829055505f818152600c6020526040902080546001600160a01b0319166001600160a01b038516178155426001820181905560045492955090916126c19161565b565b6002820155600481016126d5888a836157bd565b50600581016126e58688836157bd565b505f848152600d602090815260408083206001600160a01b038716808552925291829020805460ff19166001179055600283015491516001600160e01b031985169287917fee300f98871a66204e294dd5d599a0dfd9098b69082f5efd229eff1e90c14d329161275c918e918e918e918e9161589e565b60405180910390a4604051600181526001600160a01b0384169085907ff2913dbe661ee2acc4a046d8fbcdc792373bda34c41c6086484b5345e5785e5f9060200160405180910390a3505050949350505050565b5f808080333081146127e15760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b506127ea6136ae565b95509550955095915050565b604080516003808252608082019092526060916020820183803683370190505090505f5b600360ff82161015611095576001600160a01b0383165f90815260146020908152604080832060ff851680855292529091205483519091849181106128615761286161561c565b602090810291909101015260010161281a565b606080600b546001600160401b0381111561289157612891615608565b6040519080825280602002602001820160405280156128ba578160200160208202803683370190505b509150600b546001600160401b038111156128d7576128d7615608565b604051908082528060200260200182016040528015612900578160200160208202803683370190505b506009549091506001600160a01b03165f5b600b548110156129bf578184828151811061292f5761292f61561c565b60200260200101906001600160a01b031690816001600160a01b03168152505060085f836001600160a01b03166001600160a01b031681526020019081526020015f20600201548382815181106129885761298861561c565b6020908102919091018101919091526001600160a01b039283165f9081526008909152604090206001908101549092169101612912565b50509091565b610e9d815f19610eaf565b5f816002808210156129fe57604051631905fe7960e21b815260048101929092526024820152604401610e8a565b50505f612a083390565b9050612a1381613748565b5f612a368286865f818110612a2a57612a2a61561c565b9050602002013561379d565b6040015190505f80805b86811015612af5575f888883818110612a5b57612a5b61561c565b9050602002013590505f612a6f878361379d565b9050612a7a82613839565b604081015182908760ff82811690821614612abc5760405163471aa4c360e11b8152600481019390935260ff9182166024840152166044820152606401610e8a565b50508151612acb91508661565b565b94508381606001511115612ae157806060015193505b612aeb8783613892565b5050600101612a40565b50612b038484848442614381565b94505f5b86811015612b7457846001600160a01b031686898984818110612b2c57612b2c61561c565b60405160ff8a16815260209182029390930135927f4c6d50c854fc7fbedd38ca40809a9025c521eaf63b901edbb714c3afdef5536592500160405180910390a4600101612b07565b505050505092915050565b5f818152601560209081526040808320815160a0810183528154815260018201546001600160a01b038116948201859052600160a01b900460ff1692810192909252600281015460608301526003015460808201529015612be857612be381613875565b612bea565b5f5b9392505050565b5f33308114612c1f5760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5061258f6136ae565b5f7f000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a3256001600160a01b03908116908316148015612bea5750612bea83836144bc565b33308114612c975760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b50620151808110158015612cae575062278d008111155b816201518062278d00909192612ce8576040516319bd218160e11b8152600481019390935260248301919091526044820152606401610e8a565b5050600454905081808203612d1357604051630455bbeb60e01b8152600401610e8a91815260200190565b50600482905560408051828152602081018490527f0157f874643e34dea2d71607bde6378f09880b59546f9e2386608eb7154b89759101611c9a565b5f61104682613eca565b5f8033308114612d885760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b50612d916136ae565b94509492505050565b5f611046826144c7565b805f03612dc457604051631f2a200560e01b815260040160405180910390fd5b335f612dd0828561379d565b9050612ddb84613839565b805184908481811115612e125760405163fec7c07160e01b8152600481019390935260248301919091526044820152606401610e8a565b5050505f612e1f82613875565b9050848142811115612e4d576040516306f3183360e41b815260048101929092526024820152604401610e8a565b5050612e5883613748565b81515f90612e6790869061566e565b9050805f03612e7f57612e7a8487613892565b612ea4565b5f868152601560205260408082208390555187915f5160206159675f395f51905f5291a25b6001600160a01b0384165f9081526014602090815260408083208682015160ff16845290915281208054879290612edc90849061566e565b9250508190555084600f5f828254612ef4919061566e565b909155505060408084015160ff165f90815260116020529081208054879290612f1e90849061566e565b90915550612f2d9050846131cf565b612f616001600160a01b037f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a100168587613984565b604080840151815160ff9091168152602081018790529081018290526001600160a01b0385169087907f594761400b83cf4c3878ee37d05e98add500ea3b6716a89da223580c847680b09060600160405180910390a3505050505050565b612ff26040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f60135f846001600160a01b03166001600160a01b031681526020019081526020015f206040518060a00160405290815f820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506040518060c00160405280825f01518152602001826020015181526020018260400151815260200182606001518152602001826080015181526020016130998561104c565b90529392505050565b5f6130ac82614264565b6003549091505f806130bd85614140565b915091506130ca82613e7b565b8583859091926130fe576040516374efa1a960e11b8152600481019390935260248301919091526044820152606401610e8a565b50505060038401805460ff191660011790556040515f90819030906131279060048901906158d7565b5f604051808303815f865af19150503d805f8114613160576040519150601f19603f3d011682016040523d82523d5f602084013e613165565b606091505b50915091508161317757805160208201fd5b613180876144dc565b336001600160a01b0316877f3bbf47743a2af00b3c2d0ca51ddeef4c3b44599cffefeb12a52782068f436e518688876040516131be93929190615948565b60405180910390a350505050505050565b6001600160a01b0381165f9081526006602052604090205460ff166131f15750565b5f6131fb82614596565b6001600160a01b0383165f9081526007602052604090205490915060ff1661330357805f03613228575050565b61323460156004615644565b600b54036132a257600a546001600160a01b03165f81815260086020526040902060020154821161326457505050565b61326d816145a0565b6040516001600160a01b038216907fac3da8e81cf2b8696731b597ee3f55915425b9bcd10e3852612b20deb4a99fde905f90a2505b600a546132bc90839083906001600160a01b03165f614725565b816001600160a01b03167fc9fc9ea705f0caebf021a6bb6c51a7d6fc3e360ae32094274f64de0132f2ff16826040516132f791815260200190565b60405180910390a25050565b805f0361334a57613313826145a0565b6040516001600160a01b038316907fac3da8e81cf2b8696731b597ee3f55915425b9bcd10e3852612b20deb4a99fde905f90a25050565b6001600160a01b0382165f90815260086020526040902060028101548083036133735750505050565b815460018301546001600160a01b039182169116828511801561339e57506001600160a01b03821615155b80156133c357506001600160a01b0382165f9081526008602052604090206002015485115b156133e2576133d1866145a0565b6133dd8686845f614725565b613441565b82851080156133f957506001600160a01b03811615155b801561341e57506001600160a01b0381165f9081526008602052604090206002015485105b156134395761342c866145a0565b6133dd8686836001614725565b600284018590555b856001600160a01b03167fc9fc9ea705f0caebf021a6bb6c51a7d6fc3e360ae32094274f64de0132f2ff1686604051611b7a91815260200190565b5f8281526015602052604090206001015433906001600160a01b031683816134b95760405162d2a3f760e21b8152600401610e8a91815260200190565b504283116134da5760405163ca72d5c760e01b815260040160405180910390fd5b6134e481836139b9565b6134ee84826149a3565b6134f98482856149f8565b50505050565b6001600160a01b038381165f90815260208181526040808320938616835292905220805460ff1916821580159190911790915561357b57816001600160a01b0316836001600160a01b03167f92b270b94fd320d925800c308edf63e09be8dc4b4b10cc01ab08277a43d63e2760405160405180910390a3505050565b816001600160a01b0316836001600160a01b03167f480aa4a4a49d94f1351f899ef81d4ce57a62fa1c4c370779f4b22b60e6b0487e60405160405180910390a3505050565b6135c8614c9d565b5f82815260156020908152604091829020825160a0810184528154815260018201546001600160a01b038116938201849052600160a01b900460ff1693810193909352600281015460608401526003015460808301526136285750919050565b60405180610120016040528084815260200182602001516001600160a01b03168152602001826040015160ff168152602001825f01518152602001826060015181526020018260800151815260200161368083613875565b815260200161368e856121a5565b815260200161369c85611685565b6001600160a01b031690529392505050565b7f000000000000000000000000cd5762ac6013fa762782ac1797ab09152c1028e8365f80375f5f365f845af43d5f5f3e8080156136e9573d5ff35b3d5ffd5b7f000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a3256001600160a01b03908116908216148190611bbd57604051632d06956360e11b81526001600160a01b039091166004820152602401610e8a565b6001600160a01b0381165f9081526013602052604081206001810154909190613772908490614a5d565b905080156137925780825f015f82825461378c919061565b565b90915550505b504260019091015550565b6137d66040518060a001604052805f81526020015f6001600160a01b031681526020015f60ff1681526020015f81526020015f81525090565b6137df82613bfa565b60208101519091508290846001600160a01b0382811690821614613830576040516326603ebf60e21b815260048101939093526001600160a01b039182166024840152166044820152606401610e8a565b50505092915050565b61384281612d9a565b158161384d836121a5565b9091610f3e5760405163a582711f60e01b815260048101929092526024820152604401610e8a565b5f6138838260400151613e92565b8260600151611046919061565b565b5f818152601560209081526040808320600180820180548684556001600160a81b031981169091556002830186905560039092018590556001600160a01b038716855260139093529083206004018054600160a01b90920460ff169390916138fb90849061566e565b92505081905550600160105f828254613914919061566e565b909155505060ff81165f90815260126020526040812080546001929061393b90849061566e565b9091555061394a905082613cac565b6040516001600160a01b0384169083907f34c4f6ef00ced14f223f904220331f3ca4bb5b0fcef114040e28e874afaa2ea6905f90a3505050565b6139918383836001614afc565b610f3e57604051635274afe760e01b81526001600160a01b0384166004820152602401610e8a565b6139c2816136ed565b6139cc8282612c28565b828290916134f957604051630ca03e9b60e11b81526001600160a01b03928316600482015291166024820152604401610e8a565b6001600160a01b0381165f9081526013602052604090206004015481906064908111610f3e5760405163031086ef60e01b81526001600160a01b0390921660048301526024820152604401610e8a565b60208301515f90613a6090613748565b613a6982613748565b6020808501516001600160a01b03165f9081526014825260408082208188015160ff1683529092529081208054859290613aa490849061566e565b90915550506001600160a01b0382165f9081526014602090815260408083208782015160ff16845290915281208054859290613ae190849061565b565b90915550506020840151613af4906131cf565b613afd826131cf565b5f858152601560209081526040808320600180820180546001600160a01b0319166001600160a01b03898116919091179091554260039093019290925588840151909116845260139092528220600401805491929091613b5e90849061566e565b90915550506001600160a01b0382165f908152601360205260408120600401805460019290613b8e90849061565b565b909155505083518314613bdb575f85815260156020908152604091829020859055850151908501518551613bd8929190613bc990879061566e565b87606001518860800151614381565b90505b60405185905f5160206159675f395f51905f52905f90a2949350505050565b613c336040518060a001604052805f81526020015f6001600160a01b031681526020015f60ff1681526020015f81526020015f81525090565b505f81815260156020908152604091829020825160a0810184528154815260018201546001600160a01b038116938201849052600160a01b900460ff1693810193909352600281015460608401526003015460808301528290611095576040516333365b9b60e11b8152600401610e8a91815260200190565b5f818152600160205260409020546001600160a01b0316613cca5750565b5f81815260016020908152604080832080546001600160a01b031916905560029091528082208290555182917ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184291a250565b6001600160a01b0381165f90815260066020526040902054819060ff1615613d63576040516345ed80e960e01b81526001600160a01b039091166004820152602401610e8a565b506001600160a01b0381165f908152600660205260409020805460ff19166001179055613d8f81614b5e565b6040516001600160a01b038216907f2d3734a8e47ac8316e500ac231c90a6e1848ca2285f40d07eaa52005e4b3a0e9905f90a2610e9d816131cf565b5f613dd5826144c7565b15613df557505f908152600160205260409020546001600160a01b031690565b505f919050565b5f818152600c60205260409020805482906001600160a01b031661109557604051630853c2a360e41b8152600401610e8a91815260200190565b60038101545f9060ff1615613e4d57506001919050565b6003820154610100900460ff1615613e6757506002919050565b8160020154421115613df557506003919050565b6003545f90613e8b836002615644565b1192915050565b5f6301e13380613ea660ff84166002615644565b613eb190600161565b565b6110469190615644565b5f61104660ff8316600161565b565b6001600160a01b0381165f90815260136020526040812060018101546312cc030090613ef7908590614a5d565b8254613f03919061565b565b612bea91906156ad565b5f613f1782613dcb565b90506001600160a01b03811615613f3257613f3281336139b9565b611bbd82613cac565b613f49848484846001614bb3565b6134f957604051635274afe760e01b81526001600160a01b0385166004820152602401610e8a565b5f613f7b84613748565b6001600160a01b0384165f9081526013602052604081206003810154909103613fa5574260038201555b613fb28585854242614381565b6001600160a01b0386165f90815260146020908152604080832060ff89168452909152812080549294508592909190613fec90849061565b565b9250508190555082600f5f828254614004919061565b565b909155505060ff84165f908152601160205260408120805485929061402a90849061565b565b909155506140399050856131cf565b6040805160ff86168152602081018590526001600160a01b0387169184917f01415f65daddd59a2671475ab000aafd1dedb0b607767279efd74e10fe535521910160405180910390a3509392505050565b7f000000000000000000000000fa9d2a61f80772baafdda87082ffcea0232df7386001600160a01b038116156134f9576001600160a01b038481165f8181526013602052604090819020600301549051639f31216560e01b81526004810192909252858316602483015260448201859052606482015290821690639f312165906084015f604051808303815f87803b158015614124575f5ffd5b505af1158015614136573d5f5f3e3d5ffd5b5050505050505050565b6003545f906060906001600160401b0381111561415f5761415f615608565b604051908082528060200260200182016040528015614188578160200160208202803683370190505b506009549091505f906001600160a01b03165b600354821080156141b457506001600160a01b03811615155b1561425a57808383815181106141cc576141cc61561c565b6001600160a01b039092166020928302919091019091015260015f868152600d602090815260408083206001600160a01b038616845290915290205460ff16600281111561421c5761421c6150cd565b0361422d5761422a84615695565b93505b6001600160a01b039081165f908152600860205260409020600101541661425382615695565b915061419b565b8183525050915091565b5f61426e82613dfc565b90505f61427a82613e36565b90505f81600381111561428f5761428f6150cd565b14838290916142b357604051631494273360e21b8152600401610e8a929190615681565b505050919050565b5f6001600160e01b03198216630dc93f0760e21b14806142eb57506001600160e01b03198216632cf71f8360e21b145b8061430657506001600160e01b0319821663d147b74160e01b145b8061432157506001600160e01b0319821663521bb1a960e11b145b8061433c57506001600160e01b03198216631aec386760e01b145b8061435757506001600160e01b0319821663f5faa4f160e01b145b8061437257506001600160e01b031982166301cbcfe760e71b145b80611046575061104682614c20565b600e80545f918261439183615695565b909155506040805160a0810182528681526001600160a01b03808a16602080840182815260ff808d16868801908152606087018c8152608088018c81525f8b8152601587528a812099518a5594516001808b0180549551909616600160a01b026001600160a81b03199095169190991617929092179092559051600287015551600390950194909455908352601390529181206004018054939450919261443990849061565b565b92505081905550600160105f828254614452919061565b565b909155505060ff85165f90815260126020526040812080546001929061447990849061565b565b90915550506040516001600160a01b0387169082907fa22c02fc603732177d8ac2aa6242d6a44b293fb36ed8ec905065f8b5e2c03bf8905f90a395945050505050565b5f612bea8383614c55565b5f818152600260205260408120544290613e8b565b6040516370a0823160e01b81523060048201525f907f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a1006001600160a01b0316906370a0823190602401602060405180830381865afa158015614540573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061456491906156cc565b600f549091508190808210156134f957604051635295bde160e01b815260048101929092526024820152604401610e8a565b5f6110468261104c565b6001600160a01b038082165f90815260086020908152604091829020825160608101845281548516808252600183015490951692810192909252600201549181019190915290614613576020810151600980546001600160a01b0319166001600160a01b0390921691909117905561464e565b60208181015182516001600160a01b039081165f9081526008909352604090922060010180546001600160a01b031916929091169190911790555b60208101516001600160a01b0316614686578051600a80546001600160a01b0319166001600160a01b039092169190911790556146bb565b80516020808301516001600160a01b039081165f9081526008909252604090912080546001600160a01b031916919092161790555b6001600160a01b0382165f90815260086020908152604080832080546001600160a01b0319908116825560018083018054909216909155600290910184905560079092528220805460ff19169055600b80549192909161471c90849061566e565b90915550505050565b815b6001600160a01b0381161580159061475857506001600160a01b0381165f9081526008602052604090206002015484115b1561477c576001600160a01b039081165f9081526008602052604090205416614727565b5f6001600160a01b038216156147ae576001600160a01b038083165f90815260086020526040902060010154166147bb565b6009546001600160a01b03165b90505b6001600160a01b0381161580159061481b57506001600160a01b0381165f9081526008602052604090206002015485108061481b57508215801561481b57506001600160a01b0381165f9081526008602052604090206002015485145b15614845576001600160a01b038082165f90815260086020526040902060010154919250166147be565b604080516060810182526001600160a01b0380851680835284821660208085019182528486018b81528c85165f9081526008909252959020935184549084166001600160a01b031991821617855590516001850180549190941691161790915591516002909101556148d157600980546001600160a01b0319166001600160a01b038816179055614902565b6001600160a01b038281165f90815260086020526040902060010180546001600160a01b0319169188169190911790555b6001600160a01b03811661493057600a80546001600160a01b0319166001600160a01b03881617905561495e565b6001600160a01b038181165f90815260086020526040902080546001600160a01b0319169188169190911790555b6001600160a01b0386165f908152600760205260408120805460ff19166001908117909155600b80549192909161499690849061565b565b9091555050505050505050565b5f6149ad83613dcb565b90506001600160a01b03811615806149d65750816001600160a01b0316816001600160a01b0316145b83906134f95760405163e7743e3160e01b8152600401610e8a91815260200190565b5f83815260016020908152604080832080546001600160a01b0319166001600160a01b03871690811790915560028352928190208490555183815285917f55016b6cc60c3d15b7b1ebd0ab766c07b3082c98a5b4d1d7ff012a97652a4b1d91016124c7565b5f811580614a6b5750428210155b15614a7757505f611046565b5f614a82834261566e565b90505f805b600360ff82161015614ae8576001600160a01b0386165f90815260146020908152604080832060ff851684529091529020548015614adf57614ac882613ebb565b614ad29082615644565b614adc908461565b565b92505b50600101614a87565b50614af38282615644565b95945050505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316614b52578383151615614b46573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b610e9d6001600160a01b037f000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a1001682307f0000000000000000000000000000000000000000000000000000000005f5e100613f3b565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f51148316614c0f578383151615614c03573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f6001600160e01b03198216630d8a7c6d60e31b148061104657506001600160e01b0319821663ea0217cf60e01b1492915050565b5f816001600160a01b0316836001600160a01b03161480612bea5750506001600160a01b039182165f9081526020818152604080832093909416825291909152205460ff1690565b6040518061012001604052805f81526020015f6001600160a01b031681526020015f60ff1681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681525090565b803560ff81168114614d05575f5ffd5b919050565b5f60208284031215614d1a575f5ffd5b612bea82614cf5565b5f8151808452602084019350602083015f5b82811015614d53578151865260209586019590910190600101614d35565b5093949350505050565b602081525f612bea6020830184614d23565b80356001600160a01b0381168114614d05575f5ffd5b5f60208284031215614d95575f5ffd5b612bea82614d6f565b5f5f60408385031215614daf575f5ffd5b50508035926020909101359150565b5f5f60408385031215614dcf575f5ffd5b614dd883614d6f565b9150614de660208401614d6f565b90509250929050565b5f5f83601f840112614dff575f5ffd5b5081356001600160401b03811115614e15575f5ffd5b602083019150836020828501011115614e2c575f5ffd5b9250929050565b5f5f5f5f5f60808688031215614e47575f5ffd5b614e5086614d6f565b9450614e5e60208701614d6f565b93506040860135925060608601356001600160401b03811115614e7f575f5ffd5b614e8b88828901614def565b969995985093965092949392505050565b5f5f60208385031215614ead575f5ffd5b82356001600160401b03811115614ec2575f5ffd5b8301601f81018513614ed2575f5ffd5b80356001600160401b03811115614ee7575f5ffd5b8560208260051b8401011115614efb575f5ffd5b6020919091019590945092505050565b8051825260018060a01b03602082015116602083015260ff6040820151166040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100810151610f3e6101008401826001600160a01b03169052565b602080825282518282018190525f918401906040840190835b81811015614fbf57614fa8838551614f0b565b602093909301926101209290920191600101614f95565b509095945050505050565b5f60a08284031215611095575f5ffd5b8035600281900b8114614d05575f5ffd5b5f5f5f5f5f5f6101408789031215615001575f5ffd5b61500b8888614fca565b955061501960a08801614fda565b945061502760c08801614fda565b9598949750949560e0810135955061010081013594610120909101359350915050565b5f6020828403121561505a575f5ffd5b5035919050565b61012081016110468284614f0b565b5f5f5f5f60808587031215615083575f5ffd5b61508c85614d6f565b935060208501359250604085013591506150a860608601614d6f565b905092959194509250565b5f6101408284031280156150c5575f5ffd5b509092915050565b634e487b7160e01b5f52602160045260245ffd5b600481106150f1576150f16150cd565b9052565b6020810161104682846150e1565b5f5f60408385031215615114575f5ffd5b82359150614de660208401614d6f565b6020810160038310615138576151386150cd565b91905290565b602080825282518282018190525f918401906040840190835b81811015614fbf57835160ff8151168452602081015160208501526040810151604085015250606083019250602084019350600181019050615157565b5f8151808452602084019350602083015f5b82811015614d535781516001600160a01b03168652602095860195909101906001016151a6565b602081525f612bea6020830184615194565b815180516001600160a01b03908116835260208083015182168185015260408084015162ffffff169085015260608084015160020b908501526080928301519091169183019190915282015161010082019061524060a084018260020b9052565b50604083015161525560c084018260020b9052565b50606083015160e083015292915050565b5f5f60408385031215615277575f5ffd5b82359150614de660208401614cf5565b5f5f60208385031215615298575f5ffd5b82356001600160401b038111156152ad575f5ffd5b6152b985828601614def565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f612bea60208301846152c5565b5f5f5f60608486031215615317575f5ffd5b61532084614cf5565b92506020840135915061533560408501614d6f565b90509250925092565b803560038110614d05575f5ffd5b5f5f5f5f5f5f60c08789031215615361575f5ffd5b61536a8761533e565b955061537860208801614d6f565b945061538660408801614d6f565b9350606087013562ffffff8116811461539d575f5ffd5b9598949750929560808101359460a0909101359350915050565b5f5f5f5f5f5f60c087890312156153cc575f5ffd5b6153d58761533e565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f5f6040838503121561540e575f5ffd5b61541783614d6f565b9150614de660208401614cf5565b6020815260018060a01b03825116602082015260208201516040820152604082015160608201526060820151151560808201526080820151151560a08201525f60a083015160e060c084015261547f6101008401826152c5565b905060c0840151601f198483030160e0850152614af382826152c5565b80358015158114614d05575f5ffd5b5f5f604083850312156154bc575f5ffd5b82359150614de66020840161549c565b5f5f5f5f604085870312156154df575f5ffd5b84356001600160401b038111156154f4575f5ffd5b61550087828801614def565b90955093505060208501356001600160401b0381111561551e575f5ffd5b61552a87828801614def565b95989497509550505050565b5f5f5f5f5f60a0868803121561554a575f5ffd5b6155538661533e565b97602087013597506040870135966060810135965060800135945092505050565b604081525f6155866040830185615194565b8281036020840152614af38185614d23565b5f5f5f5f61010085870312156155ac575f5ffd5b6155b68686614fca565b93506155c460a0860161549c565b939693955050505060c08201359160e0013590565b5f5f5f5f608085870312156155ec575f5ffd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761104657611046615630565b8082018082111561104657611046615630565b8181038181111561104657611046615630565b82815260408101612bea60208301846150e1565b5f600182016156a6576156a6615630565b5060010190565b5f826156c757634e487b7160e01b5f52601260045260245ffd5b500490565b5f602082840312156156dc575f5ffd5b5051919050565b600181811c908216806156f757607f821691505b60208210810361109557634e487b7160e01b5f52602260045260245ffd5b5f5f85851115615723575f5ffd5b8386111561572f575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015610fe9576001600160e01b031960049490940360031b84901b1690921692915050565b601f821115610f3e57805f5260205f20601f840160051c810160208510156157975750805b601f840160051c820191505b818110156157b6575f81556001016157a3565b5050505050565b6001600160401b038311156157d4576157d4615608565b6157e8836157e283546156e3565b83615772565b5f601f841160018114615819575f85156158025750838201355b5f19600387901b1c1916600186901b1783556157b6565b5f83815260208120601f198716915b828110156158485786850135825560209485019460019092019101615828565b5086821015615864575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b606081525f6158b1606083018789615876565b82810360208401526158c4818688615876565b9150508260408301529695505050505050565b5f5f83546158e4816156e3565b6001821680156158fb57600181146159105761593d565b60ff198316865281151582028601935061593d565b865f5260205f205f5b8381101561593557815488820152600190910190602001615919565b505081860193505b509195945050505050565b838152826020820152606060408201525f614af3606083018461519456fece50d87c0d4882aef479475d47c796b2f0709c4d0c2dd3e8344d2344c41978bca2646970667358221220467a9ce83a56600acd89555e067944af2619f098ebc27e8600d87c46dd2e56bb64736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"optimizer":{"enabled":true,"runs":200},"remappings":["project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/","project/:@openzeppelin/contracts/=npm/@openzeppelin/contracts@5.6.1/"]},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0x100A2C7F45Fd48e217fdcE72e658dc78Fd43A100",{"internalType":"contract IERC20Metadata","name":"token_","type":"address"}],["1000000000000",{"internalType":"uint256","name":"dexSellCap_","type":"uint256"}],["0xFa9d2A61f80772bAAfdda87082FFcEa0232dF738",{"internalType":"address","name":"freezeHook_","type":"address"}],["0xc9E1b391835fd27385F0394BEe1A1CC86a46A325",{"internalType":"address","name":"freezerMarket_","type":"address"}],["0xcd5762AC6013fA762782ac1797Ab09152C1028e8",{"internalType":"address","name":"dexModule_","type":"address"}],[["0xdAC17F958D2ee523a2206206994597C13D831ec7","0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599","0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","0x1F98431c8aD98523631AE4a59f267346ea31F984","0xC36442b4a4522E871399CD717aBDD847Ab11FE88","0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45","0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865","0x46A15B0b27311cedF172AB29E4f4766fbE7F4364","0x13f4EA83D0bd40E75C8222255bc855a974568Dd4","0x000000000004444c5dc75cB358380D2e3dE08A90"],{"components":[{"internalType":"address","name":"usdt","type":"address"},{"internalType":"address","name":"usdc","type":"address"},{"internalType":"address","name":"wbtc","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"uniV3Factory","type":"address"},{"internalType":"address","name":"uniV3PositionManager","type":"address"},{"internalType":"address","name":"uniV3Router","type":"address"},{"internalType":"address","name":"pancakeV3Factory","type":"address"},{"internalType":"address","name":"pancakeV3PositionManager","type":"address"},{"internalType":"address","name":"pancakeV3Router","type":"address"},{"internalType":"address","name":"uniV4PoolManager","type":"address"}],"internalType":"struct DexBase.Config","name":"dex","type":"tuple"}]],"compiler_version":"0.8.28+commit.7893614a","is_verified_via_verifier_alliance":true,"verified_at":"2026-10-23T14:50:14.897783Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x610120604052600380556203f4806004556001600e55348015610020575f5ffd5b506040516160cd3803806160cd83398101604081905261003f916103cd565b81868683836001600160a01b0381163b61007d5760405163729c365d60e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b506001600160a01b0384811660809081526040805186841660248201526044810186905284518416606482015260208501518416608482015290840151831660a48201526060840151831660c482015290830151821660e482015260a0830151821661010482015260c0830151821661012482015260e08301518216610144820152610100830151821661016482015261012083015182166101848201526101408301519091166101a4820152610165906101c40160408051601f198184030181529190526020810180516001600160e01b03908116632d218f7560e21b1790915261030116565b505050506001600160a01b0386161580159061018957506001600160a01b03831615155b6101a65760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03841615806101c557506001600160a01b0384163b15155b84906101f05760405163129c437560e11b81526001600160a01b039091166004820152602401610074565b50826001600160a01b0381163b6102265760405163129c437560e11b81526001600160a01b039091166004820152602401610074565b506001600160a01b0380871660a081905285821660e052908416610100526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801561027d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102a19190610517565b6102ac90600a610637565b6102b7906064610645565b60c0819052604080515f815260208101929092527f4ff9d72c24885ff3b1c603541ef041427435d3c675afaa8fd20f8f5981426f2a910160405180910390a1505050505050610672565b5f5f6080516001600160a01b03168360405161031d919061065c565b5f60405180830381855af49150503d805f8114610355576040519150601f19603f3d011682016040523d82523d5f602084013e61035a565b606091505b50915091508161036c57805160208201fd5b505050565b6001600160a01b0381168114610385575f5ffd5b50565b805161039381610371565b919050565b60405161016081016001600160401b03811182821017156103c757634e487b7160e01b5f52604160045260245ffd5b60405290565b5f5f5f5f5f5f8688036102008112156103e4575f5ffd5b87516103ef81610371565b602089015160408a0151919850965061040781610371565b606089015190955061041881610371565b608089015190945061042981610371565b9250610160609f198201121561043d575f5ffd5b50610446610398565b61045260a08901610388565b815261046060c08901610388565b602082015261047160e08901610388565b60408201526104836101008901610388565b60608201526104956101208901610388565b60808201526104a76101408901610388565b60a08201526104b96101608901610388565b60c08201526104cb6101808901610388565b60e08201526104dd6101a08901610388565b6101008201526104f06101c08901610388565b6101208201526105036101e08901610388565b610140820152809150509295509295509295565b5f60208284031215610527575f5ffd5b815160ff81168114610537575f5ffd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b6001815b600184111561058d578085048111156105715761057161053e565b600184161561057f57908102905b60019390931c928002610556565b935093915050565b5f826105a357506001610631565b816105af57505f610631565b81600181146105c557600281146105cf576105eb565b6001915050610631565b60ff8411156105e0576105e061053e565b50506001821b610631565b5060208310610133831016604e8410600b841016171561060e575081810a610631565b61061a5f198484610552565b805f190482111561062d5761062d61053e565b0290505b92915050565b5f61053760ff841683610595565b80820281158282048414176106315761063161053e565b5f82518060208501845e5f920191825250919050565b60805160a05160c05160e051610100516159bc6107115f395f818161064f015281816112a80152818161151201528181612c2b01526136ef01525f8181610995015261408c01525f8181610bad0152614b8f01525f8181610d790152818161127d01528181611b1801528181611fbe0152818161211c01528181612f3a015281816144f30152614b6b01525f81816106d701526136b001526159bc5ff3fe608060405234801561000f575f5ffd5b50600436106104bc575f3560e01c806381bfd06711610279578063d147b74111610156578063ea0217cf116100ca578063f7de0ee71161008f578063f7de0ee714610cfe578063fb6f049f14610d11578063fbcbc0f114610d19578063fc0c546a14610d77578063fe0d94c114610d9d578063fed2e7a414610db0575f5ffd5b8063ea0217cf14610c87578063f44136a114610c9a578063f5faa4f114610cad578063f6aacfb114610cc0578063f794062e14610cd3575f5ffd5b8063dd4670641161011b578063dd46706414610c01578063de62d84214610c14578063e1ddbb1f14610c27578063e3034a8e14610c4e578063e5e7f38014610c61578063e985e9c514610c74575f5ffd5b8063d147b74114610b75578063d6d7e82c14610ba8578063d96a8bf114610bcf578063da35c66414610be2578063dbd42da514610beb575f5ffd5b8063a64e024a116101ed578063c3c5a547116101b2578063c3c5a54714610ad2578063c7f758a814610afd578063c9d27afe14610b1d578063cbe230c314610b30578063cccb19b814610b43578063d0a9645a14610b56575f5ffd5b8063a64e024a14610a5a578063aa34c12014610a64578063b3dc7e0c14610a77578063b7f3b59714610a85578063bc307cf914610a98575f5ffd5b806391dd73461161023e57806391dd7346146109fb57806391e916a414610a1b5780639201ea0a14610a2e578063950ad27a14610a365780639f35eb3414610a3e578063a437635214610a47575f5ffd5b806381bfd0671461099357806383914540146109b9578063879d9090146109c45780638ad87cec146109cc5780638dd1db53146109f3575f5ffd5b80633724fc1c116103a75780634a95d9d51161031b5780635bbe0837116102e05780635bbe08371461081b5780636198e339146109385780636c53e3681461094b5780636e748f971461095e5780637657a03c146109785780637dfe5b9214610980575f5ffd5b80634a95d9d5146107d75780634c55f4f8146107ec5780634cbde58f146108015780634e71d92d1461080a57806355b78daf14610812575f5ffd5b80633e09a4ee1161036c5780633e09a4ee146107165780633e4f49e61461072957806340e58ee51461074957806345ddc85d1461075c578063490055c0146107a157806349403183146107c4575f5ffd5b80633724fc1c146106ad57806337c909ec1461063057806337f31e40146106d55780633bf0c3f5146106fb5780633c7a05081461070e575f5ffd5b806316343da41161043e5780631e7f87bc116104035780631e7f87bc14610627578063215809ca14610630578063242cae9f1461063a5780632735803b1461064d578063328a1c9514610687578063353fa4991461069a575f5ffd5b806316343da41461059b578063165f150a146105a65780631aec3867146105c65780631bb11313146105f45780631bf6e00d14610614575f5ffd5b80630afb0409116104845780630afb0409146105205780630e798e61146105355780631338736f1461053d578063144e4fc314610550578063150b7a0214610563575f5ffd5b806302a251a3146104c057806302d102a4146104dc578063040eaff0146104fb578063083a258a1461051057806309e51ade14610518575b5f5ffd5b6104c960045481565b6040519081526020015b60405180910390f35b6104c96104ea366004614d0a565b60126020525f908152604090205481565b610503610ddb565b6040516104d39190614d5d565b6104c9601581565b6104c9600381565b61053361052e366004614d85565b610e48565b005b6104c9610ea0565b61053361054b366004614d9e565b610eaf565b61053361055e366004614dbe565b610ed4565b610582610571366004614e33565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016104d3565b6104c96312cc030081565b6105b96105b4366004614e9c565b610f43565b6040516104d39190614f7c565b6105d96105d4366004614feb565b610ff0565b604080519384526020840192909252908201526060016104d3565b61060761060236600461504a565b611035565b6040516104d39190615061565b6104c9610622366004614d85565b61104c565b6104c9600f5481565b6104c96201518081565b610533610648366004614d85565b61109b565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016104d3565b6104c9610695366004614e9c565b6110b0565b6104c96106a8366004615070565b6112a4565b6106c06106bb3660046150b3565b6114d2565b604080519283526020830191909152016104d3565b7f000000000000000000000000000000000000000000000000000000000000000061066f565b61053361070936600461504a565b61150f565b61053361167a565b61066f61072436600461504a565b611685565b61073c61073736600461504a565b61168f565b6040516104d391906150f5565b61053361075736600461504a565b6116a1565b61079461076a366004615103565b5f918252600d602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6040516104d39190615124565b6107b46107af366004614d85565b6117a1565b60405190151581526020016104d3565b6107b46107d236600461504a565b61184f565b6107df611861565b6040516104d3919061513e565b6107f4611916565b6040516104d391906151cd565b6104c9600e5481565b6105336119e1565b6104c960035481565b61092b61082936600461504a565b60408051610120810182525f6080820181815260a0830182905260c0830182905260e0830182905261010083018290528252602082018190529181018290526060810191909152505f9081527f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62d4602090815260409182902082516101208101845281546001600160a01b0390811660808301908152600184015480831660a0850152600160a01b810462ffffff1660c0850152600160b81b9004600290810b60e0850152808501549092166101008401528252600383015480820b94830194909452630100000090930490920b92820192909252600490910154606082015290565b6040516104d391906151df565b61053361094636600461504a565b611b8a565b61053361095936600461504a565b611bc1565b610966600381565b60405160ff90911681526020016104d3565b6104c9611ca6565b61053361098e366004615266565b611d33565b7f000000000000000000000000000000000000000000000000000000000000000061066f565b6104c96301e1338081565b6104c9611f9d565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c8546104c9565b610503612045565b610a0e610a09366004615287565b6120ae565b6040516104d391906152f3565b6104c9610a29366004615305565b6120b8565b6104c960ff81565b6104c9606481565b6104c960105481565b6104c9610a5536600461534c565b612164565b6104c962278d0081565b6104c9610a7236600461504a565b6121a5565b6105d96105d43660046153b7565b6104c9610a9336600461504a565b6121b8565b6104c9610aa63660046153fd565b6001600160a01b0382165f90815260146020908152604080832060ff8516845290915290205492915050565b6107b4610ae0366004614d85565b6001600160a01b03165f9081526006602052604090205460ff1690565b610b10610b0b36600461504a565b6121c2565b6040516104d39190615425565b610533610b2b3660046154ab565b61238e565b6107b4610b3e366004614d85565b6124d4565b6104c9610b513660046154cc565b612597565b6104c9610b64366004614d0a565b60116020525f908152604090205481565b610b88610b83366004615536565b6127b0565b6040805194855260208501939093529183015260608201526080016104d3565b6104c97f000000000000000000000000000000000000000000000000000000000000000081565b610503610bdd366004614d85565b6127f6565b6104c960055481565b610bf3612874565b6040516104d3929190615574565b610533610c0f36600461504a565b6129c5565b6104c9610c22366004614e9c565b6129d0565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c7546104c9565b6104c9610c5c36600461504a565b612b7f565b6104c9610c6f366004615598565b612bf1565b6107b4610c82366004614dbe565b612c28565b610533610c9536600461504a565b612c6a565b6104c9610ca8366004614d85565b612d4f565b6106c0610cbb3660046155d9565b612d59565b6107b4610cce36600461504a565b612d9a565b6107b4610ce1366004614d85565b6001600160a01b03165f9081526007602052604090205460ff1690565b610533610d0c366004614d9e565b612da4565b600b546104c9565b610d2c610d27366004614d85565b612fbf565b6040516104d391905f60c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b7f000000000000000000000000000000000000000000000000000000000000000061066f565b610533610dab36600461504a565b6130a2565b6104c9610dbe366004614d85565b6001600160a01b03165f9081526008602052604090206002015490565b604080516003808252608082019092526060916020820183803683370190505090505f5b600360ff82161015610e445760ff81165f818152601260205260409020548351909184918110610e3157610e3161561c565b6020908102919091010152600101610dff565b5090565b6001600160a01b0381165f90815260066020526040902054819060ff16610e935760405163bfc6c33760e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b50610e9d816131cf565b50565b610eac60156004615644565b81565b610eb9828261347c565b60405182905f5160206159675f395f51905f52905f90a25050565b336001600160a01b038316811480610efd5750816001600160a01b0316816001600160a01b0316145b83839091610f3157604051630ca03e9b60e11b81526001600160a01b03928316600482015291166024820152604401610e8a565b5050610f3e83835f6134ff565b505050565b6060816001600160401b03811115610f5d57610f5d615608565b604051908082528060200260200182016040528015610f9657816020015b610f83614c9d565b815260200190600190039081610f7b5790505b5090505f5b82811015610fe957610fc4848483818110610fb857610fb861561c565b905060200201356135c0565b828281518110610fd657610fd661561c565b6020908102919091010152600101610f9b565b5092915050565b5f8080333081146110205760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b506110296136ae565b96509650969350505050565b61103d614c9d565b611046826135c0565b92915050565b5f805b600360ff82161015611095576001600160a01b0383165f90815260146020908152604080832060ff8516845290915290205461108b908361565b565b915060010161104f565b50919050565b6110a4816136ed565b610e9d338260016134ff565b5f816001816110db57604051631905fe7960e21b815260048101929092526024820152604401610e8a565b50505f90505f6110e83390565b90506110f381613748565b5f5b8381101561124f575f8585838181106111105761111061561c565b9050602002013590505f611124848361379d565b905061112f82613839565b5f61113982613875565b9050828142811115611167576040516306f3183360e41b815260048101929092526024820152604401610e8a565b50508151611175908761565b565b82516001600160a01b0387165f9081526014602090815260408083208188015160ff1684529091528120805493995091926111b190849061566e565b9091555050815160408084015160ff165f908152601160205290812080549091906111dd90849061566e565b909155506111ed90508584613892565b6040828101518351825160ff909216825260208201525f8183015290516001600160a01b0387169185917f594761400b83cf4c3878ee37d05e98add500ea3b6716a89da223580c847680b09181900360600190a35050508060010190506110f5565b5081600f5f828254611261919061566e565b909155506112709050816131cf565b610fe96001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168284613984565b5f337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146112ee57604051633c37181960e01b815260040160405180910390fd5b6001600160a01b0382161580159061130f57506001600160a01b0382163014155b801561132d5750846001600160a01b0316826001600160a01b031614155b829061135857604051639cfea58360e01b81526001600160a01b039091166004820152602401610e8a565b50825f0361137957604051631f2a200560e01b815260040160405180910390fd5b5f611384868661379d565b8051909150859085818111156113be5760405163fec7c07160e01b8152600481019390935260248301919091526044820152606401610e8a565b5050505f6113cb86611685565b90506001600160a01b03811615806113f45750866001600160a01b0316816001600160a01b0316145b866113fe886121a5565b90916114265760405163a582711f60e01b815260048101929092526024820152604401610e8a565b5050611438876114333390565b6139b9565b61144184613a00565b61144d86838787613a50565b9250866001600160a01b031683877f0c8571631232fd02cd7c4977095e95bbfafa3699ba05adec8d5cb6322e5012c18786604001518a88606001516114918e6121a5565b604080516001600160a01b03909616865260ff9094166020860152928401919091526060830152608082015260a00160405180910390a45050949350505050565b5f80333081146115015760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5061150a6136ae565b915091565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461155857604051633c37181960e01b815260040160405180910390fd5b5f61156282611685565b9050816001600160a01b03821661158f576040516310919eab60e21b8152600401610e8a91815260200190565b5061159a81336139b9565b5f6115a483613bfa565b905080602001516001600160a01b0316826001600160a01b0316141582906115eb57604051639cfea58360e01b81526001600160a01b039091166004820152602401610e8a565b506115f582613a00565b6116048382835f015185613a50565b5061160e83613cac565b816001600160a01b031681602001516001600160a01b0316847fd186a9f6f913a9fbe33f3f86812678e0d9d23aa5d38669bf220157e476cb4bbd8460400151855f015160405161166d92919060ff929092168252602082015260400190565b60405180910390a4505050565b61168333613d1c565b565b5f61104682613dcb565b5f61104661169c83613dfc565b613e36565b335f6116ac83613dfc565b8054909150839083906001600160a01b0390811690821681146116fc576040516364a13eed60e01b815260048101939093526001600160a01b039182166024840152166044820152606401610e8a565b5050505f61170982613e36565b90505f81600381111561171e5761171e6150cd565b148061173b57506003816003811115611739576117396150cd565b145b8482909161175e57604051631494273360e21b8152600401610e8a929190615681565b505060038201805461ff00191661010017905560405184907f416e669c63d9a3a5e36ee7cc7e2104b8db28ccd286aa18966e98fa230c73b08c905f90a250505050565b6001600160a01b0381165f9081526007602052604081205460ff166117c757505f919050565b6009546001600160a01b03165f5b600354811080156117ee57506001600160a01b03821615155b1561184657836001600160a01b0316826001600160a01b031603611816575060019392505050565b6001600160a01b039182165f908152600860205260409020600101549091169061183f81615695565b90506117d5565b505f9392505050565b5f61104661185c836121b8565b613e7b565b60408051600380825260808201909252606091816020015b61189d60405180606001604052805f60ff1681526020015f81526020015f81525090565b8152602001906001900390816118795790505090505f5b600360ff82161015610e445760405180606001604052808260ff1681526020016118dd83613e92565b81526020016118eb83613ebb565b815250828260ff16815181106119035761190361561c565b60209081029190910101526001016118b4565b60605f600b546003541061192c57600b54611930565b6003545b9050806001600160401b0381111561194a5761194a615608565b604051908082528060200260200182016040528015611973578160200160208202803683370190505b506009549092506001600160a01b03165f5b828110156119db57818482815181106119a0576119a061561c565b6001600160a01b039283166020918202929092018101919091529281165f908152600890935260409092206001908101549092169101611985565b50505090565b335f81815260136020526040812060020154611a0190620151809061565b565b9050818142811115611a375760405163967c4a1d60e01b81526001600160a01b0390921660048301526024820152604401610e8a565b5050611a4282613eca565b8290611a6d576040516332559a3360e11b81526001600160a01b039091166004820152602401610e8a565b50611a7782613748565b6001600160a01b0382165f9081526013602052604081208054909190611aa2906312cc0300906156ad565b90505f611aad611f9d565b90505f818310611abd5781611abf565b825b9050805f03611ae157604051632aad581f60e01b815260040160405180910390fd5b611aef6312cc030082615644565b845f015f828254611b00919061566e565b9091555050426002850155611b3f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168783613984565b856001600160a01b03167fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a82604051611b7a91815260200190565b60405180910390a2505050505050565b5f611b9482612d9a565b9050611b9f82613f0d565b8015611bbd5760405182905f5160206159675f395f51905f52905f90a25b5050565b33308114611bee5760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5060038110158015611c01575060158111155b8160036015909192611c37576040516348ca9d6d60e01b8152600481019390935260248301919091526044820152606401610e8a565b5050600354905081808203611c6257604051630455bbeb60e01b8152600401610e8a91815260200190565b50600382905560408051828152602081018490527f6202000939fed2067e5095bb4fed84b9f3c8471e45071e06840a83a154b1924c91015b60405180910390a15050565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c8547f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c7545f917f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c69111611d19575f611d2d565b80600201548160010154611d2d919061566e565b91505090565b80600360ff821610611d5e57604051635e50d4ab60e11b815260ff9091166004820152602401610e8a565b50335f611d6b828561379d565b604081015190915084908460ff80831690821611611db057604051632e9a46f560e01b8152600481019390935260ff9182166024840152166044820152606401610e8a565b505050611dbc84613839565b611dc582613748565b80516001600160a01b0383165f9081526014602090815260408083208186015160ff16845290915281208054909190611dff90849061566e565b909155505080516001600160a01b0383165f90815260146020908152604080832060ff8816845290915281208054909190611e3b90849061565b565b9091555050805160408083015160ff165f90815260116020529081208054909190611e6790849061566e565b9091555050805160ff84165f9081526011602052604081208054909190611e8f90849061565b565b909155505060408082015160ff165f9081526012602052908120805460019290611eba90849061566e565b909155505060ff83165f908152601260205260408120805460019290611ee190849061565b565b90915550505f84815260156020526040902060018101805460ff60a01b1916600160a01b60ff8716021790554260028201819055600390910155611f24826131cf565b6040818101518251825160ff928316815291861660208301528183015242606082015290516001600160a01b0384169186917f59605b01384e51f98f39b719b389a370c2b776755d561f35a0e64d35b0766e9c9181900360800190a360405184905f5160206159675f395f51905f52905f90a250505050565b6040516370a0823160e01b81523060048201525f9081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612003573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061202791906156cc565b9050600f548111612038575f611d2d565b600f54611d2d908261566e565b604080516003808252608082019092526060916020820183803683370190505090505f5b600360ff82161015610e445760ff81165f81815260116020526040902054835190918491811061209b5761209b61561c565b6020908102919091010152600101612069565b60606110466136ae565b5f83600360ff8216106120e457604051635e50d4ab60e11b815260ff9091166004820152602401610e8a565b50825f0361210557604051631f2a200560e01b815260040160405180910390fd5b3361210f81613a00565b6121446001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823087613f3b565b61214f818686613f71565b915061215c81848661408a565b509392505050565b5f333081146121925760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5061219b6136ae565b9695505050505050565b5f81815260026020526040812054611046565b5f610fe982614140565b61220a6040518060e001604052805f6001600160a01b031681526020015f81526020015f81526020015f151581526020015f1515815260200160608152602001606081525090565b61221382613dfc565b6040805160e08101825282546001600160a01b0316815260018301546020820152600283015491810191909152600382015460ff80821615156060840152610100909104161515608082015260048201805491929160a084019190612277906156e3565b80601f01602080910402602001604051908101604052809291908181526020018280546122a3906156e3565b80156122ee5780601f106122c5576101008083540402835291602001916122ee565b820191905f5260205f20905b8154815290600101906020018083116122d157829003601f168201915b50505050508152602001600582018054612307906156e3565b80601f0160208091040260200160405190810160405280929190818152602001828054612333906156e3565b801561237e5780601f106123555761010080835404028352916020019161237e565b820191905f5260205f20905b81548152906001019060200180831161236157829003601f168201915b5050505050815250509050919050565b3361239883614264565b506123a2816117a1565b81906123cd5760405163dbed96b160e01b81526001600160a01b039091166004820152602401610e8a565b505f838152600d602090815260408083206001600160a01b038516845290915281205460ff166002811115612404576124046150cd565b1483829091612438576040516304f9da6360e01b815260048101929092526001600160a01b03166024820152604401610e8a565b505081612446576002612449565b60015b5f848152600d602090815260408083206001600160a01b03861684529091529020805460ff19166001836002811115612484576124846150cd565b0217905550806001600160a01b0316837ff2913dbe661ee2acc4a046d8fbcdc792373bda34c41c6086484b5345e5785e5f846040516124c7911515815260200190565b60405180910390a3505050565b7f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c680545f91907f61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c9906001600160a01b0385811691161480612541575080546001600160a01b038581169116145b8061255b575060018101546001600160a01b038581169116145b80612575575060028101546001600160a01b038581169116145b8061258f575060038101546001600160a01b038581169116145b949350505050565b5f336125a2816117a1565b81906125cd5760405163dbed96b160e01b81526001600160a01b039091166004820152602401610e8a565b5060048510156125f057604051638129bbcd60e01b815260040160405180910390fd5b8260ff8082111561261d576040516371a24cf360e01b815260048101929092526024820152604401610e8a565b505f905061262e600482888a615715565b6126379161573c565b9050612642816142bb565b819061266e5760405163f556f5dd60e01b81526001600160e01b03199091166004820152602401610e8a565b5060055f815461267d90615695565b91829055505f818152600c6020526040902080546001600160a01b0319166001600160a01b038516178155426001820181905560045492955090916126c19161565b565b6002820155600481016126d5888a836157bd565b50600581016126e58688836157bd565b505f848152600d602090815260408083206001600160a01b038716808552925291829020805460ff19166001179055600283015491516001600160e01b031985169287917fee300f98871a66204e294dd5d599a0dfd9098b69082f5efd229eff1e90c14d329161275c918e918e918e918e9161589e565b60405180910390a4604051600181526001600160a01b0384169085907ff2913dbe661ee2acc4a046d8fbcdc792373bda34c41c6086484b5345e5785e5f9060200160405180910390a3505050949350505050565b5f808080333081146127e15760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b506127ea6136ae565b95509550955095915050565b604080516003808252608082019092526060916020820183803683370190505090505f5b600360ff82161015611095576001600160a01b0383165f90815260146020908152604080832060ff851680855292529091205483519091849181106128615761286161561c565b602090810291909101015260010161281a565b606080600b546001600160401b0381111561289157612891615608565b6040519080825280602002602001820160405280156128ba578160200160208202803683370190505b509150600b546001600160401b038111156128d7576128d7615608565b604051908082528060200260200182016040528015612900578160200160208202803683370190505b506009549091506001600160a01b03165f5b600b548110156129bf578184828151811061292f5761292f61561c565b60200260200101906001600160a01b031690816001600160a01b03168152505060085f836001600160a01b03166001600160a01b031681526020019081526020015f20600201548382815181106129885761298861561c565b6020908102919091018101919091526001600160a01b039283165f9081526008909152604090206001908101549092169101612912565b50509091565b610e9d815f19610eaf565b5f816002808210156129fe57604051631905fe7960e21b815260048101929092526024820152604401610e8a565b50505f612a083390565b9050612a1381613748565b5f612a368286865f818110612a2a57612a2a61561c565b9050602002013561379d565b6040015190505f80805b86811015612af5575f888883818110612a5b57612a5b61561c565b9050602002013590505f612a6f878361379d565b9050612a7a82613839565b604081015182908760ff82811690821614612abc5760405163471aa4c360e11b8152600481019390935260ff9182166024840152166044820152606401610e8a565b50508151612acb91508661565b565b94508381606001511115612ae157806060015193505b612aeb8783613892565b5050600101612a40565b50612b038484848442614381565b94505f5b86811015612b7457846001600160a01b031686898984818110612b2c57612b2c61561c565b60405160ff8a16815260209182029390930135927f4c6d50c854fc7fbedd38ca40809a9025c521eaf63b901edbb714c3afdef5536592500160405180910390a4600101612b07565b505050505092915050565b5f818152601560209081526040808320815160a0810183528154815260018201546001600160a01b038116948201859052600160a01b900460ff1692810192909252600281015460608301526003015460808201529015612be857612be381613875565b612bea565b5f5b9392505050565b5f33308114612c1f5760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b5061258f6136ae565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116908316148015612bea5750612bea83836144bc565b33308114612c975760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b50620151808110158015612cae575062278d008111155b816201518062278d00909192612ce8576040516319bd218160e11b8152600481019390935260248301919091526044820152606401610e8a565b5050600454905081808203612d1357604051630455bbeb60e01b8152600401610e8a91815260200190565b50600482905560408051828152602081018490527f0157f874643e34dea2d71607bde6378f09880b59546f9e2386608eb7154b89759101611c9a565b5f61104682613eca565b5f8033308114612d885760405163d0e8d40360e01b81526001600160a01b039091166004820152602401610e8a565b50612d916136ae565b94509492505050565b5f611046826144c7565b805f03612dc457604051631f2a200560e01b815260040160405180910390fd5b335f612dd0828561379d565b9050612ddb84613839565b805184908481811115612e125760405163fec7c07160e01b8152600481019390935260248301919091526044820152606401610e8a565b5050505f612e1f82613875565b9050848142811115612e4d576040516306f3183360e41b815260048101929092526024820152604401610e8a565b5050612e5883613748565b81515f90612e6790869061566e565b9050805f03612e7f57612e7a8487613892565b612ea4565b5f868152601560205260408082208390555187915f5160206159675f395f51905f5291a25b6001600160a01b0384165f9081526014602090815260408083208682015160ff16845290915281208054879290612edc90849061566e565b9250508190555084600f5f828254612ef4919061566e565b909155505060408084015160ff165f90815260116020529081208054879290612f1e90849061566e565b90915550612f2d9050846131cf565b612f616001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168587613984565b604080840151815160ff9091168152602081018790529081018290526001600160a01b0385169087907f594761400b83cf4c3878ee37d05e98add500ea3b6716a89da223580c847680b09060600160405180910390a3505050505050565b612ff26040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f60135f846001600160a01b03166001600160a01b031681526020019081526020015f206040518060a00160405290815f820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506040518060c00160405280825f01518152602001826020015181526020018260400151815260200182606001518152602001826080015181526020016130998561104c565b90529392505050565b5f6130ac82614264565b6003549091505f806130bd85614140565b915091506130ca82613e7b565b8583859091926130fe576040516374efa1a960e11b8152600481019390935260248301919091526044820152606401610e8a565b50505060038401805460ff191660011790556040515f90819030906131279060048901906158d7565b5f604051808303815f865af19150503d805f8114613160576040519150601f19603f3d011682016040523d82523d5f602084013e613165565b606091505b50915091508161317757805160208201fd5b613180876144dc565b336001600160a01b0316877f3bbf47743a2af00b3c2d0ca51ddeef4c3b44599cffefeb12a52782068f436e518688876040516131be93929190615948565b60405180910390a350505050505050565b6001600160a01b0381165f9081526006602052604090205460ff166131f15750565b5f6131fb82614596565b6001600160a01b0383165f9081526007602052604090205490915060ff1661330357805f03613228575050565b61323460156004615644565b600b54036132a257600a546001600160a01b03165f81815260086020526040902060020154821161326457505050565b61326d816145a0565b6040516001600160a01b038216907fac3da8e81cf2b8696731b597ee3f55915425b9bcd10e3852612b20deb4a99fde905f90a2505b600a546132bc90839083906001600160a01b03165f614725565b816001600160a01b03167fc9fc9ea705f0caebf021a6bb6c51a7d6fc3e360ae32094274f64de0132f2ff16826040516132f791815260200190565b60405180910390a25050565b805f0361334a57613313826145a0565b6040516001600160a01b038316907fac3da8e81cf2b8696731b597ee3f55915425b9bcd10e3852612b20deb4a99fde905f90a25050565b6001600160a01b0382165f90815260086020526040902060028101548083036133735750505050565b815460018301546001600160a01b039182169116828511801561339e57506001600160a01b03821615155b80156133c357506001600160a01b0382165f9081526008602052604090206002015485115b156133e2576133d1866145a0565b6133dd8686845f614725565b613441565b82851080156133f957506001600160a01b03811615155b801561341e57506001600160a01b0381165f9081526008602052604090206002015485105b156134395761342c866145a0565b6133dd8686836001614725565b600284018590555b856001600160a01b03167fc9fc9ea705f0caebf021a6bb6c51a7d6fc3e360ae32094274f64de0132f2ff1686604051611b7a91815260200190565b5f8281526015602052604090206001015433906001600160a01b031683816134b95760405162d2a3f760e21b8152600401610e8a91815260200190565b504283116134da5760405163ca72d5c760e01b815260040160405180910390fd5b6134e481836139b9565b6134ee84826149a3565b6134f98482856149f8565b50505050565b6001600160a01b038381165f90815260208181526040808320938616835292905220805460ff1916821580159190911790915561357b57816001600160a01b0316836001600160a01b03167f92b270b94fd320d925800c308edf63e09be8dc4b4b10cc01ab08277a43d63e2760405160405180910390a3505050565b816001600160a01b0316836001600160a01b03167f480aa4a4a49d94f1351f899ef81d4ce57a62fa1c4c370779f4b22b60e6b0487e60405160405180910390a3505050565b6135c8614c9d565b5f82815260156020908152604091829020825160a0810184528154815260018201546001600160a01b038116938201849052600160a01b900460ff1693810193909352600281015460608401526003015460808301526136285750919050565b60405180610120016040528084815260200182602001516001600160a01b03168152602001826040015160ff168152602001825f01518152602001826060015181526020018260800151815260200161368083613875565b815260200161368e856121a5565b815260200161369c85611685565b6001600160a01b031690529392505050565b7f0000000000000000000000000000000000000000000000000000000000000000365f80375f5f365f845af43d5f5f3e8080156136e9573d5ff35b3d5ffd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116908216148190611bbd57604051632d06956360e11b81526001600160a01b039091166004820152602401610e8a565b6001600160a01b0381165f9081526013602052604081206001810154909190613772908490614a5d565b905080156137925780825f015f82825461378c919061565b565b90915550505b504260019091015550565b6137d66040518060a001604052805f81526020015f6001600160a01b031681526020015f60ff1681526020015f81526020015f81525090565b6137df82613bfa565b60208101519091508290846001600160a01b0382811690821614613830576040516326603ebf60e21b815260048101939093526001600160a01b039182166024840152166044820152606401610e8a565b50505092915050565b61384281612d9a565b158161384d836121a5565b9091610f3e5760405163a582711f60e01b815260048101929092526024820152604401610e8a565b5f6138838260400151613e92565b8260600151611046919061565b565b5f818152601560209081526040808320600180820180548684556001600160a81b031981169091556002830186905560039092018590556001600160a01b038716855260139093529083206004018054600160a01b90920460ff169390916138fb90849061566e565b92505081905550600160105f828254613914919061566e565b909155505060ff81165f90815260126020526040812080546001929061393b90849061566e565b9091555061394a905082613cac565b6040516001600160a01b0384169083907f34c4f6ef00ced14f223f904220331f3ca4bb5b0fcef114040e28e874afaa2ea6905f90a3505050565b6139918383836001614afc565b610f3e57604051635274afe760e01b81526001600160a01b0384166004820152602401610e8a565b6139c2816136ed565b6139cc8282612c28565b828290916134f957604051630ca03e9b60e11b81526001600160a01b03928316600482015291166024820152604401610e8a565b6001600160a01b0381165f9081526013602052604090206004015481906064908111610f3e5760405163031086ef60e01b81526001600160a01b0390921660048301526024820152604401610e8a565b60208301515f90613a6090613748565b613a6982613748565b6020808501516001600160a01b03165f9081526014825260408082208188015160ff1683529092529081208054859290613aa490849061566e565b90915550506001600160a01b0382165f9081526014602090815260408083208782015160ff16845290915281208054859290613ae190849061565b565b90915550506020840151613af4906131cf565b613afd826131cf565b5f858152601560209081526040808320600180820180546001600160a01b0319166001600160a01b03898116919091179091554260039093019290925588840151909116845260139092528220600401805491929091613b5e90849061566e565b90915550506001600160a01b0382165f908152601360205260408120600401805460019290613b8e90849061565b565b909155505083518314613bdb575f85815260156020908152604091829020859055850151908501518551613bd8929190613bc990879061566e565b87606001518860800151614381565b90505b60405185905f5160206159675f395f51905f52905f90a2949350505050565b613c336040518060a001604052805f81526020015f6001600160a01b031681526020015f60ff1681526020015f81526020015f81525090565b505f81815260156020908152604091829020825160a0810184528154815260018201546001600160a01b038116938201849052600160a01b900460ff1693810193909352600281015460608401526003015460808301528290611095576040516333365b9b60e11b8152600401610e8a91815260200190565b5f818152600160205260409020546001600160a01b0316613cca5750565b5f81815260016020908152604080832080546001600160a01b031916905560029091528082208290555182917ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184291a250565b6001600160a01b0381165f90815260066020526040902054819060ff1615613d63576040516345ed80e960e01b81526001600160a01b039091166004820152602401610e8a565b506001600160a01b0381165f908152600660205260409020805460ff19166001179055613d8f81614b5e565b6040516001600160a01b038216907f2d3734a8e47ac8316e500ac231c90a6e1848ca2285f40d07eaa52005e4b3a0e9905f90a2610e9d816131cf565b5f613dd5826144c7565b15613df557505f908152600160205260409020546001600160a01b031690565b505f919050565b5f818152600c60205260409020805482906001600160a01b031661109557604051630853c2a360e41b8152600401610e8a91815260200190565b60038101545f9060ff1615613e4d57506001919050565b6003820154610100900460ff1615613e6757506002919050565b8160020154421115613df557506003919050565b6003545f90613e8b836002615644565b1192915050565b5f6301e13380613ea660ff84166002615644565b613eb190600161565b565b6110469190615644565b5f61104660ff8316600161565b565b6001600160a01b0381165f90815260136020526040812060018101546312cc030090613ef7908590614a5d565b8254613f03919061565b565b612bea91906156ad565b5f613f1782613dcb565b90506001600160a01b03811615613f3257613f3281336139b9565b611bbd82613cac565b613f49848484846001614bb3565b6134f957604051635274afe760e01b81526001600160a01b0385166004820152602401610e8a565b5f613f7b84613748565b6001600160a01b0384165f9081526013602052604081206003810154909103613fa5574260038201555b613fb28585854242614381565b6001600160a01b0386165f90815260146020908152604080832060ff89168452909152812080549294508592909190613fec90849061565b565b9250508190555082600f5f828254614004919061565b565b909155505060ff84165f908152601160205260408120805485929061402a90849061565b565b909155506140399050856131cf565b6040805160ff86168152602081018590526001600160a01b0387169184917f01415f65daddd59a2671475ab000aafd1dedb0b607767279efd74e10fe535521910160405180910390a3509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116156134f9576001600160a01b038481165f8181526013602052604090819020600301549051639f31216560e01b81526004810192909252858316602483015260448201859052606482015290821690639f312165906084015f604051808303815f87803b158015614124575f5ffd5b505af1158015614136573d5f5f3e3d5ffd5b5050505050505050565b6003545f906060906001600160401b0381111561415f5761415f615608565b604051908082528060200260200182016040528015614188578160200160208202803683370190505b506009549091505f906001600160a01b03165b600354821080156141b457506001600160a01b03811615155b1561425a57808383815181106141cc576141cc61561c565b6001600160a01b039092166020928302919091019091015260015f868152600d602090815260408083206001600160a01b038616845290915290205460ff16600281111561421c5761421c6150cd565b0361422d5761422a84615695565b93505b6001600160a01b039081165f908152600860205260409020600101541661425382615695565b915061419b565b8183525050915091565b5f61426e82613dfc565b90505f61427a82613e36565b90505f81600381111561428f5761428f6150cd565b14838290916142b357604051631494273360e21b8152600401610e8a929190615681565b505050919050565b5f6001600160e01b03198216630dc93f0760e21b14806142eb57506001600160e01b03198216632cf71f8360e21b145b8061430657506001600160e01b0319821663d147b74160e01b145b8061432157506001600160e01b0319821663521bb1a960e11b145b8061433c57506001600160e01b03198216631aec386760e01b145b8061435757506001600160e01b0319821663f5faa4f160e01b145b8061437257506001600160e01b031982166301cbcfe760e71b145b80611046575061104682614c20565b600e80545f918261439183615695565b909155506040805160a0810182528681526001600160a01b03808a16602080840182815260ff808d16868801908152606087018c8152608088018c81525f8b8152601587528a812099518a5594516001808b0180549551909616600160a01b026001600160a81b03199095169190991617929092179092559051600287015551600390950194909455908352601390529181206004018054939450919261443990849061565b565b92505081905550600160105f828254614452919061565b565b909155505060ff85165f90815260126020526040812080546001929061447990849061565b565b90915550506040516001600160a01b0387169082907fa22c02fc603732177d8ac2aa6242d6a44b293fb36ed8ec905065f8b5e2c03bf8905f90a395945050505050565b5f612bea8383614c55565b5f818152600260205260408120544290613e8b565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015614540573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061456491906156cc565b600f549091508190808210156134f957604051635295bde160e01b815260048101929092526024820152604401610e8a565b5f6110468261104c565b6001600160a01b038082165f90815260086020908152604091829020825160608101845281548516808252600183015490951692810192909252600201549181019190915290614613576020810151600980546001600160a01b0319166001600160a01b0390921691909117905561464e565b60208181015182516001600160a01b039081165f9081526008909352604090922060010180546001600160a01b031916929091169190911790555b60208101516001600160a01b0316614686578051600a80546001600160a01b0319166001600160a01b039092169190911790556146bb565b80516020808301516001600160a01b039081165f9081526008909252604090912080546001600160a01b031916919092161790555b6001600160a01b0382165f90815260086020908152604080832080546001600160a01b0319908116825560018083018054909216909155600290910184905560079092528220805460ff19169055600b80549192909161471c90849061566e565b90915550505050565b815b6001600160a01b0381161580159061475857506001600160a01b0381165f9081526008602052604090206002015484115b1561477c576001600160a01b039081165f9081526008602052604090205416614727565b5f6001600160a01b038216156147ae576001600160a01b038083165f90815260086020526040902060010154166147bb565b6009546001600160a01b03165b90505b6001600160a01b0381161580159061481b57506001600160a01b0381165f9081526008602052604090206002015485108061481b57508215801561481b57506001600160a01b0381165f9081526008602052604090206002015485145b15614845576001600160a01b038082165f90815260086020526040902060010154919250166147be565b604080516060810182526001600160a01b0380851680835284821660208085019182528486018b81528c85165f9081526008909252959020935184549084166001600160a01b031991821617855590516001850180549190941691161790915591516002909101556148d157600980546001600160a01b0319166001600160a01b038816179055614902565b6001600160a01b038281165f90815260086020526040902060010180546001600160a01b0319169188169190911790555b6001600160a01b03811661493057600a80546001600160a01b0319166001600160a01b03881617905561495e565b6001600160a01b038181165f90815260086020526040902080546001600160a01b0319169188169190911790555b6001600160a01b0386165f908152600760205260408120805460ff19166001908117909155600b80549192909161499690849061565b565b9091555050505050505050565b5f6149ad83613dcb565b90506001600160a01b03811615806149d65750816001600160a01b0316816001600160a01b0316145b83906134f95760405163e7743e3160e01b8152600401610e8a91815260200190565b5f83815260016020908152604080832080546001600160a01b0319166001600160a01b03871690811790915560028352928190208490555183815285917f55016b6cc60c3d15b7b1ebd0ab766c07b3082c98a5b4d1d7ff012a97652a4b1d91016124c7565b5f811580614a6b5750428210155b15614a7757505f611046565b5f614a82834261566e565b90505f805b600360ff82161015614ae8576001600160a01b0386165f90815260146020908152604080832060ff851684529091529020548015614adf57614ac882613ebb565b614ad29082615644565b614adc908461565b565b92505b50600101614a87565b50614af38282615644565b95945050505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316614b52578383151615614b46573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b610e9d6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682307f0000000000000000000000000000000000000000000000000000000000000000613f3b565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f51148316614c0f578383151615614c03573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f6001600160e01b03198216630d8a7c6d60e31b148061104657506001600160e01b0319821663ea0217cf60e01b1492915050565b5f816001600160a01b0316836001600160a01b03161480612bea5750506001600160a01b039182165f9081526020818152604080832093909416825291909152205460ff1690565b6040518061012001604052805f81526020015f6001600160a01b031681526020015f60ff1681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681525090565b803560ff81168114614d05575f5ffd5b919050565b5f60208284031215614d1a575f5ffd5b612bea82614cf5565b5f8151808452602084019350602083015f5b82811015614d53578151865260209586019590910190600101614d35565b5093949350505050565b602081525f612bea6020830184614d23565b80356001600160a01b0381168114614d05575f5ffd5b5f60208284031215614d95575f5ffd5b612bea82614d6f565b5f5f60408385031215614daf575f5ffd5b50508035926020909101359150565b5f5f60408385031215614dcf575f5ffd5b614dd883614d6f565b9150614de660208401614d6f565b90509250929050565b5f5f83601f840112614dff575f5ffd5b5081356001600160401b03811115614e15575f5ffd5b602083019150836020828501011115614e2c575f5ffd5b9250929050565b5f5f5f5f5f60808688031215614e47575f5ffd5b614e5086614d6f565b9450614e5e60208701614d6f565b93506040860135925060608601356001600160401b03811115614e7f575f5ffd5b614e8b88828901614def565b969995985093965092949392505050565b5f5f60208385031215614ead575f5ffd5b82356001600160401b03811115614ec2575f5ffd5b8301601f81018513614ed2575f5ffd5b80356001600160401b03811115614ee7575f5ffd5b8560208260051b8401011115614efb575f5ffd5b6020919091019590945092505050565b8051825260018060a01b03602082015116602083015260ff6040820151166040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100810151610f3e6101008401826001600160a01b03169052565b602080825282518282018190525f918401906040840190835b81811015614fbf57614fa8838551614f0b565b602093909301926101209290920191600101614f95565b509095945050505050565b5f60a08284031215611095575f5ffd5b8035600281900b8114614d05575f5ffd5b5f5f5f5f5f5f6101408789031215615001575f5ffd5b61500b8888614fca565b955061501960a08801614fda565b945061502760c08801614fda565b9598949750949560e0810135955061010081013594610120909101359350915050565b5f6020828403121561505a575f5ffd5b5035919050565b61012081016110468284614f0b565b5f5f5f5f60808587031215615083575f5ffd5b61508c85614d6f565b935060208501359250604085013591506150a860608601614d6f565b905092959194509250565b5f6101408284031280156150c5575f5ffd5b509092915050565b634e487b7160e01b5f52602160045260245ffd5b600481106150f1576150f16150cd565b9052565b6020810161104682846150e1565b5f5f60408385031215615114575f5ffd5b82359150614de660208401614d6f565b6020810160038310615138576151386150cd565b91905290565b602080825282518282018190525f918401906040840190835b81811015614fbf57835160ff8151168452602081015160208501526040810151604085015250606083019250602084019350600181019050615157565b5f8151808452602084019350602083015f5b82811015614d535781516001600160a01b03168652602095860195909101906001016151a6565b602081525f612bea6020830184615194565b815180516001600160a01b03908116835260208083015182168185015260408084015162ffffff169085015260608084015160020b908501526080928301519091169183019190915282015161010082019061524060a084018260020b9052565b50604083015161525560c084018260020b9052565b50606083015160e083015292915050565b5f5f60408385031215615277575f5ffd5b82359150614de660208401614cf5565b5f5f60208385031215615298575f5ffd5b82356001600160401b038111156152ad575f5ffd5b6152b985828601614def565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f612bea60208301846152c5565b5f5f5f60608486031215615317575f5ffd5b61532084614cf5565b92506020840135915061533560408501614d6f565b90509250925092565b803560038110614d05575f5ffd5b5f5f5f5f5f5f60c08789031215615361575f5ffd5b61536a8761533e565b955061537860208801614d6f565b945061538660408801614d6f565b9350606087013562ffffff8116811461539d575f5ffd5b9598949750929560808101359460a0909101359350915050565b5f5f5f5f5f5f60c087890312156153cc575f5ffd5b6153d58761533e565b9860208801359850604088013597606081013597506080810135965060a00135945092505050565b5f5f6040838503121561540e575f5ffd5b61541783614d6f565b9150614de660208401614cf5565b6020815260018060a01b03825116602082015260208201516040820152604082015160608201526060820151151560808201526080820151151560a08201525f60a083015160e060c084015261547f6101008401826152c5565b905060c0840151601f198483030160e0850152614af382826152c5565b80358015158114614d05575f5ffd5b5f5f604083850312156154bc575f5ffd5b82359150614de66020840161549c565b5f5f5f5f604085870312156154df575f5ffd5b84356001600160401b038111156154f4575f5ffd5b61550087828801614def565b90955093505060208501356001600160401b0381111561551e575f5ffd5b61552a87828801614def565b95989497509550505050565b5f5f5f5f5f60a0868803121561554a575f5ffd5b6155538661533e565b97602087013597506040870135966060810135965060800135945092505050565b604081525f6155866040830185615194565b8281036020840152614af38185614d23565b5f5f5f5f61010085870312156155ac575f5ffd5b6155b68686614fca565b93506155c460a0860161549c565b939693955050505060c08201359160e0013590565b5f5f5f5f608085870312156155ec575f5ffd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761104657611046615630565b8082018082111561104657611046615630565b8181038181111561104657611046615630565b82815260408101612bea60208301846150e1565b5f600182016156a6576156a6615630565b5060010190565b5f826156c757634e487b7160e01b5f52601260045260245ffd5b500490565b5f602082840312156156dc575f5ffd5b5051919050565b600181811c908216806156f757607f821691505b60208210810361109557634e487b7160e01b5f52602260045260245ffd5b5f5f85851115615723575f5ffd5b8386111561572f575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015610fe9576001600160e01b031960049490940360031b84901b1690921692915050565b601f821115610f3e57805f5260205f20601f840160051c810160208510156157975750805b601f840160051c820191505b818110156157b6575f81556001016157a3565b5050505050565b6001600160401b038311156157d4576157d4615608565b6157e8836157e283546156e3565b83615772565b5f601f841160018114615819575f85156158025750838201355b5f19600387901b1c1916600186901b1783556157b6565b5f83815260208120601f198716915b828110156158485786850135825560209485019460019092019101615828565b5086821015615864575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b606081525f6158b1606083018789615876565b82810360208401526158c4818688615876565b9150508260408301529695505050505050565b5f5f83546158e4816156e3565b6001821680156158fb57600181146159105761593d565b60ff198316865281151582028601935061593d565b865f5260205f205f5b8381101561593557815488820152600190910190602001615919565b505081860193505b509195945050505050565b838152826020820152606060408201525f614af3606083018461519456fece50d87c0d4882aef479475d47c796b2f0709c4d0c2dd3e8344d2344c41978bca2646970667358221220467a9ce83a56600acd89555e067944af2619f098ebc27e8600d87c46dd2e56bb64736f6c634300081c0033000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a100000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000fa9d2a61f80772baafdda87082ffcea0232df738000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a325000000000000000000000000cd5762ac6013fa762782ac1797ab09152c1028e8000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe8800000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000bfbcf9fa4f9c56b0f40a671ad40e0805a09186500000000000000000000000046a15b0b27311cedf172ab29e4f4766fbe7f436400000000000000000000000013f4ea83d0bd40e75c8222255bc855a974568dd4000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90","name":"Freezer","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"npm/@openzeppelin/contracts@5.6.1/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        if (!_safeTransfer(token, to, value, true)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        if (!_safeTransferFrom(token, from, to, value, true)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _safeTransfer(token, to, value, false);\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _safeTransferFrom(token, from, to, value, false);\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        if (!_safeApprove(token, spender, value, false)) {\n            if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));\n            if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity `token.transfer(to, value)` call, relaxing the requirement on the return value: the\n     * return value is optional (but if data is returned, it must not be false).\n     *\n     * @param token The token targeted by the call.\n     * @param to The recipient of the tokens\n     * @param value The amount of token to transfer\n     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.\n     */\n    function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {\n        bytes4 selector = IERC20.transfer.selector;\n\n        assembly (\"memory-safe\") {\n            let fmp := mload(0x40)\n            mstore(0x00, selector)\n            mstore(0x04, and(to, shr(96, not(0))))\n            mstore(0x24, value)\n            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)\n            // if call success and return is true, all is good.\n            // otherwise (not success or return is not true), we need to perform further checks\n            if iszero(and(success, eq(mload(0x00), 1))) {\n                // if the call was a failure and bubble is enabled, bubble the error\n                if and(iszero(success), bubble) {\n                    returndatacopy(fmp, 0x00, returndatasize())\n                    revert(fmp, returndatasize())\n                }\n                // if the return value is not true, then the call is only successful if:\n                // - the token address has code\n                // - the returndata is empty\n                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))\n            }\n            mstore(0x40, fmp)\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, relaxing the requirement on the return\n     * value: the return value is optional (but if data is returned, it must not be false).\n     *\n     * @param token The token targeted by the call.\n     * @param from The sender of the tokens\n     * @param to The recipient of the tokens\n     * @param value The amount of token to transfer\n     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.\n     */\n    function _safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value,\n        bool bubble\n    ) private returns (bool success) {\n        bytes4 selector = IERC20.transferFrom.selector;\n\n        assembly (\"memory-safe\") {\n            let fmp := mload(0x40)\n            mstore(0x00, selector)\n            mstore(0x04, and(from, shr(96, not(0))))\n            mstore(0x24, and(to, shr(96, not(0))))\n            mstore(0x44, value)\n            success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)\n            // if call success and return is true, all is good.\n            // otherwise (not success or return is not true), we need to perform further checks\n            if iszero(and(success, eq(mload(0x00), 1))) {\n                // if the call was a failure and bubble is enabled, bubble the error\n                if and(iszero(success), bubble) {\n                    returndatacopy(fmp, 0x00, returndatasize())\n                    revert(fmp, returndatasize())\n                }\n                // if the return value is not true, then the call is only successful if:\n                // - the token address has code\n                // - the returndata is empty\n                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))\n            }\n            mstore(0x40, fmp)\n            mstore(0x60, 0)\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity `token.approve(spender, value)` call, relaxing the requirement on the return value:\n     * the return value is optional (but if data is returned, it must not be false).\n     *\n     * @param token The token targeted by the call.\n     * @param spender The spender of the tokens\n     * @param value The amount of token to transfer\n     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.\n     */\n    function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {\n        bytes4 selector = IERC20.approve.selector;\n\n        assembly (\"memory-safe\") {\n            let fmp := mload(0x40)\n            mstore(0x00, selector)\n            mstore(0x04, and(spender, shr(96, not(0))))\n            mstore(0x24, value)\n            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)\n            // if call success and return is true, all is good.\n            // otherwise (not success or return is not true), we need to perform further checks\n            if iszero(and(success, eq(mload(0x00), 1))) {\n                // if the call was a failure and bubble is enabled, bubble the error\n                if and(iszero(success), bubble) {\n                    returndatacopy(fmp, 0x00, returndatasize())\n                    revert(fmp, returndatasize())\n                }\n                // if the return value is not true, then the call is only successful if:\n                // - the token address has code\n                // - the returndata is empty\n                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))\n            }\n            mstore(0x40, fmp)\n        }\n    }\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/token/ERC721/IERC721Receiver.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity >=0.5.0;\n\n/**\n * @title ERC-721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC-721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n     * reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"npm/@openzeppelin/contracts@5.6.1/utils/math/SafeCast.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n    /**\n     * @dev Value doesn't fit in a uint of `bits` size.\n     */\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n    /**\n     * @dev An int value doesn't fit in a uint of `bits` size.\n     */\n    error SafeCastOverflowedIntToUint(int256 value);\n\n    /**\n     * @dev Value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n    /**\n     * @dev A uint value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedUintToInt(uint256 value);\n\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        if (value > type(uint248).max) {\n            revert SafeCastOverflowedUintDowncast(248, value);\n        }\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        if (value > type(uint240).max) {\n            revert SafeCastOverflowedUintDowncast(240, value);\n        }\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        if (value > type(uint232).max) {\n            revert SafeCastOverflowedUintDowncast(232, value);\n        }\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        if (value > type(uint224).max) {\n            revert SafeCastOverflowedUintDowncast(224, value);\n        }\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        if (value > type(uint216).max) {\n            revert SafeCastOverflowedUintDowncast(216, value);\n        }\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        if (value > type(uint208).max) {\n            revert SafeCastOverflowedUintDowncast(208, value);\n        }\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        if (value > type(uint200).max) {\n            revert SafeCastOverflowedUintDowncast(200, value);\n        }\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        if (value > type(uint192).max) {\n            revert SafeCastOverflowedUintDowncast(192, value);\n        }\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        if (value > type(uint184).max) {\n            revert SafeCastOverflowedUintDowncast(184, value);\n        }\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        if (value > type(uint176).max) {\n            revert SafeCastOverflowedUintDowncast(176, value);\n        }\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        if (value > type(uint168).max) {\n            revert SafeCastOverflowedUintDowncast(168, value);\n        }\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        if (value > type(uint160).max) {\n            revert SafeCastOverflowedUintDowncast(160, value);\n        }\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        if (value > type(uint152).max) {\n            revert SafeCastOverflowedUintDowncast(152, value);\n        }\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        if (value > type(uint144).max) {\n            revert SafeCastOverflowedUintDowncast(144, value);\n        }\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        if (value > type(uint136).max) {\n            revert SafeCastOverflowedUintDowncast(136, value);\n        }\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        if (value > type(uint128).max) {\n            revert SafeCastOverflowedUintDowncast(128, value);\n        }\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        if (value > type(uint120).max) {\n            revert SafeCastOverflowedUintDowncast(120, value);\n        }\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        if (value > type(uint112).max) {\n            revert SafeCastOverflowedUintDowncast(112, value);\n        }\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        if (value > type(uint104).max) {\n            revert SafeCastOverflowedUintDowncast(104, value);\n        }\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        if (value > type(uint96).max) {\n            revert SafeCastOverflowedUintDowncast(96, value);\n        }\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        if (value > type(uint88).max) {\n            revert SafeCastOverflowedUintDowncast(88, value);\n        }\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        if (value > type(uint80).max) {\n            revert SafeCastOverflowedUintDowncast(80, value);\n        }\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        if (value > type(uint72).max) {\n            revert SafeCastOverflowedUintDowncast(72, value);\n        }\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        if (value > type(uint64).max) {\n            revert SafeCastOverflowedUintDowncast(64, value);\n        }\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        if (value > type(uint56).max) {\n            revert SafeCastOverflowedUintDowncast(56, value);\n        }\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        if (value > type(uint48).max) {\n            revert SafeCastOverflowedUintDowncast(48, value);\n        }\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        if (value > type(uint40).max) {\n            revert SafeCastOverflowedUintDowncast(40, value);\n        }\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        if (value > type(uint32).max) {\n            revert SafeCastOverflowedUintDowncast(32, value);\n        }\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        if (value > type(uint24).max) {\n            revert SafeCastOverflowedUintDowncast(24, value);\n        }\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        if (value > type(uint16).max) {\n            revert SafeCastOverflowedUintDowncast(16, value);\n        }\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        if (value > type(uint8).max) {\n            revert SafeCastOverflowedUintDowncast(8, value);\n        }\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        if (value < 0) {\n            revert SafeCastOverflowedIntToUint(value);\n        }\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(248, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(240, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(232, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(224, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(216, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(208, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(200, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(192, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(184, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(176, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(168, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(160, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(152, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(144, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(136, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(128, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(120, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(112, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(104, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(96, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(88, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(80, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(72, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(64, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(56, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(48, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(40, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(32, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(24, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(16, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(8, value);\n        }\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        if (value > uint256(type(int256).max)) {\n            revert SafeCastOverflowedUintToInt(value);\n        }\n        return int256(value);\n    }\n\n    /**\n     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n     */\n    function toUint(bool b) internal pure returns (uint256 u) {\n        assembly (\"memory-safe\") {\n            u := iszero(iszero(b))\n        }\n    }\n}\n"},{"file_path":"project/contracts/DexBase.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {IPoolManager} from \"./interfaces/dex/IPoolManager.sol\";\n\nabstract contract DexBase {\n    struct Config {\n        address usdt;\n        address usdc;\n        address wbtc;\n        address weth;\n        address uniV3Factory;\n        address uniV3PositionManager;\n        address uniV3Router;\n        address pancakeV3Factory;\n        address pancakeV3PositionManager;\n        address pancakeV3Router;\n        address uniV4PoolManager;\n    }\n\n    enum Dex {\n        UniswapV3,\n        PancakeV3,\n        UniswapV4\n    }\n\n    struct V3MintParams {\n        Dex dex;\n        address token0;\n        address token1;\n        uint24 fee;\n        int24 tickLower;\n        int24 tickUpper;\n        uint256 amount0;\n        uint256 amount1;\n        uint256 amount0Min;\n        uint256 amount1Min;\n    }\n\n    struct V4Position {\n        IPoolManager.PoolKey key;\n        int24 tickLower;\n        int24 tickUpper;\n        uint256 liquidity;\n    }\n\n    struct Store {\n        address base;\n        uint256 dexSellCap;\n        uint256 dexSold;\n        Config config;\n\n        mapping(bytes32 positionId => V4Position) v4Positions;\n    }\n\n    // keccak256(\"dex.base.store\") - 1\n    bytes32 private constant STORE_SLOT = 0x61bd53f0a65728bdc7104173bbf7d4c06ffcedce7cc582891262b3e0cf8c62c6;\n\n    event V3Minted(\n        Dex indexed dex,\n        uint256 indexed tokenId,\n        address token0,\n        address token1,\n        uint24 fee,\n        int24 tickLower,\n        int24 tickUpper,\n        uint256 liquidity,\n        uint256 amount0,\n        uint256 amount1\n    );\n    event V3Increased(Dex indexed dex, uint256 indexed tokenId, uint256 liquidity, uint256 amount0, uint256 amount1);\n\n    event V3Decreased(\n        Dex indexed dex,\n        uint256 indexed tokenId,\n        uint256 liquidity,\n        uint256 amount0,\n        uint256 amount1,\n        uint256 fees0,\n        uint256 fees1,\n        bool burned\n    );\n\n    event V4PositionOpened(\n        bytes32 indexed positionId,\n        address currency0,\n        address currency1,\n        uint24 fee,\n        int24 tickSpacing,\n        int24 tickLower,\n        int24 tickUpper\n    );\n\n    event V4Modified(\n        bytes32 indexed positionId,\n        int256 liquidityDelta,\n        uint256 amount0,\n        uint256 amount1,\n        uint256 fees0,\n        uint256 fees1\n    );\n\n    event V4PositionClosed(bytes32 indexed positionId);\n    event Swapped(Dex indexed dex, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut);\n\n    error ZeroDexAddress();\n    error ZeroDexAmount();\n    error DexSellCapExceeded(uint256 sold, uint256 cap);\n    error TokenNotAllowed(address token);\n    error UnsortedPair(address token0, address token1);\n    error SamePair(address token);\n    error NotV3(Dex dex);\n    error PoolNotFound();\n    error HookedPool(address hooks);\n    error InsufficientLiquidity(uint256 available, uint256 requested);\n    error UnknownPosition(bytes32 positionId);\n    error ForeignPosition(uint256 tokenId);\n    error AmountExceedsMax(uint256 amount, uint256 max);\n    error AmountBelowMin(uint256 amount, uint256 min);\n    error NotPoolManager(address caller);\n    error NotSelf(address caller);\n    error AlreadyInitialized();\n\n    function _store() internal pure returns (Store storage s) {\n        assembly (\"memory-safe\") {\n            s.slot := STORE_SLOT\n        }\n    }\n\n    function isAllowedToken(address token) public view returns (bool) {\n        Store storage s = _store();\n        Config storage c = s.config;\n        return token == s.base || token == c.usdt || token == c.usdc || token == c.wbtc || token == c.weth;\n    }\n}\n"},{"file_path":"project/contracts/DexModule.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {SafeCast} from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport {DexBase} from \"./DexBase.sol\";\nimport {IUniswapV3Factory} from \"./interfaces/dex/IUniswapV3Factory.sol\";\nimport {INonfungiblePositionManager} from \"./interfaces/dex/INonfungiblePositionManager.sol\";\nimport {IV3SwapRouter} from \"./interfaces/dex/IV3SwapRouter.sol\";\nimport {IPoolManager} from \"./interfaces/dex/IPoolManager.sol\";\n\ncontract DexModule is DexBase {\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n    using SafeCast for int256;\n\n    enum V4Op {\n        Modify,\n        Swap\n    }\n\n    uint160 private constant MIN_SQRT_PRICE = 4295128739;\n    uint160 private constant MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342;\n\n    uint256 private constant POOLS_SLOT = 6;\n\n    modifier onlySelf() {\n        require(msg.sender == address(this), NotSelf(msg.sender));\n        _;\n    }\n\n    function init(address base, uint256 dexSellCap, Config calldata config) external {\n        Store storage s = _store();\n        require(s.base == address(0), AlreadyInitialized());\n        require(\n            base != address(0) &&\n                config.usdt != address(0) &&\n                config.usdc != address(0) &&\n                config.wbtc != address(0) &&\n                config.weth != address(0) &&\n                config.uniV3Factory != address(0) &&\n                config.uniV3PositionManager != address(0) &&\n                config.uniV3Router != address(0) &&\n                config.pancakeV3Factory != address(0) &&\n                config.pancakeV3PositionManager != address(0) &&\n                config.pancakeV3Router != address(0) &&\n                config.uniV4PoolManager != address(0),\n            ZeroDexAddress()\n        );\n\n        s.base = base;\n        s.dexSellCap = dexSellCap;\n        s.config = config;\n    }\n\n    function v3Mint(V3MintParams calldata p) external onlySelf returns (uint256 tokenId, uint256 liquidity) {\n        (, INonfungiblePositionManager positionManager, ) = _v3(p.dex);\n        _requireV3Pool(p.dex, p.token0, p.token1, p.fee);\n\n        IERC20(p.token0).forceApprove(address(positionManager), p.amount0);\n        IERC20(p.token1).forceApprove(address(positionManager), p.amount1);\n\n        uint256 used0;\n        uint256 used1;\n        (tokenId, liquidity, used0, used1) = positionManager.mint(\n            INonfungiblePositionManager.MintParams({\n                token0: p.token0,\n                token1: p.token1,\n                fee: p.fee,\n                tickLower: p.tickLower,\n                tickUpper: p.tickUpper,\n                amount0Desired: p.amount0,\n                amount1Desired: p.amount1,\n                amount0Min: p.amount0Min,\n                amount1Min: p.amount1Min,\n                recipient: address(this),\n                deadline: block.timestamp\n            })\n        );\n\n        IERC20(p.token0).forceApprove(address(positionManager), 0);\n        IERC20(p.token1).forceApprove(address(positionManager), 0);\n\n        _countSold(p.token0, used0);\n        _countSold(p.token1, used1);\n\n        emit V3Minted(p.dex, tokenId, p.token0, p.token1, p.fee, p.tickLower, p.tickUpper, liquidity, used0, used1);\n    }\n\n    function v3Increase(\n        Dex dex,\n        uint256 tokenId,\n        uint256 amount0,\n        uint256 amount1,\n        uint256 amount0Min,\n        uint256 amount1Min\n    ) external onlySelf returns (uint256 liquidity, uint256 used0, uint256 used1) {\n        (, INonfungiblePositionManager positionManager, ) = _v3(dex);\n        require(positionManager.ownerOf(tokenId) == address(this), ForeignPosition(tokenId));\n\n        (, , address token0, address token1, , , , , , , , ) = positionManager.positions(tokenId);\n        _requirePair(token0, token1);\n\n        IERC20(token0).forceApprove(address(positionManager), amount0);\n        IERC20(token1).forceApprove(address(positionManager), amount1);\n\n        (liquidity, used0, used1) = positionManager.increaseLiquidity(\n            INonfungiblePositionManager.IncreaseLiquidityParams({\n                tokenId: tokenId,\n                amount0Desired: amount0,\n                amount1Desired: amount1,\n                amount0Min: amount0Min,\n                amount1Min: amount1Min,\n                deadline: block.timestamp\n            })\n        );\n\n        IERC20(token0).forceApprove(address(positionManager), 0);\n        IERC20(token1).forceApprove(address(positionManager), 0);\n\n        _countSold(token0, used0);\n        _countSold(token1, used1);\n\n        emit V3Increased(dex, tokenId, liquidity, used0, used1);\n    }\n\n    function v3Decrease(\n        Dex dex,\n        uint256 tokenId,\n        uint256 liquidity,\n        uint256 amount0Min,\n        uint256 amount1Min\n    ) external onlySelf returns (uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1) {\n        (, INonfungiblePositionManager positionManager, ) = _v3(dex);\n\n        (, , address token0, address token1, , , , uint128 total, , , , ) = positionManager.positions(tokenId);\n        _requirePair(token0, token1);\n        require(liquidity <= total, InsufficientLiquidity(total, liquidity));\n\n        if (liquidity != 0) {\n            (amount0, amount1) = positionManager.decreaseLiquidity(\n                INonfungiblePositionManager.DecreaseLiquidityParams({\n                    tokenId: tokenId,\n                    liquidity: liquidity.toUint128(),\n                    amount0Min: amount0Min,\n                    amount1Min: amount1Min,\n                    deadline: block.timestamp\n                })\n            );\n            _countBought(token0, amount0);\n            _countBought(token1, amount1);\n        }\n\n        (fees0, fees1) = positionManager.collect(\n            INonfungiblePositionManager.CollectParams({\n                tokenId: tokenId,\n                recipient: address(this),\n                amount0Max: type(uint128).max,\n                amount1Max: type(uint128).max\n            })\n        );\n\n        fees0 = fees0 > amount0 ? fees0 - amount0 : 0;\n        fees1 = fees1 > amount1 ? fees1 - amount1 : 0;\n\n        bool burned = liquidity == total && total != 0;\n        if (burned) {\n            positionManager.burn(tokenId);\n        }\n\n        emit V3Decreased(dex, tokenId, liquidity, amount0, amount1, fees0, fees1, burned);\n    }\n\n    function v3Swap(\n        Dex dex,\n        address tokenIn,\n        address tokenOut,\n        uint24 fee,\n        uint256 amountIn,\n        uint256 amountOutMinimum\n    ) external onlySelf returns (uint256 amountOut) {\n        require(amountIn != 0, ZeroDexAmount());\n        (, , IV3SwapRouter router) = _v3(dex);\n        (address token0, address token1) = tokenIn < tokenOut ? (tokenIn, tokenOut) : (tokenOut, tokenIn);\n        _requireV3Pool(dex, token0, token1, fee);\n\n        uint256 before = IERC20(tokenIn).balanceOf(address(this));\n        IERC20(tokenIn).forceApprove(address(router), amountIn);\n\n        amountOut = router.exactInputSingle(\n            IV3SwapRouter.ExactInputSingleParams({\n                tokenIn: tokenIn,\n                tokenOut: tokenOut,\n                fee: fee,\n                recipient: address(this),\n                amountIn: amountIn,\n                amountOutMinimum: amountOutMinimum,\n                sqrtPriceLimitX96: 0\n            })\n        );\n\n        IERC20(tokenIn).forceApprove(address(router), 0);\n        uint256 spent = before - IERC20(tokenIn).balanceOf(address(this));\n\n        _countSold(tokenIn, spent);\n        _countBought(tokenOut, amountOut);\n\n        emit Swapped(dex, tokenIn, tokenOut, spent, amountOut);\n    }\n\n    function v4Increase(\n        IPoolManager.PoolKey calldata key,\n        int24 tickLower,\n        int24 tickUpper,\n        uint256 liquidity,\n        uint256 amount0Max,\n        uint256 amount1Max\n    ) external onlySelf returns (bytes32 positionId, uint256 amount0, uint256 amount1) {\n        require(liquidity != 0, ZeroDexAmount());\n        _requireV4Pool(key);\n\n        uint256 fees0;\n        uint256 fees1;\n        (amount0, amount1, fees0, fees1) = _v4Modify(key, tickLower, tickUpper, liquidity.toInt256(), amount0Max, amount1Max);\n\n        positionId = _positionId(key, tickLower, tickUpper);\n        _open(positionId, key, tickLower, tickUpper);\n        _store().v4Positions[positionId].liquidity += liquidity;\n\n        _countSold(key.currency0, amount0);\n        _countSold(key.currency1, amount1);\n\n        emit V4Modified(positionId, liquidity.toInt256(), amount0, amount1, fees0, fees1);\n    }\n\n    function v4Decrease(\n        bytes32 positionId,\n        uint256 liquidity,\n        uint256 amount0Min,\n        uint256 amount1Min\n    ) external onlySelf returns (uint256 amount0, uint256 amount1) {\n        Store storage s = _store();\n        V4Position memory position = s.v4Positions[positionId];\n        require(position.liquidity != 0, UnknownPosition(positionId));\n        require(liquidity <= position.liquidity, InsufficientLiquidity(position.liquidity, liquidity));\n\n        uint256 fees0;\n        uint256 fees1;\n        (amount0, amount1, fees0, fees1) = _v4Modify(\n            position.key,\n            position.tickLower,\n            position.tickUpper,\n            -liquidity.toInt256(),\n            amount0Min,\n            amount1Min\n        );\n\n        _countBought(position.key.currency0, amount0);\n        _countBought(position.key.currency1, amount1);\n\n        if (liquidity == position.liquidity) {\n            delete s.v4Positions[positionId];\n            emit V4PositionClosed(positionId);\n        } else {\n            s.v4Positions[positionId].liquidity -= liquidity;\n        }\n\n        emit V4Modified(positionId, -liquidity.toInt256(), amount0, amount1, fees0, fees1);\n    }\n\n    function v4Swap(\n        IPoolManager.PoolKey calldata key,\n        bool zeroForOne,\n        uint256 amountIn,\n        uint256 amountOutMinimum\n    ) external onlySelf returns (uint256 amountOut) {\n        require(amountIn != 0, ZeroDexAmount());\n        _requireV4Pool(key);\n\n        bytes memory result = _poolManager().unlock(\n            abi.encode(V4Op.Swap, abi.encode(key, zeroForOne, amountIn, amountOutMinimum))\n        );\n\n        uint256 spent;\n        (spent, amountOut) = abi.decode(result, (uint256, uint256));\n\n        (address tokenIn, address tokenOut) = zeroForOne\n            ? (key.currency0, key.currency1)\n            : (key.currency1, key.currency0);\n\n        _countSold(tokenIn, spent);\n        _countBought(tokenOut, amountOut);\n\n        emit Swapped(Dex.UniswapV4, tokenIn, tokenOut, spent, amountOut);\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        IPoolManager poolManager = _poolManager();\n        require(msg.sender == address(poolManager), NotPoolManager(msg.sender));\n\n        (V4Op op, bytes memory payload) = abi.decode(data, (V4Op, bytes));\n\n        if (op == V4Op.Modify) {\n            return _modifyInsideUnlock(poolManager, payload);\n        }\n        return _swapInsideUnlock(poolManager, payload);\n    }\n\n    function _modifyInsideUnlock(IPoolManager poolManager, bytes memory payload) private returns (bytes memory) {\n        (\n            IPoolManager.PoolKey memory key,\n            int24 tickLower,\n            int24 tickUpper,\n            int256 liquidityDelta,\n            uint256 bound0,\n            uint256 bound1\n        ) = abi.decode(payload, (IPoolManager.PoolKey, int24, int24, int256, uint256, uint256));\n\n        (int256 delta, int256 fees) = poolManager.modifyLiquidity(\n            key,\n            IPoolManager.ModifyLiquidityParams({\n                tickLower: tickLower,\n                tickUpper: tickUpper,\n                liquidityDelta: liquidityDelta,\n                salt: bytes32(0)\n            }),\n            \"\"\n        );\n\n        (int256 delta0, int256 delta1) = _split(delta);\n        _settle(poolManager, key.currency0, delta0);\n        _settle(poolManager, key.currency1, delta1);\n\n        return _bounded(delta, fees, liquidityDelta, bound0, bound1);\n    }\n\n    function _bounded(\n        int256 delta,\n        int256 fees,\n        int256 liquidityDelta,\n        uint256 bound0,\n        uint256 bound1\n    ) private pure returns (bytes memory) {\n        (int256 delta0, int256 delta1) = _split(delta);\n        (int256 fees0, int256 fees1) = _split(fees);\n        int256 principal0 = delta0 - fees0;\n        int256 principal1 = delta1 - fees1;\n\n        uint256 amount0;\n        uint256 amount1;\n        if (liquidityDelta > 0) {\n            amount0 = principal0 < 0 ? uint256(-principal0) : 0;\n            amount1 = principal1 < 0 ? uint256(-principal1) : 0;\n            require(amount0 <= bound0, AmountExceedsMax(amount0, bound0));\n            require(amount1 <= bound1, AmountExceedsMax(amount1, bound1));\n        } else {\n            amount0 = principal0 > 0 ? uint256(principal0) : 0;\n            amount1 = principal1 > 0 ? uint256(principal1) : 0;\n            require(amount0 >= bound0, AmountBelowMin(amount0, bound0));\n            require(amount1 >= bound1, AmountBelowMin(amount1, bound1));\n        }\n        return abi.encode(amount0, amount1, uint256(fees0), uint256(fees1));\n    }\n\n    function _swapInsideUnlock(IPoolManager poolManager, bytes memory payload) private returns (bytes memory) {\n        (IPoolManager.PoolKey memory key, bool zeroForOne, uint256 amountIn, uint256 amountOutMinimum) = abi.decode(\n            payload,\n            (IPoolManager.PoolKey, bool, uint256, uint256)\n        );\n\n        int256 delta = poolManager.swap(\n            key,\n            IPoolManager.SwapParams({\n                zeroForOne: zeroForOne,\n                amountSpecified: -amountIn.toInt256(),\n                sqrtPriceLimitX96: zeroForOne ? MIN_SQRT_PRICE + 1 : MAX_SQRT_PRICE - 1\n            }),\n            \"\"\n        );\n\n        (int256 delta0, int256 delta1) = _split(delta);\n        _settle(poolManager, key.currency0, delta0);\n        _settle(poolManager, key.currency1, delta1);\n\n        (int256 inDelta, int256 outDelta) = zeroForOne ? (delta0, delta1) : (delta1, delta0);\n        uint256 spent = inDelta < 0 ? uint256(-inDelta) : 0;\n        uint256 amountOut = outDelta > 0 ? uint256(outDelta) : 0;\n        require(amountOut >= amountOutMinimum, AmountBelowMin(amountOut, amountOutMinimum));\n        return abi.encode(spent, amountOut);\n    }\n\n    function _v3(Dex dex) private view returns (IUniswapV3Factory, INonfungiblePositionManager, IV3SwapRouter) {\n        Config storage c = _store().config;\n        if (dex == Dex.UniswapV3) {\n            return (\n                IUniswapV3Factory(c.uniV3Factory),\n                INonfungiblePositionManager(c.uniV3PositionManager),\n                IV3SwapRouter(c.uniV3Router)\n            );\n        }\n        if (dex == Dex.PancakeV3) {\n            return (\n                IUniswapV3Factory(c.pancakeV3Factory),\n                INonfungiblePositionManager(c.pancakeV3PositionManager),\n                IV3SwapRouter(c.pancakeV3Router)\n            );\n        }\n        revert NotV3(dex);\n    }\n\n    function _countSold(address token, uint256 amount) private {\n        Store storage s = _store();\n        if (token != s.base || amount == 0) {\n            return;\n        }\n        uint256 sold = s.dexSold + amount;\n        require(sold <= s.dexSellCap, DexSellCapExceeded(sold, s.dexSellCap));\n        s.dexSold = sold;\n    }\n\n    function _countBought(address token, uint256 amount) private {\n        Store storage s = _store();\n        if (token != s.base || amount == 0) {\n            return;\n        }\n        uint256 sold = s.dexSold;\n        s.dexSold = amount >= sold ? 0 : sold - amount;\n    }\n\n    function _poolManager() private view returns (IPoolManager) {\n        return IPoolManager(_store().config.uniV4PoolManager);\n    }\n\n    function _requirePair(address token0, address token1) private view {\n        require(isAllowedToken(token0), TokenNotAllowed(token0));\n        require(isAllowedToken(token1), TokenNotAllowed(token1));\n        require(token0 != token1, SamePair(token0));\n        require(token0 < token1, UnsortedPair(token0, token1));\n    }\n\n    function _requireV3Pool(Dex dex, address token0, address token1, uint24 fee) private view {\n        _requirePair(token0, token1);\n        (IUniswapV3Factory factory, , ) = _v3(dex);\n        require(factory.getPool(token0, token1, fee) != address(0), PoolNotFound());\n    }\n\n    function _requireV4Pool(IPoolManager.PoolKey calldata key) private view {\n        require(key.hooks == address(0), HookedPool(key.hooks));\n        _requirePair(key.currency0, key.currency1);\n\n        bytes32 poolId = keccak256(abi.encode(key));\n        bytes32 slot0 = _poolManager().extsload(keccak256(abi.encodePacked(poolId, POOLS_SLOT)));\n        require(uint160(uint256(slot0)) != 0, PoolNotFound());\n    }\n\n    function _v4Modify(\n        IPoolManager.PoolKey memory key,\n        int24 tickLower,\n        int24 tickUpper,\n        int256 liquidityDelta,\n        uint256 bound0,\n        uint256 bound1\n    ) private returns (uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1) {\n        bytes memory result = _poolManager().unlock(\n            abi.encode(V4Op.Modify, abi.encode(key, tickLower, tickUpper, liquidityDelta, bound0, bound1))\n        );\n        return abi.decode(result, (uint256, uint256, uint256, uint256));\n    }\n\n    function _settle(IPoolManager poolManager, address currency, int256 amount) private {\n        if (amount < 0) {\n            poolManager.sync(currency);\n            IERC20(currency).safeTransfer(address(poolManager), uint256(-amount));\n            poolManager.settle();\n        } else if (amount > 0) {\n            poolManager.take(currency, address(this), uint256(amount));\n        }\n    }\n\n    function _open(bytes32 positionId, IPoolManager.PoolKey calldata key, int24 tickLower, int24 tickUpper) private {\n        V4Position storage position = _store().v4Positions[positionId];\n        if (position.liquidity != 0) {\n            return;\n        }\n        position.key = key;\n        position.tickLower = tickLower;\n        position.tickUpper = tickUpper;\n        emit V4PositionOpened(positionId, key.currency0, key.currency1, key.fee, key.tickSpacing, tickLower, tickUpper);\n    }\n\n    function _positionId(\n        IPoolManager.PoolKey memory key,\n        int24 tickLower,\n        int24 tickUpper\n    ) private pure returns (bytes32) {\n        return keccak256(abi.encode(key, tickLower, tickUpper));\n    }\n\n    function _split(int256 delta) private pure returns (int256 amount0, int256 amount1) {\n        amount0 = int256(int128(delta >> 128));\n        amount1 = int256(int128(delta));\n    }\n}\n"},{"file_path":"project/contracts/DexTreasury.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {IERC721Receiver} from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\n\nimport {Senate} from \"./Senate.sol\";\nimport {DexBase} from \"./DexBase.sol\";\nimport {DexModule} from \"./DexModule.sol\";\nimport {IPoolManager, IUnlockCallback} from \"./interfaces/dex/IPoolManager.sol\";\n\nabstract contract DexTreasury is Senate, DexBase, IERC721Receiver, IUnlockCallback {\n    address private immutable _module;\n\n    error NoModule(address module);\n\n    constructor(address module, address base, uint256 dexSellCap_, Config memory config) {\n        require(module.code.length != 0, NoModule(module));\n        _module = module;\n\n        _delegate(abi.encodeCall(DexModule.init, (base, dexSellCap_, config)));\n    }\n\n    function v3Mint(V3MintParams calldata) external onlySenate returns (uint256, uint256) {\n        _forward();\n    }\n\n    function v3Increase(\n        Dex,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256\n    ) external onlySenate returns (uint256, uint256, uint256) {\n        _forward();\n    }\n\n    function v3Decrease(\n        Dex,\n        uint256,\n        uint256,\n        uint256,\n        uint256\n    ) external onlySenate returns (uint256, uint256, uint256, uint256) {\n        _forward();\n    }\n\n    function v3Swap(\n        Dex,\n        address,\n        address,\n        uint24,\n        uint256,\n        uint256\n    ) external onlySenate returns (uint256) {\n        _forward();\n    }\n\n    function v4Increase(\n        IPoolManager.PoolKey calldata,\n        int24,\n        int24,\n        uint256,\n        uint256,\n        uint256\n    ) external onlySenate returns (bytes32, uint256, uint256) {\n        _forward();\n    }\n\n    function v4Decrease(\n        bytes32,\n        uint256,\n        uint256,\n        uint256\n    ) external onlySenate returns (uint256, uint256) {\n        _forward();\n    }\n\n    function v4Swap(\n        IPoolManager.PoolKey calldata,\n        bool,\n        uint256,\n        uint256\n    ) external onlySenate returns (uint256) {\n        _forward();\n    }\n\n    function unlockCallback(bytes calldata) external returns (bytes memory) {\n        _forward();\n    }\n\n    function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {\n        return IERC721Receiver.onERC721Received.selector;\n    }\n\n    function dexModule() external view returns (address) {\n        return _module;\n    }\n\n    function dexSellCap() external view returns (uint256) {\n        return _store().dexSellCap;\n    }\n\n    function dexSold() external view returns (uint256) {\n        return _store().dexSold;\n    }\n\n    function dexSellLeft() external view returns (uint256) {\n        Store storage s = _store();\n        return s.dexSellCap > s.dexSold ? s.dexSellCap - s.dexSold : 0;\n    }\n\n    function v4PositionOf(bytes32 positionId) external view returns (V4Position memory) {\n        return _store().v4Positions[positionId];\n    }\n\n    function _isProposable(bytes4 selector) internal view virtual override returns (bool) {\n        return\n            selector == this.v3Mint.selector ||\n            selector == this.v3Increase.selector ||\n            selector == this.v3Decrease.selector ||\n            selector == this.v3Swap.selector ||\n            selector == this.v4Increase.selector ||\n            selector == this.v4Decrease.selector ||\n            selector == this.v4Swap.selector ||\n            super._isProposable(selector);\n    }\n\n    function _forward() private {\n        address module = _module;\n\n        assembly {\n            calldatacopy(0, 0, calldatasize())\n            let ok := delegatecall(gas(), module, 0, calldatasize(), 0, 0)\n            returndatacopy(0, 0, returndatasize())\n            switch ok\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n\n    function _delegate(bytes memory data) private {\n        (bool ok, bytes memory result) = _module.delegatecall(data);\n        if (!ok) {\n            assembly (\"memory-safe\") {\n                revert(add(result, 32), mload(result))\n            }\n        }\n    }\n}\n"},{"file_path":"project/contracts/OperatorLockable.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {Context} from \"@openzeppelin/contracts/utils/Context.sol\";\n\nabstract contract OperatorLockable is Context {\n    mapping(address owner => mapping(address operator => bool approved)) private _approvals;\n\n    mapping(uint256 id => address lockedFor) private _lockedFor;\n\n    mapping(uint256 id => uint256 till) private _lockedTill;\n\n    event OperatorApproved(address indexed owner, address indexed operator);\n\n    event OperatorApproveRevoked(address indexed owner, address indexed operator);\n\n    event Locked(uint256 indexed id, address indexed lockedFor, uint256 till);\n\n    event Unlocked(uint256 indexed id);\n\n    error NotApproved(address owner, address operator);\n\n    error AlreadyLocked(uint256 id);\n\n    error LockTillInPast();\n\n    error NonexistentId(uint256 id);\n\n    error OperatorNotPermitted(address operator);\n\n    function approveOperator(address operator) public virtual {\n        _requireOperatorPermitted(operator);\n\n        _changeApprove(_msgSender(), operator, true);\n    }\n\n    function revokeOperatorApprove(address owner, address operator) public virtual {\n        address sender = _msgSender();\n        require(sender == owner || sender == operator, NotApproved(owner, operator));\n\n        _changeApprove(owner, operator, false);\n    }\n\n    function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {\n        return _isApprovedForAll(owner, operator);\n    }\n\n    function lock(uint256 id) public virtual {\n        lock(id, type(uint256).max);\n    }\n\n    function lock(uint256 id, uint256 lockTill) public virtual {\n        address operator = _msgSender();\n        address owner = _ownerOf(id);\n\n        require(owner != address(0), NonexistentId(id));\n        require(lockTill > block.timestamp, LockTillInPast());\n\n        _requireLockAllowed(id, lockTill);\n\n        _requireAllowance(owner, operator);\n        _requireRelockAllowed(id, owner);\n\n        _lock(id, owner, lockTill);\n    }\n\n    function unlock(uint256 id) public virtual {\n        address lockedFor = _lockedForOf(id);\n        if (lockedFor != address(0)) {\n            _requireAllowance(lockedFor, _msgSender());\n        }\n\n        _unlock(id);\n    }\n\n    function isLocked(uint256 id) public view virtual returns (bool) {\n        return _isLocked(id);\n    }\n\n    function lockTillOf(uint256 id) public view virtual returns (uint256) {\n        return _lockedTillOf(id);\n    }\n\n    function lockedForOf(uint256 id) public view virtual returns (address) {\n        return _lockedForOf(id);\n    }\n\n    function _isApprovedForAll(address owner, address operator) internal view virtual returns (bool) {\n        return owner == operator || _approvals[owner][operator];\n    }\n\n    function _ownerOf(uint256 id) internal view virtual returns (address);\n\n    function _lockedForOf(uint256 id) internal view virtual returns (address) {\n        if (_isLocked(id)) {\n            return _lockedFor[id];\n        }\n\n        return address(0);\n    }\n\n    function _lockedTillOf(uint256 id) internal view virtual returns (uint256) {\n        return _lockedTill[id];\n    }\n\n    function _isLocked(uint256 id) internal view virtual returns (bool) {\n        return _lockedTillOf(id) > block.timestamp;\n    }\n\n    function _operatorPermitted(address operator) internal view virtual returns (bool) {\n        return operator != address(0);\n    }\n\n    function _requireAllowance(address owner, address operator) internal view virtual {\n        if (owner == operator) {\n            return;\n        }\n        _requireOperatorPermitted(operator);\n        require(_isApprovedForAll(owner, operator), NotApproved(owner, operator));\n    }\n\n    function _requireRelockAllowed(uint256 id, address owner) internal view virtual {\n        address beneficiary = _lockedForOf(id);\n        require(beneficiary == address(0) || beneficiary == owner, AlreadyLocked(id));\n    }\n\n    function _requireOperatorPermitted(address operator) internal view virtual {\n        require(_operatorPermitted(operator), OperatorNotPermitted(operator));\n    }\n\n    function _requireLockAllowed(uint256 id, uint256 till) internal view virtual {}\n\n    function _lock(uint256 id, address lockedFor, uint256 lockedTill) internal virtual {\n        _lockedFor[id] = lockedFor;\n        _lockedTill[id] = lockedTill;\n\n        emit Locked(id, lockedFor, lockedTill);\n    }\n\n    function _unlock(uint256 id) internal virtual {\n        if (_lockedFor[id] == address(0)) {\n            return;\n        }\n        delete _lockedFor[id];\n        delete _lockedTill[id];\n\n        emit Unlocked(id);\n    }\n\n    function _changeApprove(address owner, address operator, bool approved) internal virtual {\n        _approvals[owner][operator] = approved;\n\n        if (approved) {\n            emit OperatorApproved(owner, operator);\n        } else {\n            emit OperatorApproveRevoked(owner, operator);\n        }\n    }\n}\n"},{"file_path":"project/contracts/Senate.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {Context} from \"@openzeppelin/contracts/utils/Context.sol\";\n\nabstract contract Senate is Context {\n    struct Node {\n        address prev;\n        address next;\n        uint256 stake;\n    }\n\n    struct Proposal {\n        address proposer;\n        uint256 createdAt;\n        uint256 deadline;\n        bool executed;\n        bool cancelled;\n        bytes data;\n        string description;\n    }\n\n    enum Vote {\n        None,\n        For,\n        Against\n    }\n\n    enum ProposalState {\n        Open,\n        Executed,\n        Cancelled,\n        Expired\n    }\n\n    uint256 public constant MIN_SENATE = 3;\n    uint256 public constant MAX_SENATE = 21;\n    uint256 public constant LIST_CAP = 4 * MAX_SENATE;\n    uint256 public constant MIN_VOTING_PERIOD = 1 days;\n    uint256 public constant MAX_VOTING_PERIOD = 30 days;\n\n    uint256 public constant MAX_DESCRIPTION_LENGTH = 255;\n\n    uint256 public senateSize = MIN_SENATE;\n    uint256 public votingPeriod = 3 days;\n    uint256 public proposalCount;\n\n    mapping(address account => bool) private _registered;\n    mapping(address account => bool) private _listed;\n    mapping(address account => Node) private _nodes;\n    address private _head;\n    address private _tail;\n    uint256 private _listLength;\n\n    mapping(uint256 id => Proposal) private _proposals;\n    mapping(uint256 id => mapping(address voter => Vote)) private _votes;\n\n    event Registered(address indexed account);\n    event Ranked(address indexed account, uint256 stake);\n    event Unranked(address indexed account);\n    event SenateSizeChanged(uint256 oldSize, uint256 newSize);\n    event VotingPeriodChanged(uint256 oldPeriod, uint256 newPeriod);\n    event ProposalCreated(\n        uint256 indexed id,\n        address indexed proposer,\n        bytes4 indexed selector,\n        bytes data,\n        string description,\n        uint256 deadline\n    );\n    event Voted(uint256 indexed id, address indexed voter, bool support);\n    event ProposalCancelled(uint256 indexed id);\n\n    event ProposalExecuted(\n        uint256 indexed id,\n        address indexed executor,\n        uint256 votesFor,\n        uint256 senateSize,\n        address[] senators\n    );\n\n    error AlreadyRegistered(address account);\n    error NotRegistered(address account);\n    error NotSenator(address account);\n    error NotSenate(address caller);\n    error NotProposable(bytes4 selector);\n    error InvalidCalldata();\n    error DescriptionTooLong(uint256 length, uint256 max);\n    error NonexistentProposal(uint256 id);\n    error ProposalNotOpen(uint256 id, ProposalState state);\n    error AlreadyVoted(uint256 id, address voter);\n    error NotProposer(uint256 id, address caller, address proposer);\n    error NotPassed(uint256 id, uint256 votesFor, uint256 seats);\n    error InvalidSenateSize(uint256 size, uint256 min, uint256 max);\n    error InvalidVotingPeriod(uint256 period, uint256 min, uint256 max);\n    error SameValue(uint256 value);\n\n    modifier onlySenate() {\n        require(_msgSender() == address(this), NotSenate(_msgSender()));\n        _;\n    }\n\n    function applyForSenate() external {\n        _register(_msgSender());\n    }\n\n    function refresh(address account) external {\n        require(_registered[account], NotRegistered(account));\n\n        _onStakeChanged(account);\n    }\n\n    function propose(bytes calldata data, string calldata description) external returns (uint256 id) {\n        address sender = _msgSender();\n        require(isSenator(sender), NotSenator(sender));\n        require(data.length >= 4, InvalidCalldata());\n        require(\n            bytes(description).length <= MAX_DESCRIPTION_LENGTH,\n            DescriptionTooLong(bytes(description).length, MAX_DESCRIPTION_LENGTH)\n        );\n\n        bytes4 selector = bytes4(data[:4]);\n        require(_isProposable(selector), NotProposable(selector));\n\n        id = ++proposalCount;\n\n        Proposal storage proposal = _proposals[id];\n        proposal.proposer = sender;\n        proposal.createdAt = block.timestamp;\n        proposal.deadline = block.timestamp + votingPeriod;\n        proposal.data = data;\n        proposal.description = description;\n\n        _votes[id][sender] = Vote.For;\n\n        emit ProposalCreated(id, sender, selector, data, description, proposal.deadline);\n        emit Voted(id, sender, true);\n    }\n\n    function vote(uint256 id, bool support) external {\n        address sender = _msgSender();\n        _requireOpen(id);\n        require(isSenator(sender), NotSenator(sender));\n        require(_votes[id][sender] == Vote.None, AlreadyVoted(id, sender));\n\n        _votes[id][sender] = support ? Vote.For : Vote.Against;\n\n        emit Voted(id, sender, support);\n    }\n\n    function cancel(uint256 id) external {\n        address sender = _msgSender();\n        Proposal storage proposal = _requireProposal(id);\n        require(proposal.proposer == sender, NotProposer(id, sender, proposal.proposer));\n        ProposalState current = _state(proposal);\n        require(\n            current == ProposalState.Open || current == ProposalState.Expired,\n            ProposalNotOpen(id, current)\n        );\n\n        proposal.cancelled = true;\n\n        emit ProposalCancelled(id);\n    }\n\n    function execute(uint256 id) external {\n        Proposal storage proposal = _requireOpen(id);\n\n        uint256 size = senateSize;\n        (uint256 support, address[] memory seats) = _tally(id);\n        require(_isPassed(support), NotPassed(id, support, size));\n\n        proposal.executed = true;\n\n        (bool ok, bytes memory result) = address(this).call(proposal.data);\n        if (!ok) {\n            assembly (\"memory-safe\") {\n                revert(add(result, 32), mload(result))\n            }\n        }\n\n        _afterExecute(id);\n\n        emit ProposalExecuted(id, _msgSender(), support, size, seats);\n    }\n\n    function setSenateSize(uint256 size) external onlySenate {\n        require(size >= MIN_SENATE && size <= MAX_SENATE, InvalidSenateSize(size, MIN_SENATE, MAX_SENATE));\n\n        uint256 previous = senateSize;\n        require(size != previous, SameValue(size));\n        senateSize = size;\n\n        emit SenateSizeChanged(previous, size);\n    }\n\n    function setVotingPeriod(uint256 period) external onlySenate {\n        require(\n            period >= MIN_VOTING_PERIOD && period <= MAX_VOTING_PERIOD,\n            InvalidVotingPeriod(period, MIN_VOTING_PERIOD, MAX_VOTING_PERIOD)\n        );\n\n        uint256 previous = votingPeriod;\n        require(period != previous, SameValue(period));\n        votingPeriod = period;\n\n        emit VotingPeriodChanged(previous, period);\n    }\n\n    function isRegistered(address account) public view returns (bool) {\n        return _registered[account];\n    }\n\n    function isListed(address account) public view returns (bool) {\n        return _listed[account];\n    }\n\n    function listLength() public view returns (uint256) {\n        return _listLength;\n    }\n\n    function listedStakeOf(address account) public view returns (uint256) {\n        return _nodes[account].stake;\n    }\n\n    function isSenator(address account) public view returns (bool) {\n        if (!_listed[account]) {\n            return false;\n        }\n\n        address current = _head;\n        for (uint256 seat = 0; seat < senateSize && current != address(0); ++seat) {\n            if (current == account) {\n                return true;\n            }\n            current = _nodes[current].next;\n        }\n        return false;\n    }\n\n    function senators() external view returns (address[] memory out) {\n        uint256 seats = senateSize < _listLength ? senateSize : _listLength;\n        out = new address[](seats);\n\n        address current = _head;\n        for (uint256 i = 0; i < seats; ++i) {\n            out[i] = current;\n            current = _nodes[current].next;\n        }\n    }\n\n    function ranked() external view returns (address[] memory accounts, uint256[] memory stakes) {\n        accounts = new address[](_listLength);\n        stakes = new uint256[](_listLength);\n\n        address current = _head;\n        for (uint256 i = 0; i < _listLength; ++i) {\n            accounts[i] = current;\n            stakes[i] = _nodes[current].stake;\n            current = _nodes[current].next;\n        }\n    }\n\n    function getProposal(uint256 id) external view returns (Proposal memory) {\n        return _requireProposal(id);\n    }\n\n    function state(uint256 id) public view returns (ProposalState) {\n        return _state(_requireProposal(id));\n    }\n\n    function voteOf(uint256 id, address voter) external view returns (Vote) {\n        return _votes[id][voter];\n    }\n\n    function votesFor(uint256 id) public view returns (uint256 support) {\n        (support, ) = _tally(id);\n    }\n\n    function _tally(uint256 id) private view returns (uint256 support, address[] memory seats) {\n        support = 0;\n        seats = new address[](senateSize);\n\n        uint256 seat = 0;\n        address current = _head;\n        for (; seat < senateSize && current != address(0); ++seat) {\n            seats[seat] = current;\n            if (_votes[id][current] == Vote.For) {\n                ++support;\n            }\n            current = _nodes[current].next;\n        }\n        assembly (\"memory-safe\") {\n            mstore(seats, seat)\n        }\n    }\n\n    function isPassed(uint256 id) external view returns (bool) {\n        return _isPassed(votesFor(id));\n    }\n\n    function _stakeOf(address account) internal view virtual returns (uint256);\n\n    function _collectCandidacyFee(address payer) internal virtual;\n\n    function _isProposable(bytes4 selector) internal view virtual returns (bool) {\n        return selector == this.setSenateSize.selector || selector == this.setVotingPeriod.selector;\n    }\n\n    function _afterExecute(uint256 id) internal virtual {}\n\n    function _register(address account) internal {\n        require(!_registered[account], AlreadyRegistered(account));\n\n        _registered[account] = true;\n        _collectCandidacyFee(account);\n\n        emit Registered(account);\n\n        _onStakeChanged(account);\n    }\n\n    function _onStakeChanged(address account) internal {\n        if (!_registered[account]) {\n            return;\n        }\n\n        uint256 stake = _stakeOf(account);\n\n        if (!_listed[account]) {\n            if (stake == 0) {\n                return;\n            }\n            if (_listLength == LIST_CAP) {\n                address last = _tail;\n                if (stake <= _nodes[last].stake) {\n                    return;\n                }\n                _unlink(last);\n                emit Unranked(last);\n            }\n            _link(account, stake, _tail, false);\n            emit Ranked(account, stake);\n            return;\n        }\n\n        if (stake == 0) {\n            _unlink(account);\n            emit Unranked(account);\n            return;\n        }\n\n        Node storage node = _nodes[account];\n        uint256 previous = node.stake;\n        if (stake == previous) {\n            return;\n        }\n\n        address prev = node.prev;\n        address next = node.next;\n        if (stake > previous && prev != address(0) && stake > _nodes[prev].stake) {\n            _unlink(account);\n            _link(account, stake, prev, false);\n        } else if (stake < previous && next != address(0) && stake < _nodes[next].stake) {\n            _unlink(account);\n            _link(account, stake, next, true);\n        } else {\n            node.stake = stake;\n        }\n\n        emit Ranked(account, stake);\n    }\n\n    function _link(address account, uint256 stake, address hint, bool aboveEquals) private {\n        address above = hint;\n        while (above != address(0) && _nodes[above].stake < stake) {\n            above = _nodes[above].prev;\n        }\n        address next = above == address(0) ? _head : _nodes[above].next;\n        while (next != address(0) && (_nodes[next].stake > stake || (!aboveEquals && _nodes[next].stake == stake))) {\n            above = next;\n            next = _nodes[next].next;\n        }\n\n        _nodes[account] = Node({prev: above, next: next, stake: stake});\n\n        if (above == address(0)) {\n            _head = account;\n        } else {\n            _nodes[above].next = account;\n        }\n        if (next == address(0)) {\n            _tail = account;\n        } else {\n            _nodes[next].prev = account;\n        }\n\n        _listed[account] = true;\n        _listLength += 1;\n    }\n\n    function _unlink(address account) private {\n        Node memory node = _nodes[account];\n\n        if (node.prev == address(0)) {\n            _head = node.next;\n        } else {\n            _nodes[node.prev].next = node.next;\n        }\n        if (node.next == address(0)) {\n            _tail = node.prev;\n        } else {\n            _nodes[node.next].prev = node.prev;\n        }\n\n        delete _nodes[account];\n        _listed[account] = false;\n        _listLength -= 1;\n    }\n\n    function _isPassed(uint256 support) private view returns (bool) {\n        return support * 2 > senateSize;\n    }\n\n    function _state(Proposal storage proposal) private view returns (ProposalState) {\n        if (proposal.executed) {\n            return ProposalState.Executed;\n        }\n        if (proposal.cancelled) {\n            return ProposalState.Cancelled;\n        }\n        if (block.timestamp > proposal.deadline) {\n            return ProposalState.Expired;\n        }\n        return ProposalState.Open;\n    }\n\n    function _requireProposal(uint256 id) private view returns (Proposal storage proposal) {\n        proposal = _proposals[id];\n        require(proposal.proposer != address(0), NonexistentProposal(id));\n    }\n\n    function _requireOpen(uint256 id) private view returns (Proposal storage proposal) {\n        proposal = _requireProposal(id);\n        ProposalState current = _state(proposal);\n        require(current == ProposalState.Open, ProposalNotOpen(id, current));\n    }\n}\n"},{"file_path":"project/contracts/interfaces/IFreezeHook.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @dev Receiver of freezing notifications from a {Freezer}.\n */\ninterface IFreezeHook {\n    /**\n     * @dev Called by the freezer after each deposit is recorded. A revert here reverts\n     * the deposit, so implementations must decline quietly instead of reverting.\n     * `firstFreezeAt` is the depositor's first-ever deposit time.\n     */\n    function onFreeze(address owner, address referrer, uint256 amount, uint256 firstFreezeAt) external;\n}\n"},{"file_path":"project/contracts/interfaces/ITokenSource.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @dev A contract whose accounting is denominated in a single primary ERC20 token.\n */\ninterface ITokenSource {\n    /**\n     * @dev Returns the primary token this contract operates on.\n     */\n    function token() external view returns (IERC20);\n}\n"},{"file_path":"project/contracts/interfaces/dex/INonfungiblePositionManager.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @dev The Uniswap v3 / PancakeSwap v3 position manager.\n */\ninterface INonfungiblePositionManager {\n    /**\n     * @dev Parameters of {mint}. `token0`, `token1` and `fee` identify the pool;\n     * `tickLower`/`tickUpper` set the range; the `Desired` amounts are offered and the `Min`\n     * amounts are the least the call may consume; `recipient` gets the NFT.\n     */\n    struct MintParams {\n        address token0;\n        address token1;\n        uint24 fee;\n        int24 tickLower;\n        int24 tickUpper;\n        uint256 amount0Desired;\n        uint256 amount1Desired;\n        uint256 amount0Min;\n        uint256 amount1Min;\n        address recipient;\n        uint256 deadline;\n    }\n\n    /**\n     * @dev Parameters of {increaseLiquidity}: the position, the amounts offered and the least\n     * amounts the call may consume.\n     */\n    struct IncreaseLiquidityParams {\n        uint256 tokenId;\n        uint256 amount0Desired;\n        uint256 amount1Desired;\n        uint256 amount0Min;\n        uint256 amount1Min;\n        uint256 deadline;\n    }\n\n    /**\n     * @dev Parameters of {decreaseLiquidity}: the position, the liquidity to remove and the\n     * least principal it must release.\n     */\n    struct DecreaseLiquidityParams {\n        uint256 tokenId;\n        uint128 liquidity;\n        uint256 amount0Min;\n        uint256 amount1Min;\n        uint256 deadline;\n    }\n\n    /**\n     * @dev Parameters of {collect}: the position, the receiver and caps on how much of what\n     * is owed to take.\n     */\n    struct CollectParams {\n        uint256 tokenId;\n        address recipient;\n        uint128 amount0Max;\n        uint128 amount1Max;\n    }\n\n    /**\n     * @dev Creates a position and mints its NFT to `recipient`; returns the token id, the\n     * liquidity and the amounts actually consumed.\n     */\n    function mint(\n        MintParams calldata params\n    ) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);\n\n    /**\n     * @dev Adds liquidity to an existing position. Checks no ownership: anyone paying the tokens\n     * tops up whosever NFT it is — callers guard the owner themselves.\n     */\n    function increaseLiquidity(\n        IncreaseLiquidityParams calldata params\n    ) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1);\n\n    /**\n     * @dev Removes liquidity and returns the principal released; transfers nothing — the amounts\n     * become owed to the position and are paid by {collect}.\n     */\n    function decreaseLiquidity(\n        DecreaseLiquidityParams calldata params\n    ) external payable returns (uint256 amount0, uint256 amount1);\n\n    /**\n     * @dev Transfers what the position is owed — released principal plus accrued fees — and\n     * returns what was actually paid.\n     */\n    function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);\n\n    /**\n     * @dev Burns the NFT of a position holding no liquidity and nothing owed.\n     */\n    function burn(uint256 tokenId) external payable;\n\n    /**\n     * @dev Returns the owner of position `tokenId` (plain ERC721).\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Returns the full book of position `tokenId`: the pool, the range, the liquidity and\n     * what it is owed.\n     */\n    function positions(\n        uint256 tokenId\n    )\n        external\n        view\n        returns (\n            uint96 nonce,\n            address operator,\n            address token0,\n            address token1,\n            uint24 fee,\n            int24 tickLower,\n            int24 tickUpper,\n            uint128 liquidity,\n            uint256 feeGrowthInside0LastX128,\n            uint256 feeGrowthInside1LastX128,\n            uint128 tokensOwed0,\n            uint128 tokensOwed1\n        );\n}\n"},{"file_path":"project/contracts/interfaces/dex/IPoolManager.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @dev The Uniswap v4 `PoolManager`.\n */\ninterface IPoolManager {\n    /**\n     * @dev Identifies a pool: the two tokens sorted by address, the fee tier, its tick spacing\n     * and the hooks contract (zero for a hookless pool).\n     */\n    struct PoolKey {\n        address currency0;\n        address currency1;\n        uint24 fee;\n        int24 tickSpacing;\n        address hooks;\n    }\n\n    /**\n     * @dev Parameters of {modifyLiquidity}: the tick range, the signed amount of liquidity to\n     * add or remove, and a salt separating positions of one owner on the same range.\n     */\n    struct ModifyLiquidityParams {\n        int24 tickLower;\n        int24 tickUpper;\n        int256 liquidityDelta;\n        bytes32 salt;\n    }\n\n    /**\n     * @dev Parameters of {swap}: `zeroForOne` picks the direction (true sells currency0),\n     * `amountSpecified` is negative for exact input and positive for exact output,\n     * `sqrtPriceLimitX96` is the price at which the swap stops.\n     */\n    struct SwapParams {\n        bool zeroForOne;\n        int256 amountSpecified;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /**\n     * @dev Opens the manager for the duration of one call to `msg.sender`'s `unlockCallback(data)`;\n     * all pool operations happen inside, and every balance must be settled before it returns.\n     */\n    function unlock(bytes calldata data) external returns (bytes memory);\n\n    /**\n     * @dev Adds or removes liquidity. `callerDelta` is the full balance change including fees,\n     * `feesAccrued` the fee part alone.\n     */\n    function modifyLiquidity(\n        PoolKey memory key,\n        ModifyLiquidityParams memory params,\n        bytes calldata hookData\n    ) external returns (int256 callerDelta, int256 feesAccrued);\n\n    /**\n     * @dev Swaps within one pool and returns the resulting balance delta.\n     */\n    function swap(PoolKey memory key, SwapParams memory params, bytes calldata hookData) external returns (int256 swapDelta);\n\n    /**\n     * @dev Snapshots the manager's balance of `currency` so the next {settle} can measure what was paid in.\n     */\n    function sync(address currency) external;\n\n    /**\n     * @dev Settles a debt with the tokens transferred in since {sync}; returns the amount credited.\n     */\n    function settle() external payable returns (uint256 paid);\n\n    /**\n     * @dev Pays out `amount` of `currency` owed to the caller.\n     */\n    function take(address currency, address to, uint256 amount) external;\n\n    /**\n     * @dev Reads a raw storage slot of the manager.\n     */\n    function extsload(bytes32 slot) external view returns (bytes32 value);\n}\n\n/**\n * @dev Implemented by callers of {IPoolManager.unlock}; the manager calls back with the same `data`.\n */\ninterface IUnlockCallback {\n    function unlockCallback(bytes calldata data) external returns (bytes memory);\n}\n"},{"file_path":"project/contracts/interfaces/dex/IUniswapV3Factory.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @dev Uniswap v3 and PancakeSwap v3 factories share this call.\n */\ninterface IUniswapV3Factory {\n    /**\n     * @dev Returns the pool for a pair and fee tier, zero when none exists; token order is free.\n     */\n    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);\n}\n"},{"file_path":"project/contracts/interfaces/dex/IV3SwapRouter.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.28;\n\n/**\n * @dev Uniswap `SwapRouter02` and PancakeSwap `SmartRouter` single-pool swap.\n */\ninterface IV3SwapRouter {\n    /**\n     * @dev Parameters of {exactInputSingle}. `tokenIn`, `tokenOut` and `fee` identify the pool;\n     * `recipient` receives the output; `amountIn` is the input to spend, zero meaning the\n     * router's own balance; `amountOutMinimum` is the least acceptable output;\n     * `sqrtPriceLimitX96` bounds the price, zero for no bound.\n     */\n    struct ExactInputSingleParams {\n        address tokenIn;\n        address tokenOut;\n        uint24 fee;\n        address recipient;\n        uint256 amountIn;\n        uint256 amountOutMinimum;\n        uint160 sqrtPriceLimitX96;\n    }\n\n    /**\n     * @dev Swaps an exact input within one pool and returns the output amount.\n     */\n    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"contract IERC20Metadata","name":"token_","type":"address"},{"internalType":"uint256","name":"dexSellCap_","type":"uint256"},{"internalType":"address","name":"freezeHook_","type":"address"},{"internalType":"address","name":"freezerMarket_","type":"address"},{"internalType":"address","name":"dexModule_","type":"address"},{"components":[{"internalType":"address","name":"usdt","type":"address"},{"internalType":"address","name":"usdc","type":"address"},{"internalType":"address","name":"wbtc","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"uniV3Factory","type":"address"},{"internalType":"address","name":"uniV3PositionManager","type":"address"},{"internalType":"address","name":"uniV3Router","type":"address"},{"internalType":"address","name":"pancakeV3Factory","type":"address"},{"internalType":"address","name":"pancakeV3PositionManager","type":"address"},{"internalType":"address","name":"pancakeV3Router","type":"address"},{"internalType":"address","name":"uniV4PoolManager","type":"address"}],"internalType":"struct DexBase.Config","name":"dex","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"AddressWithoutCode","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"AlreadyLocked","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AlreadyRegistered","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"voter","type":"address"}],"name":"AlreadyVoted","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"}],"name":"AmountBelowMin","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"AmountExceedsMax","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"availableAt","type":"uint256"}],"name":"ClaimTooEarly","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"DescriptionTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"sold","type":"uint256"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"DexSellCapExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ForeignPosition","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"lockedTill","type":"uint256"}],"name":"FrostLocked","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"FrostNotLocked","type":"error"},{"inputs":[{"internalType":"address","name":"hooks","type":"address"}],"name":"HookedPool","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"IncorrectOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientFrost","type":"error"},{"inputs":[{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InvalidCalldata","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"InvalidListLength","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"InvalidReceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"InvalidSenateSize","type":"error"},{"inputs":[{"internalType":"uint8","name":"tier","type":"uint8"}],"name":"InvalidTier","type":"error"},{"inputs":[{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"InvalidVotingPeriod","type":"error"},{"inputs":[],"name":"LockTillInPast","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"NoModule","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"NonexistentFrost","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"NonexistentId","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"NonexistentProposal","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint8","name":"newTier","type":"uint8"}],"name":"NotAnUpgrade","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"NotApproved","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"votesFor","type":"uint256"},{"internalType":"uint256","name":"seats","type":"uint256"}],"name":"NotPassed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotPoolManager","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"NotProposable","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"proposer","type":"address"}],"name":"NotProposer","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotRegistered","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotSelf","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotSenate","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotSenator","type":"error"},{"inputs":[{"internalType":"enum DexBase.Dex","name":"dex","type":"uint8"}],"name":"NotV3","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"OnlyMarketAccess","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotPermitted","type":"error"},{"inputs":[],"name":"PoolNotFound","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"enum Senate.ProposalState","name":"state","type":"uint8"}],"name":"ProposalNotOpen","type":"error"},{"inputs":[],"name":"RewardsDepleted","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SamePair","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SameValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"unfreezeAt","type":"uint256"}],"name":"StillFrozen","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint8","name":"expected","type":"uint8"}],"name":"TierMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TokenNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"TooManyFrosts","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"frozen","type":"uint256"}],"name":"TreasuryBelowFrozen","type":"error"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"UnknownPosition","type":"error"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"UnsortedPair","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroDexAddress","type":"error"},{"inputs":[],"name":"ZeroDexAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"CandidacyFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimAmount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"FrostChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"FrostCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"FrostRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8","name":"tier","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Frozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"lockedFor","type":"address"},{"indexed":false,"internalType":"uint256","name":"till","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"intoId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8","name":"tier","type":"uint8"}],"name":"Merged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorApproveRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProposalCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":false,"internalType":"uint256","name":"votesFor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"senateSize","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"senators","type":"address[]"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"}],"name":"Ranked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint8","name":"tier","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Returned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSize","type":"uint256"}],"name":"SenateSizeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DexBase.Dex","name":"dex","type":"uint8"},{"indexed":true,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"remainderId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint8","name":"tier","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"frozenAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedTill","type":"uint256"}],"name":"Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8","name":"tier","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"left","type":"uint256"}],"name":"Unfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Unlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Unranked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8","name":"fromTier","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"toTier","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"frozenAt","type":"uint256"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DexBase.Dex","name":"dex","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees1","type":"uint256"},{"indexed":false,"internalType":"bool","name":"burned","type":"bool"}],"name":"V3Decreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DexBase.Dex","name":"dex","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"V3Increased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum DexBase.Dex","name":"dex","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"token0","type":"address"},{"indexed":false,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":false,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"V3Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"int256","name":"liquidityDelta","type":"int256"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees1","type":"uint256"}],"name":"V4Modified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"V4PositionClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"positionId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"currency0","type":"address"},{"indexed":false,"internalType":"address","name":"currency1","type":"address"},{"indexed":false,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":false,"internalType":"int24","name":"tickSpacing","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"V4PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"bool","name":"support","type":"bool"}],"name":"Voted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPeriod","type":"uint256"}],"name":"VotingPeriodChanged","type":"event"},{"inputs":[],"name":"CLAIM_COOLDOWN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DENOM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIST_CAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DESCRIPTION_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FROSTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SENATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_VOTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SENATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_VOTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIERS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YEAR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeFrosts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeFrostsByTier","outputs":[{"internalType":"uint256[]","name":"out","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"tier","type":"uint8"}],"name":"activeFrostsIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"applyForSenate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"approveOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"availableRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"candidacyFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dexModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dexSellCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dexSellLeft","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dexSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"}],"name":"freeze","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"freezeHook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"freezerMarket","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"frozenByTierOf","outputs":[{"internalType":"uint256[]","name":"out","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"frozenOf","outputs":[{"internalType":"uint256","name":"total","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getAccount","outputs":[{"components":[{"internalType":"uint256","name":"accruedNum","type":"uint256"},{"internalType":"uint256","name":"lastAccrualAt","type":"uint256"},{"internalType":"uint256","name":"lastClaimAt","type":"uint256"},{"internalType":"uint256","name":"firstFreezeAt","type":"uint256"},{"internalType":"uint256","name":"frostCount","type":"uint256"},{"internalType":"uint256","name":"frozenTotal","type":"uint256"}],"internalType":"struct Freezer.AccountView","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getFrost","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"frozenAt","type":"uint256"},{"internalType":"uint256","name":"ownedAt","type":"uint256"},{"internalType":"uint256","name":"unfreezeAt","type":"uint256"},{"internalType":"uint256","name":"lockedTill","type":"uint256"},{"internalType":"address","name":"lockedFor","type":"address"}],"internalType":"struct Freezer.FrostView","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"getFrosts","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"frozenAt","type":"uint256"},{"internalType":"uint256","name":"ownedAt","type":"uint256"},{"internalType":"uint256","name":"unfreezeAt","type":"uint256"},{"internalType":"uint256","name":"lockedTill","type":"uint256"},{"internalType":"address","name":"lockedFor","type":"address"}],"internalType":"struct Freezer.FrostView[]","name":"out","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getProposal","outputs":[{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"cancelled","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct Senate.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isAllowedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isListed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isPassed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSenator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"listedStakeOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"lockTill","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"lockTillOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"lockedForOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"merge","outputs":[{"internalType":"uint256","name":"newId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextFrostId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"pendingOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"string","name":"description","type":"string"}],"name":"propose","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ranked","outputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"stakes","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"refresh","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"returnLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"revokeOperatorApprove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"senateSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"senators","outputs":[{"internalType":"address[]","name":"out","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"size","type":"uint256"}],"name":"setSenateSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"period","type":"uint256"}],"name":"setVotingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"state","outputs":[{"internalType":"enum Senate.ProposalState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint8","name":"tier","type":"uint8"}],"name":"tierTotalOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tiers","outputs":[{"components":[{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint256","name":"term","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"}],"internalType":"struct Freezer.TierInfo[]","name":"out","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFrozen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFrozenByTier","outputs":[{"internalType":"uint256[]","name":"out","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"tier","type":"uint8"}],"name":"totalFrozenIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"transferPart","outputs":[{"internalType":"uint256","name":"remainderId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"unfreeze","outputs":[{"internalType":"uint256","name":"released","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unfreezeAtOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unfreezeOne","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"unlockCallback","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint8","name":"newTier","type":"uint8"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum DexBase.Dex","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"v3Decrease","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum DexBase.Dex","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"v3Increase","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum DexBase.Dex","name":"dex","type":"uint8"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct DexBase.V3MintParams","name":"","type":"tuple"}],"name":"v3Mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum DexBase.Dex","name":"","type":"uint8"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint24","name":"","type":"uint24"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"v3Swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"v4Decrease","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency0","type":"address"},{"internalType":"address","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"address","name":"hooks","type":"address"}],"internalType":"struct IPoolManager.PoolKey","name":"","type":"tuple"},{"internalType":"int24","name":"","type":"int24"},{"internalType":"int24","name":"","type":"int24"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"v4Increase","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"positionId","type":"bytes32"}],"name":"v4PositionOf","outputs":[{"components":[{"components":[{"internalType":"address","name":"currency0","type":"address"},{"internalType":"address","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"address","name":"hooks","type":"address"}],"internalType":"struct IPoolManager.PoolKey","name":"key","type":"tuple"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct DexBase.V4Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"currency0","type":"address"},{"internalType":"address","name":"currency1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"address","name":"hooks","type":"address"}],"internalType":"struct IPoolManager.PoolKey","name":"","type":"tuple"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"v4Swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"support","type":"bool"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"voter","type":"address"}],"name":"voteOf","outputs":[{"internalType":"enum Senate.Vote","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"votesFor","outputs":[{"internalType":"uint256","name":"support","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000100a2c7f45fd48e217fdce72e658dc78fd43a100000000000000000000000000000000000000000000000000000000e8d4a51000000000000000000000000000fa9d2a61f80772baafdda87082ffcea0232df738000000000000000000000000c9e1b391835fd27385f0394bee1a1cc86a46a325000000000000000000000000cd5762ac6013fa762782ac1797ab09152c1028e8000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe8800000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc450000000000000000000000000bfbcf9fa4f9c56b0f40a671ad40e0805a09186500000000000000000000000046a15b0b27311cedf172ab29e4f4766fbe7f436400000000000000000000000013f4ea83d0bd40e75c8222255bc855a974568dd4000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90"}