{"file_path":"src/USG/Market/StakeDao/StakeDaoVaultV2Market.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport {GlobalMarketInitParams, MarketInit} from \"../../../interfaces/internals/USG/IMarketCore.sol\";\nimport {IStakeDaoVaultV2} from \"../../../interfaces/externals/StakeDao/IStakeDaoVaultV2.sol\";\nimport {IAccountant} from \"../../../interfaces/externals/StakeDao/IAccountant.sol\";\n\nimport {MarketExternalActions} from \"../abstract/MarketExternalActions.sol\";\nimport {TokenAmount} from \"../../../interfaces/internals/ICommonStruct.sol\";\n\n/// @title  StakeDaoVaultV2Market\n/// @author Tangent Finance\n/// @notice Lending Market of a StakeDao Vault boosting CRV rewards of a Curve LP.\ncontract StakeDaoVaultV2Market is MarketExternalActions {\n    address public receiptToken;\n    IAccountant constant accountant = IAccountant(0x93b4B9bd266fFA8AF68e39EDFa8cFe2A62011Ce0);\n\n    error WrongVaultToken();\n    function initialize(GlobalMarketInitParams memory _marketConstants, MarketInit memory _marketInit, address _receipt) external {\n        // Common\n        _initializationCommon(_marketConstants, _marketInit);\n        require(IStakeDaoVaultV2(_receipt).asset() == address(collatToken), WrongVaultToken());\n\n        collatToken.approve(address(_receipt), MAX_UINT);\n        receiptToken = _receipt;\n    }\n\n    function _transferCollateralDeposit(uint256 collatToDeposit, bool isReceiptIn) internal override {\n        IERC20 _tokenIn = isReceiptIn ? IERC20(receiptToken) : collatToken;\n        _tokenIn.transferFrom(msg.sender, address(this), collatToDeposit);\n    }\n\n    function _postDeposit(IERC20 _collatToken) internal override {\n        uint256 collatBalance = _collatToken.balanceOf(address(this));\n        if (collatBalance != 0) {\n            // Deposit the whole balance of LP into the StakeDao Vault\n            IStakeDaoVaultV2(receiptToken).deposit(collatBalance, address(this), controlTower.feeTreasury());\n        }\n    }\n\n    function _transferCollateralWithdraw(address to, uint256 collatToWithdraw, bool isReceipt) internal override {\n        if (isReceipt) {\n            // Transfer the vault token to receiver\n            IStakeDaoVaultV2(receiptToken).transfer(to, collatToWithdraw);\n        } else {\n            // Withdraw the LP from the Vault to the receiver\n            IStakeDaoVaultV2(receiptToken).withdraw(collatToWithdraw, to, address(this));\n        }\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        CLAIM  \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    function _claimRewards() internal override {\n        address[] memory gauges = new address[](1);\n        gauges[0] = address(IStakeDaoVaultV2(receiptToken).gauge());\n\n        // When nothing is claimable, accountant.claim() revert\n        // However, to be able to change reward cut, we want to be able to call processRewards at any moment.\n        try accountant.claim(gauges, new bytes[](1)) {} catch {}\n    }\n\n    /**\n     * @notice Claim the extra rewards from StakeDao Vault.\n     *         Extra rewards can be CVX ( from OnlyBoost and Convex ) or any other rewards streamed in the vault\n     */\n    function claimExtraRewards(address[] calldata rewards) external nonReentrant {\n        // Claim the extra rewards\n        IStakeDaoVaultV2(receiptToken).claim(rewards, address(this));\n    }\n}\n","deployed_bytecode":"0x608060405260043610610324575f3560e01c80637ed57d47116101a7578063bb66baeb116100e7578063ec78e83211610092578063f384bd051161006d578063f384bd051461092b578063fd0526f914610940578063fe45fe1714610998578063fef0bec8146109b7575f5ffd5b8063ec78e832146108cc578063f2fcad12146108f8578063f2fde38b1461090c575f5ffd5b8063ce1ad4f1116100c2578063ce1ad4f114610862578063d0b0c81614610881578063ec60b844146108a0575f5ffd5b8063bb66baeb1461081b578063bbcac5571461082e578063c3d5f5e614610843575f5ffd5b806395043df711610152578063a043d6d71161012d578063a043d6d7146107b2578063a36a3630146107de578063ab60577a146107f3578063b8a8badf14610808575f5ffd5b806395043df71461075f57806398d34e941461077e5780639bd6012f1461079d575f5ffd5b80638da5cb5b116101825780638da5cb5b146106dd5780639198e8401461070857806394ee082714610733575f5ffd5b80637ed57d47146106735780638574a20914610692578063873c0e39146106be575f5ffd5b806327f9f2cf116102725780634031234c1161021d5780635c57f6d8116101f85780635c57f6d8146106005780636a959886146106155780636aebf6301461064157806378477edc14610654575f5ffd5b80634031234c146105b75780634ac8eb5f146105cc5780634b8a3529146105e1575f5ffd5b806338d074361161024d57806338d07436146105285780633d07b176146105475780633edd112814610598575f5ffd5b806327f9f2cf146104ca57806329bc969d146104de5780632d0f9abe14610509575f5ffd5b806314211c53116102d257806321fc7ffc116102ad57806321fc7ffc1461047957806322867d78146104985780632395ed2e146104b7575f5ffd5b806314211c53146104265780631a186127146104455780631b859e4114610464575f5ffd5b806308a0c3751161030257806308a0c375146103d55780630ac89759146103f4578063129bc8f014610413575f5ffd5b806303c6c0b614610328578063062d8bc71461038757806306c46a58146103a8575b5f5ffd5b348015610333575f5ffd5b5061036d610342366004614ee8565b73ffffffffffffffffffffffffffffffffffffffff165f908152601260205260409020546011549091565b604080519283526020830191909152015b60405180910390f35b348015610392575f5ffd5b506103a66103a1366004614f03565b6109d6565b005b3480156103b3575f5ffd5b506103c76103c2366004614f1a565b610a1a565b60405190815260200161037e565b3480156103e0575f5ffd5b506103a66103ef366004614f03565b610b4e565b3480156103ff575f5ffd5b506103a661040e366004614f82565b610bc6565b6103a6610421366004614fe4565b610d5f565b348015610431575f5ffd5b506103a661044036600461502b565b610eb4565b348015610450575f5ffd5b506103a661045f366004614ee8565b610fe7565b34801561046f575f5ffd5b506103c760085481565b348015610484575f5ffd5b506103a6610493366004615311565b611062565b3480156104a3575f5ffd5b506103a66104b23660046153e6565b611250565b6103a66104c5366004615410565b611302565b3480156104d5575f5ffd5b506103a66114a5565b3480156104e9575f5ffd5b506103c76104f8366004614ee8565b60126020525f908152604090205481565b348015610514575f5ffd5b506103a6610523366004615487565b6114b7565b348015610533575f5ffd5b506103a66105423660046154f8565b611582565b348015610552575f5ffd5b50600c546105739073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161037e565b3480156105a3575f5ffd5b506103a66105b2366004615526565b611674565b3480156105c2575f5ffd5b506103c7600f5481565b3480156105d7575f5ffd5b506103c760115481565b3480156105ec575f5ffd5b506103a66105fb3660046153e6565b6117a8565b34801561060b575f5ffd5b506103c760055481565b348015610620575f5ffd5b506013546105739073ffffffffffffffffffffffffffffffffffffffff1681565b6103a661064f36600461555a565b61184d565b34801561065f575f5ffd5b506103a661066e366004615591565b611951565b34801561067e575f5ffd5b506103a661068d366004614f03565b611ab2565b34801561069d575f5ffd5b506106b16106ac3660046155c7565b611b53565b60405161037e91906155f9565b3480156106c9575f5ffd5b506103a66106d836600461565d565b611c8b565b3480156106e8575f5ffd5b505f546105739073ffffffffffffffffffffffffffffffffffffffff1681565b348015610713575f5ffd5b506103c7610722366004614ee8565b60096020525f908152604090205481565b34801561073e575f5ffd5b50600b546105739073ffffffffffffffffffffffffffffffffffffffff1681565b34801561076a575f5ffd5b506103a661077936600461502b565b611d9a565b348015610789575f5ffd5b506103a661079836600461568f565b611e96565b3480156107a8575f5ffd5b506103c7600a5481565b3480156107bd575f5ffd5b506003546105739073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107e9575f5ffd5b506103c760105481565b3480156107fe575f5ffd5b506103c760065481565b6103a66108163660046156cc565b61215f565b6103a661082936600461555a565b6122c6565b348015610839575f5ffd5b506103c760075481565b34801561084e575f5ffd5b506103a661085d366004614f03565b612421565b34801561086d575f5ffd5b506103a661087c366004615721565b61245e565b34801561088c575f5ffd5b506103a661089b366004614f03565b612599565b3480156108ab575f5ffd5b50600d546105739073ffffffffffffffffffffffffffffffffffffffff1681565b3480156108d7575f5ffd5b506014546105739073ffffffffffffffffffffffffffffffffffffffff1681565b348015610903575f5ffd5b5061057361264d565b348015610917575f5ffd5b506103a6610926366004614ee8565b61267b565b348015610936575f5ffd5b506103c7600e5481565b34801561094b575f5ffd5b506002546040805167ffffffffffffffff8084168252680100000000000000008404811660208301527001000000000000000000000000000000009093049092169082015260600161037e565b3480156109a3575f5ffd5b506103a66109b2366004614ee8565b6126e0565b3480156109c2575f5ffd5b506103a66109d1366004614f03565b612862565b6109de6128dc565b60058190556040518181527f0937edcd92487438a2b500669f3c2b5145a80d7e0390d321137ee08da1e5d81c906020015b60405180910390a150565b5f610a2361292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8781165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015288929190911690634a9bd802906064015f604051808303815f87803b158015610aaf575f5ffd5b505af1158015610ac1573d5f5f3e3d5ffd5b505050505f5f610ad489898989896129b4565b604080518b8152602081018b905290810189905260608101829052919350915073ffffffffffffffffffffffffffffffffffffffff8a16907f20843bedc56d43973249c6823b8ab2e5ea90894751a5120b2f41742835d80c199060800160405180910390a250915050610b45612b23565b95945050505050565b610b566128dc565b600f548110610b91576040517fb6aa88a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8190556040518181527f6ad6c0ca92bb285e6f642e202af7fcd6377e3b6fd6dda78384c4e3e24acc3d2a90602001610a0f565b610bce61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015610c5a575f5ffd5b505af1158015610c6c573d5f5f3e3d5ffd5b505050505f610c7a33612b4d565b90505f5f610cdd6040518060e0016040528088803603810190610c9d91906157d2565b8152602001855f01518152602001856020015181526020016011548152602001856040015181526020016008548152602001856060015181525086612be5565b9092509050337f1548292c70c1a3db5c87d3e6c926b6d456017b86ee5c4d3113ee5de211cd898183838935610d1560208b018b614ee8565b6040805194855260208501939093529183015273ffffffffffffffffffffffffffffffffffffffff1660608201526080015b60405180910390a250505050610d5b612b23565b5050565b610d6761292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015610df3575f5ffd5b505af1158015610e05573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff1691505f9050610e30848330612d41565b90505f610e3f8287855f612f2d565b9050337faebe32d9b5f423f063ee6c4998222119fce5d9f8eedf5280bf8b84cd50a5aca4838884610e7360208b018b614ee8565b6040805194855260208581019490945284019190915273ffffffffffffffffffffffffffffffffffffffff166060830152880135608082015260a001610d47565b610ebc61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015610f48575f5ffd5b505af1158015610f5a573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff169150610f8390508584612f9b565b5f610f908686845f612f2d565b604080518881526020810188905290810182905290915033907fa9535af9dc0ff2e9e0c8f578d8f9aafb7fecdd1566ac257aad5c7d3fabec12e6906060015b60405180910390a2505050610fe2612b23565b505050565b610fef6128dc565b600c80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd3b5d1e0ffaeff528910f3663f0adace7694ab8241d58e17a91351ced2e0803190602001610a0f565b61106c8383613077565b600b54604080517f38d52e0f000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff928316928416916338d52e0f9160048083019260209291908290030181865afa1580156110dc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061110091906157ec565b73ffffffffffffffffffffffffffffffffffffffff161461114d576040517f50e6a09c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301529091169063095ea7b3906044016020604051808303815f875af11580156111e2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112069190615807565b50601480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b61125861292e565b5f5f5f6112658585613355565b5092509250925061129d85838373ffffffffffffffffffffffffffffffffffffffff9092165f90815260096020526040902055600855565b604080513381526020810185905290810183905273ffffffffffffffffffffffffffffffffffffffff8616907fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e0906060015b60405180910390a2505050610d5b612b23565b61130a61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611396575f5ffd5b505af11580156113a8573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff1691505f90506113d3848330612d41565b90505f5f5f6114058560405180608001604052808781526020018d81526020018c81526020015f15158152508a613489565b91945092509050337fd35d526454c24890c99712173c621bbc95962d51143051ed7782a2c37aa82bd78386868e8661144060208f018f614ee8565b604080519687526020878101969096528601939093526060850191909152608084015273ffffffffffffffffffffffffffffffffffffffff1660a08301528a013560c082015260e00160405180910390a250505050505061149f612b23565b50505050565b6114ad6135fd565b6114b5612b23565b565b6114bf61292e565b6014546040517f25181bb000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906325181bb09061151990859085903090600401615822565b5f604051808303815f875af1158015611534573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611579919081019061589b565b50610d5b612b23565b61158a61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611616575f5ffd5b505af1158015611628573d5f5f3e3d5ffd5b5050505061163683836136c3565b60405183815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a250610d5b612b23565b61167c61292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8481165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015285929190911690634a9bd802906064015f604051808303815f87803b158015611708575f5ffd5b505af115801561171a573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff16915061174390508484612f9b565b61174e85858361373d565b8473ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c8560405161179691815260200190565b60405180910390a25050610fe2612b23565b6117b061292e565b335f9081526012602052604081205481906117cf9085908590846137c3565b335f908152600960205260409020829055600881905590925090506040805173ffffffffffffffffffffffffffffffffffffffff861681526020810185905290810183905233907fc1561b330e73faa7d5d1ac03c968d8f359b0191ccdb9cc002cf7d8eb6ae038cb9060600160405180910390a25050610d5b612b23565b61185561292e565b6004545f9061187c90839073ffffffffffffffffffffffffffffffffffffffff1633612d41565b90505f5f5f61188b8685613355565b509250925092506118c386838373ffffffffffffffffffffffffffffffffffffffff9092165f90815260096020526040902055600855565b73ffffffffffffffffffffffffffffffffffffffff86167f3f64dfb3813cd414050511f815ad02154fdfd1ec318508ed886c411c42eacb4633858561190b60208b018b614ee8565b6040805173ffffffffffffffffffffffffffffffffffffffff9586168152602080820195909552908101929092529092166060830152880135608082015260a001610d47565b61195961292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b1580156119e5575f5ffd5b505af11580156119f7573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff16915050833515611a3657611a368435611a31608087016060880161592c565b612f9b565b5f8080611a5284611a4c368a90038a018a615947565b88613489565b6040805183815260208082018690528c013581830152606081018390529051939650919450925033917f247b1d4a7d9e5a9db44e04d512cc546013c9d28034db34eb63abc908ca1bf0f99181900360800190a25050505050610d5b612b23565b611aba61292e565b60075480821115611af7576040517f6b8f3dc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b0182826159de565b600755611b0e338361388a565b60408051338152602081018490527f489f8907efd42611728dc7378e422a9f505a041b1b48831593145b62cc30cc3a910160405180910390a150611b50612b23565b50565b6060611b5d61292e565b600d545f80805260126020527f7e7fa33969761a458e04f477e039a608702b4f924981d6653935a8319a08ad7b546011546040517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101929092526044820152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611c01575f5ffd5b505af1158015611c13573d5f5f3e3d5ffd5b5050600d5473ffffffffffffffffffffffffffffffffffffffff1633149150611c6a9050576040517fc008bfc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c72613917565b611c7b83613a93565b915050611c86612b23565b919050565b611c9361292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8481165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015285929190911690634a9bd802906064015f604051808303815f87803b158015611d1f575f5ffd5b505af1158015611d31573d5f5f3e3d5ffd5b505050505f611d41858585613c6f565b604080518681526020810186905290810182905290915073ffffffffffffffffffffffffffffffffffffffff8616907f6c8724ad04a771490ffee385dfa3b678038e31a6fde3f32666c681b0b7443b2490606001611796565b611da261292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611e2e575f5ffd5b505af1158015611e40573d5f5f3e3d5ffd5b505050505f5f611e51868686613dad565b6040805189815260208101849052908101829052919350915033907f1d7597506f537c4ec23388b55909c8ca6a6a39bedb13fe958a7e2eba31f5d24e90606001610fcf565b611e9e61292e565b611eab6020830183614ee8565b600d5473ffffffffffffffffffffffffffffffffffffffff8281165f81815260126020526040908190205460115491517f4a9bd802000000000000000000000000000000000000000000000000000000008152600481019390935260248301526044820152911690634a9bd802906064015f604051808303815f87803b158015611f33575f5ffd5b505af1158015611f45573d5f5f3e3d5ffd5b505f9250611f629150611f5d90506020860186614ee8565b612b4d565b90505f611f6f6001613e03565b60608301519091507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9015611fff57620186a08360600151611fb191906159f1565b600f5483600a546012611fc491906159de565b611fcf90600a615b21565b8660200151611fde91906159f1565b611fe891906159f1565b611ff291906159f1565b611ffc9190615b59565b90505b670de0b6b3a76400008110612040576040517f1bad36df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f5f5f6120aa6040518061010001604052808c8036038101906120649190615b6c565b8152602001888152602001895f0151815260200189602001518152602001601154815260200189604001518152602001600854815260200189606001518152508a613e9c565b929650909450925090506120c160208b018b614ee8565b73ffffffffffffffffffffffffffffffffffffffff167fdde0adb27be857d0db946bcab48f6a9f4b90b721fa0672622d5ec3de019bee3e848385888e5f01602081019061210e9190614ee8565b60408051958652602086019490945292840191909152606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a00160405180910390a25050505050505050610d5b612b23565b61216761292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b1580156121f3575f5ffd5b505af1158015612205573d5f5f3e3d5ffd5b50506004545f92506122309150849073ffffffffffffffffffffffffffffffffffffffff1633612d41565b90505f5f61223f878488613dad565b9092509050337f249be7ccf5d800b92c9d775dcd88d9e1bbb1b26eac70852c203a0f79f4bf9a7088848461227660208b018b614ee8565b6040805194855260208581019490945284019190915273ffffffffffffffffffffffffffffffffffffffff166060830152880135608082015260a00160405180910390a250505050610fe2612b23565b6122ce61292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8381165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015284929190911690634a9bd802906064015f604051808303815f87803b15801561235a575f5ffd5b505af115801561236c573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff1691505f9050612397848330612d41565b90506123a485828461373d565b73ffffffffffffffffffffffffffffffffffffffff85167fe61106c51c4c591aeba5b8340c4271817aa7d1d2e8c360f568cea6aa43c7bc5c826123ea6020880188614ee8565b6040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083810191909152880135908201526060016112ef565b6124296128dc565b60068190556040518181527f0278b9e7389dd0abae8ab123abafedb45c523c7d6fa5aff191a6ed0541e0174e90602001610a0f565b612466614120565b5f82600281111561247957612479615bd5565b036124b757600280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831617905561255c565b60018260028111156124cb576124cb615bd5565b0361251457600280547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff84160217905561255c565b600280547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000067ffffffffffffffff8416021790555b7f4c47716be4fe501c50cc9446e3c627be438c5d4865413f0444fbb33d74f03218828260405161258d929190615c02565b60405180910390a15050565b6125a16128dc565b620186a081106125dd576040517f15f85eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e548111612618576040517f7c07cff900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8190556040518181527fde1cb344f21d9f06ecaf12cc8a2029fee63238f03db53e66234ce6f86c72a90390602001610a0f565b5f61265661292e565b61265e6135fd565b50600b5473ffffffffffffffffffffffffffffffffffffffff1690565b6126836128dc565b73ffffffffffffffffffffffffffffffffffffffff81166126d7576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024015b60405180910390fd5b611b50816141e6565b6126e861292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8281165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015283929190911690634a9bd802906064015f604051808303815f87803b158015612774575f5ffd5b505af1158015612786573d5f5f3e3d5ffd5b505050505f61279483612b4d565b905080606001516127aa8260200151600161425a565b106127e1576040517fd42d4f2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127ff83826020015160115484604001516008548660600151614275565b6060810151602080830151604080519384529183015273ffffffffffffffffffffffffffffffffffffffff8516917f0f175fe8ca3f35beba045eef36a95c6067ed110972d5fe4e104ade3e9e6f0403910160405180910390a25050611b50612b23565b61286a6128dc565b620138808111156128a7576040517fde61ab3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60108190556040518181527f76d62e6b12d0246e4dbc36a0207cb0bb2136ab4d758da9a4fadc4b09197bf41390602001610a0f565b5f5473ffffffffffffffffffffffffffffffffffffffff1633146114b5576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016126ce565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15612987576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114b560017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90614344565b5f5f6129be6135fd565b5f6129c761434b565b73ffffffffffffffffffffffffffffffffffffffff89165f908152600960205260408120549192506129fb828460016143dc565b73ffffffffffffffffffffffffffffffffffffffff8b165f9081526012602052604081205491925090612a2f908b906159de565b90505f5f898b1015612a6d576040517f6246601800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838b10612a8a57849150839a50838a10612a85578399505b612ab7565b612a958b875f6143fd565b9150612aa18b856159de565b9050612aac81614416565b612ab783825f614452565b5f612ac283876159de565b9050612aeb8e858f601154612ad791906159de565b8487600854612ae691906159de565b6144a4565b612af68a8e5f61450d565b8a15612b0657612b068e8c61388a565b612b108b8d6159de565b9e909d509b505050505050505050505050565b6114b55f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006129ae565b612b7460405180608001604052805f81526020015f81526020015f81526020015f81525090565b5f612b7d61434b565b73ffffffffffffffffffffffffffffffffffffffff84165f81815260096020908152604080832054815160808101835286815294845260128352928190205491840191909152820181905291925060608101612bdb838560016143dc565b9052949350505050565b8151515f908190612bf590614612565b83515160408501515f91612c08916159de565b85516020015160c08701519192505f918110612c3057505060c0850151608086015190612ca9565b612c3f8188602001515f6143fd565b91508015612c8057815f03612c80576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818860c00151612c9191906159de565b9050612c9c81614416565b612ca784825f614452565b505b5f828860800151612cba91906159de565b9050612ce833858a5f01515f01518b60600151612cd791906159de565b84878d60a00151612ae691906159de565b6040805160a0810182528951518152895160609081015160208301528a5183015192820192909252895151918101919091528851608090810151151590820152612d349083908961464b565b9097909650945050505050565b5f83602001355f03612d7f576040517f3133a04300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60135473ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee612dba6020870187614ee8565b73ffffffffffffffffffffffffffffffffffffffff1614612e46573415612e0d576040517f3133a04300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e41338260208801803590612e23908a614ee8565b73ffffffffffffffffffffffffffffffffffffffff1692919061483f565b612e83565b84602001353414612e83576040517f3133a04300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811663fb3eb4b634612ead6020890189614ee8565b8760408a013588612ec160608d018d615c54565b6040518763ffffffff1660e01b8152600401612ee1959493929190615d64565b60206040518083038185885af1158015612efd573d5f5f3e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190612f229190615ddb565b9150505b9392505050565b5f612f366148c8565b612f3f85614612565b335f90815260126020526040812054612f59908790615df2565b90505f5f612f69338885886137c3565b91509150612f8733848a601154612f809190615df2565b85856144a4565b612f908661490c565b509695505050505050565b5f81612fbf57600b5473ffffffffffffffffffffffffffffffffffffffff16612fd9565b60145473ffffffffffffffffffffffffffffffffffffffff165b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905290915073ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064015b6020604051808303815f875af1158015613053573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061149f9190615807565b60015474010000000000000000000000000000000000000000900467ffffffffffffffff16156130d3576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018054602084810151600480547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff938416179091556040870151740100000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000090951690831617939093179093556060808601516003805485169186169190911790556080860151600d8054851691861691909117905560a08601516013805485169186169190911790558451600b8054851691861691909117905590840151600c80549093169316929092179055810151620186a01161320a576040517f15f85eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015181606001511161324b576040517f7c07cff900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620138808160800151111561328c576040517fde61ab3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080820151600e556060820151600f55608082015160105560a082015160055560c0820151600655600b5481517f313ce567000000000000000000000000000000000000000000000000000000008152915173ffffffffffffffffffffffffffffffffffffffff9091169163313ce5679160048083019260209291908290030181865afa158015613320573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133449190615e05565b60ff16600a558151610d5b906141e6565b5f5f5f5f61336285614adf565b5f61336b61434b565b73ffffffffffffffffffffffffffffffffffffffff88165f9081526009602052604081205491925061339f828460016143dc565b9050815f036133da576040517fbe6b0c1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f5f838b106133f257839a505f9250849150613420565b6133fc8b856159de565b90506134098b875f6143fd565b915061341582866159de565b925061342081614416565b815f03613459576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613463338c61388a565b8a838360085461347391906159de565b919e909d50909b50909950975050505050505050565b5f5f5f6134946148c8565b600254700100000000000000000000000000000000900467ffffffffffffffff16156134ec576040517f8cb0972500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454601354602087015173ffffffffffffffffffffffffffffffffffffffff92831692909116906135219083908390614b18565b600b5460408089015190517ffb3eb4b60000000000000000000000000000000000000000000000000000000081525f9273ffffffffffffffffffffffffffffffffffffffff8086169363fb3eb4b69361358593899316919030908e90600401615d64565b6020604051808303815f875af11580156135a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135c59190615ddb565b90505f81895f01516135d79190615df2565b90505f6135eb828b602001518d6001612f2d565b929b919a509198509650505050505050565b6001546040517f1622c70f00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911690631622c70f90602401602060405180830381865afa158015613669573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061368d9190615807565b6114b5576040517f99277d1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6136cc61434b565b335f81815260096020526040902054919250613732916136f99086906136f4908660016143dc565b614ba0565b8560115461370791906159de565b60115573ffffffffffffffffffffffffffffffffffffffff9091165f90815260126020526040902055565b610fe233848461450d565b73ffffffffffffffffffffffffffffffffffffffff831661375c575f5ffd5b6137646148c8565b61376d82614612565b61377561434b565b5073ffffffffffffffffffffffffffffffffffffffff83165f908152601260205260409020546137ba9084906137ac908590615df2565b846011546137079190615df2565b610fe28161490c565b5f5f6137cd614bd1565b6137d685614adf565b5f6137df61434b565b335f908152600960205260408120549192506137fd828460016143dc565b6138079089615df2565b90505f613816898560016143fd565b90505f816008546138279190615df2565b90506138338186614c21565b61383c83614416565b61384789845f614452565b87613870576004546138709073ffffffffffffffffffffffffffffffffffffffff168c8c614b18565b61387a8285615df2565b9b909a5098505050505050505050565b600480546040517f936474cc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116938201939093526024810184905291169063936474cc906044015f604051808303815f87803b1580156138fd575f5ffd5b505af115801561390f573d5f5f3e3d5ffd5b505050505050565b6040805160018082528183019092525f91602080830190803683375050601454604080517fa6f19c84000000000000000000000000000000000000000000000000000000008152905193945073ffffffffffffffffffffffffffffffffffffffff9091169263a6f19c84925060048083019260209291908290030181865afa1580156139a5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139c991906157ec565b815f815181106139db576139db615e25565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160018082528183019092527393b4b9bd266ffa8af68e39edfa8cfe2a62011ce09263ef933df09285929182015b6060815260200190600190039081613a31579050506040518363ffffffff1660e01b8152600401613a63929190615e52565b5f604051808303815f87803b158015613a7a575f5ffd5b505af1925050508015613a8b575060015b15611b505750565b80516060905f8167ffffffffffffffff811115613ab257613ab2615061565b604051908082528060200260200182016040528015613af657816020015b604080518082019091525f8082526020820152815260200190600190039081613ad05790505b50600d5490915073ffffffffffffffffffffffffffffffffffffffff165f805b84811015613c54575f878281518110613b3157613b31615e25565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015613ba9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bcd9190615ddb565b90508015613c4a5760405180604001604052808373ffffffffffffffffffffffffffffffffffffffff16815260200182815250868580613c0c90615f64565b965081518110613c1e57613c1e615e25565b6020908102919091010152613c4a73ffffffffffffffffffffffffffffffffffffffff83168683614c75565b5050600101613b16565b50825115613c655780840383510383525b5090949350505050565b5f613c786135fd565b8215613c8657613c866148c8565b8115613c9457613c94614bd1565b5f613c9d61434b565b73ffffffffffffffffffffffffffffffffffffffff86165f9081526009602052604081205491925084613cd2838560016143dc565b613cdc9190615df2565b73ffffffffffffffffffffffffffffffffffffffff88165f9081526012602052604081205491925090613d10908890615df2565b90505f613d1f878660016143fd565b90505f81600854613d309190615df2565b90505f613d3d8387615df2565b90508415613d6357613d4e85614416565b613d5984865f614452565b613d638288614c21565b613d7d8b858c601154613d769190615df2565b84866144a4565b600b54613d9f9073ffffffffffffffffffffffffffffffffffffffff1661490c565b9a9950505050505050505050565b5f5f5f5f5f5f613dbd3389613355565b9350935093509350613de833613dd38b84614ba0565b8b601154613de191906159de565b86866144a4565b613df3338a8961450d565b509193509150505b935093915050565b600c546040517fafb4b04600000000000000000000000000000000000000000000000000000000815282151560048201525f9173ffffffffffffffffffffffffffffffffffffffff169063afb4b046906024016020604051808303815f875af1158015613e72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e969190615ddb565b92915050565b815160200151515f90819081908190613eb481614612565b5f5f88606001518310613ee257505050606086018051875160200151525160e087015160a088015190613f2b565b606089015160e08a0151613ef690856159f1565b613f009190615b59565b9050613f11818a604001515f6143fd565b9150613f2b818a60e00151613f2691906159de565b614416565b815f03613f64576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828a60a00151613f7591906159de565b8a515160608c0151919250613fb091613f8f9087906159de565b868d60800151613f9f91906159de565b84878f60c00151612ae691906159de565b5f5f613fcf868d60200151600a54600a613fca9190615b21565b614cb3565b8c51604001519091508190811015614016576040517f4e50c4e30000000000000000000000000000000000000000000000000000000081526004016126ce91815260200190565b508381111561404c575f61402a85836159de565b9050620186a08160105461403e91906159f1565b6140489190615b59565b9250505b5061406661405a8285615df2565b8c51602001518c61464b565b801561410d5760048054600154604080517f60dc2340000000000000000000000000000000000000000000000000000000008152905161410d9473ffffffffffffffffffffffffffffffffffffffff94851694909316926360dc2340928082019260209290918290030181865afa1580156140e3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061410791906157ec565b83614b18565b939a919950929750919550909350505050565b6001546040517f46fbf68e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff909116906346fbf68e90602401602060405180830381865afa15801561418c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141b09190615807565b6114b5576040517fd47659ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f612f268361426884613e03565b600a8054613fca91615b21565b61428f865f61428488886159de565b5f612ae688886159de565b8060075f8282546142a09190615df2565b9091555050600154604080517f60dc2340000000000000000000000000000000000000000000000000000000008152905161390f9273ffffffffffffffffffffffffffffffffffffffff16916360dc23409160048083019260209291908290030181865afa158015614314573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061433891906157ec565b865f61450d565b905090565b80825d5050565b6003546040517f73c1ca900000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906373c1ca90906024016020604051808303815f875af11580156143b8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061433f9190615ddb565b5f6143f584846b033b2e3c9fd0803ce800000085614cc9565b949350505050565b5f6143f5846b033b2e3c9fd0803ce80000008585614cc9565b600654811015611b50576040517f6abca20a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8161446c600e54614463868561425a565b620186a0614cb3565b1015610fe2576040517f70f4443900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6144d585858560115573ffffffffffffffffffffffffffffffffffffffff9091165f90815260126020526040902055565b61450685838373ffffffffffffffffffffffffffffffffffffffff9092165f90815260096020526040902055600855565b5050505050565b8015614572576014546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018590529091169063a9059cbb90604401613037565b6014546040517fb460af940000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff85811660248301523060448301529091169063b460af94906064016020604051808303815f875af11580156145ee573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061149f9190615ddb565b805f03611b50576040517f5b41c2f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160400151831115614689576040517f5b12919800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160608301518110156146cc576040517f353a52510000000000000000000000000000000000000000000000000000000081526004016126ce91815260200190565b5060135473ffffffffffffffffffffffffffffffffffffffff166147265f6146f76020850185614ee8565b73ffffffffffffffffffffffffffffffffffffffff1603614718573361471a565b815b8451608086015161450d565b5f6147346020840184614ee8565b73ffffffffffffffffffffffffffffffffffffffff16146148355782608001511561478b576040517f702275b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546004805460208601516040517ffb3eb4b600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681169563fb3eb4b6956147f39591831694929091169233918a9101615d64565b6020604051808303815f875af115801561480f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906148339190615ddb565b505b61149f338561388a565b60405173ffffffffffffffffffffffffffffffffffffffff848116602483015283811660448301526064820183905261149f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050614d0b565b60025467ffffffffffffffff16156114b5576040517f35edea3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015614976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061499a9190615ddb565b90508015610d5b57601454600154604080517f60dc2340000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff93841693632e2d2984938693309391909216916360dc23409160048083019260209291908290030181865afa158015614a21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614a4591906157ec565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935273ffffffffffffffffffffffffffffffffffffffff91821660248401521660448201526064016020604051808303815f875af1158015614abb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fe29190615ddb565b805f03611b50576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9d0bee0300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015260248201839052841690639d0bee03906044015f604051808303815f87803b158015614b85575f5ffd5b505af1158015614b97573d5f5f3e3d5ffd5b50505050505050565b5f614baa83614612565b335f90815260126020526040812054614bc49085906159de565b9050612f2681845f614452565b60025468010000000000000000900467ffffffffffffffff16156114b5576040517f12b0cb4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554614c30838360016143dc565b600754614c3d9190615df2565b1115610d5b576040517f22ab3c5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff838116602483015260448201839052610fe291859182169063a9059cbb90606401614881565b5f81614cbf84866159f1565b6143f59190615b59565b5f614cf6614cd683614daa565b8015614cf157505f8480614cec57614cec615b2c565b868809115b151590565b614d01868686614dd6565b610b459190615df2565b5f5f60205f8451602086015f885af180614d2a576040513d5f823e3d81fd5b50505f513d91508115614d41578060011415614d5b565b73ffffffffffffffffffffffffffffffffffffffff84163b155b1561149f576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016126ce565b5f6002826003811115614dbf57614dbf615bd5565b614dc99190615f9b565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03614e2957838281614e1f57614e1f615b2c565b0492505050612f26565b808411614e4057614e406003851502601118614eab565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b634e487b715f52806020526024601cfd5b73ffffffffffffffffffffffffffffffffffffffff81168114611b50575f5ffd5b8035611c8681614ebc565b5f60208284031215614ef8575f5ffd5b8135612f2681614ebc565b5f60208284031215614f13575f5ffd5b5035919050565b5f5f5f5f5f60a08688031215614f2e575f5ffd5b8535614f3981614ebc565b94506020860135935060408601359250606086013591506080860135614f5e81614ebc565b809150509295509295909350565b5f60408284031215614f7c575f5ffd5b50919050565b5f5f82840360c0811215614f94575f5ffd5b60a0811215614fa1575f5ffd5b5082915060a083013567ffffffffffffffff811115614fbe575f5ffd5b614fca85828601614f6c565b9150509250929050565b5f60808284031215614f7c575f5ffd5b5f5f60408385031215614ff5575f5ffd5b82359150602083013567ffffffffffffffff811115615012575f5ffd5b614fca85828601614fd4565b8015158114611b50575f5ffd5b5f5f5f6060848603121561503d575f5ffd5b833592506020840135915060408401356150568161501e565b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff811182821017156150b2576150b2615061565b60405290565b60405160c0810167ffffffffffffffff811182821017156150b2576150b2615061565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561512257615122615061565b604052919050565b5f67ffffffffffffffff82111561514357615143615061565b5060051b60200190565b5f82601f83011261515c575f5ffd5b813561516f61516a8261512a565b6150db565b8082825260208201915060208360051b860101925085831115615190575f5ffd5b602085015b838110156151b65780356151a881614ebc565b835260209283019201615195565b5095945050505050565b5f82601f8301126151cf575f5ffd5b813567ffffffffffffffff8111156151e9576151e9615061565b61521a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016150db565b81815284602083860101111561522e575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f610120828403121561525b575f5ffd5b61526361508e565b905061526e82614edd565b815261527c60208301614edd565b602082015260408281013590820152606080830135908201526080808301359082015260a0808301359082015260c0808301359082015260e082013567ffffffffffffffff8111156152cc575f5ffd5b6152d88482850161514d565b60e08301525061010082013567ffffffffffffffff8111156152f8575f5ffd5b615304848285016151c0565b6101008301525092915050565b5f5f5f838503610100811215615325575f5ffd5b60c0811215615332575f5ffd5b5061533b6150b8565b843561534681614ebc565b8152602085013561535681614ebc565b6020820152604085013561536981614ebc565b6040820152606085013561537c81614ebc565b6060820152608085013561538f81614ebc565b608082015260a08501356153a281614ebc565b60a0820152925060c084013567ffffffffffffffff8111156153c2575f5ffd5b6153ce8682870161524a565b9250506153dd60e08501614edd565b90509250925092565b5f5f604083850312156153f7575f5ffd5b823561540281614ebc565b946020939093013593505050565b5f5f5f5f60808587031215615423575f5ffd5b8435935060208501359250604085013567ffffffffffffffff811115615447575f5ffd5b61545387828801614f6c565b925050606085013567ffffffffffffffff81111561546f575f5ffd5b61547b87828801614fd4565b91505092959194509250565b5f5f60208385031215615498575f5ffd5b823567ffffffffffffffff8111156154ae575f5ffd5b8301601f810185136154be575f5ffd5b803567ffffffffffffffff8111156154d4575f5ffd5b8560208260051b84010111156154e8575f5ffd5b6020919091019590945092505050565b5f5f60408385031215615509575f5ffd5b82359150602083013561551b8161501e565b809150509250929050565b5f5f5f60608486031215615538575f5ffd5b833561554381614ebc565b92506020840135915060408401356150568161501e565b5f5f6040838503121561556b575f5ffd5b823561557681614ebc565b9150602083013567ffffffffffffffff811115615012575f5ffd5b5f5f60a083850312156155a2575f5ffd5b6155ac8484614fd4565b9150608083013567ffffffffffffffff811115614fbe575f5ffd5b5f602082840312156155d7575f5ffd5b813567ffffffffffffffff8111156155ed575f5ffd5b6143f58482850161514d565b602080825282518282018190525f918401906040840190835b81811015615652578351805173ffffffffffffffffffffffffffffffffffffffff1684526020908101518185015290930192604090920191600101615612565b509095945050505050565b5f5f5f6060848603121561566f575f5ffd5b833561567a81614ebc565b95602085013595506040909401359392505050565b5f5f8284036101008112156156a2575f5ffd5b60e08112156156af575f5ffd5b5082915060e083013567ffffffffffffffff811115614fbe575f5ffd5b5f5f5f606084860312156156de575f5ffd5b8335925060208401356156f08161501e565b9150604084013567ffffffffffffffff81111561570b575f5ffd5b61571786828701614fd4565b9150509250925092565b5f5f60408385031215615732575f5ffd5b823560038110615740575f5ffd5b9150602083013567ffffffffffffffff8116811461551b575f5ffd5b5f60a0828403121561576c575f5ffd5b60405160a0810167ffffffffffffffff8111828210171561578f5761578f615061565b6040908152833582526020808501359083015283810135908201526060808401359082015290508060808301356157c58161501e565b6080919091015292915050565b5f60a082840312156157e2575f5ffd5b612f26838361575c565b5f602082840312156157fc575f5ffd5b8151612f2681614ebc565b5f60208284031215615817575f5ffd5b8151612f268161501e565b604080825281018390525f8460608301825b8681101561587157823561584781614ebc565b73ffffffffffffffffffffffffffffffffffffffff16825260209283019290910190600101615834565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b5f602082840312156158ab575f5ffd5b815167ffffffffffffffff8111156158c1575f5ffd5b8201601f810184136158d1575f5ffd5b80516158df61516a8261512a565b8082825260208201915060208360051b850101925086831115615900575f5ffd5b6020840193505b82841015615922578351825260209384019390910190615907565b9695505050505050565b5f6020828403121561593c575f5ffd5b8135612f268161501e565b5f6080828403128015615958575f5ffd5b506040516080810167ffffffffffffffff8111828210171561597c5761597c615061565b60409081528335825260208085013590830152838101359082015260608301356159a58161501e565b60608201529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115613e9657613e966159b1565b8082028115828204841417613e9657613e966159b1565b6001815b6001841115613dfb57808504811115615a2757615a276159b1565b6001841615615a3557908102905b60019390931c928002615a0c565b5f82615a5157506001613e96565b81615a5d57505f613e96565b8160018114615a735760028114615a7d57615a99565b6001915050613e96565b60ff841115615a8e57615a8e6159b1565b50506001821b613e96565b5060208310610133831016604e8410600b8410161715615abc575081810a613e96565b615ae77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615a08565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b1957615b196159b1565b029392505050565b5f612f268383615a43565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82615b6757615b67615b2c565b500490565b5f60e0828403128015615b7d575f5ffd5b506040516060810167ffffffffffffffff81118282101715615ba157615ba1615061565b6040528235615baf81614ebc565b8152615bbe846020850161575c565b602082015260c09290920135604083015250919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6040810160038410615c3b577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b92815267ffffffffffffffff9190911660209091015290565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112615c86575f5ffd5b9190910192915050565b5f8135615c9c81614ebc565b73ffffffffffffffffffffffffffffffffffffffff1683526020820135368390037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1018112615ce9575f5ffd5b820160208101903567ffffffffffffffff811115615d05575f5ffd5b803603821315615d13575f5ffd5b60406020860152806040860152808260608701375f6060828701015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168601019250505092915050565b73ffffffffffffffffffffffffffffffffffffffff8616815273ffffffffffffffffffffffffffffffffffffffff8516602082015283604082015273ffffffffffffffffffffffffffffffffffffffff8316606082015260a060808201525f615dd060a0830184615c90565b979650505050505050565b5f60208284031215615deb575f5ffd5b5051919050565b80820180821115613e9657613e966159b1565b5f60208284031215615e15575f5ffd5b815160ff81168114612f26575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b604080825283519082018190525f9060208501906060840190835b81811015615ea157835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101615e6d565b50508381036020850152809150845180825260208201925060208160051b830101602087015f5b83811015615f56577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0858403018652815180518085528060208301602087015e5f6020828701015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010194505050602082019150602086019550600181019050615ec8565b509098975050505050505050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615f9457615f946159b1565b5060010190565b5f60ff831680615fad57615fad615b2c565b8060ff8416069150509291505056fea2646970667358221220bfb13f04be390016add095ef49ca264b379c292cc1754fb43ce3d0b1fd1a9fd664736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"optimizer":{"enabled":true,"runs":1000000},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":1000000,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-05-27T23:48:31.575014Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600e575f5ffd5b5060018054600160a01b600160e01b031916600160a01b179055615ff2806100355f395ff3fe608060405260043610610324575f3560e01c80637ed57d47116101a7578063bb66baeb116100e7578063ec78e83211610092578063f384bd051161006d578063f384bd051461092b578063fd0526f914610940578063fe45fe1714610998578063fef0bec8146109b7575f5ffd5b8063ec78e832146108cc578063f2fcad12146108f8578063f2fde38b1461090c575f5ffd5b8063ce1ad4f1116100c2578063ce1ad4f114610862578063d0b0c81614610881578063ec60b844146108a0575f5ffd5b8063bb66baeb1461081b578063bbcac5571461082e578063c3d5f5e614610843575f5ffd5b806395043df711610152578063a043d6d71161012d578063a043d6d7146107b2578063a36a3630146107de578063ab60577a146107f3578063b8a8badf14610808575f5ffd5b806395043df71461075f57806398d34e941461077e5780639bd6012f1461079d575f5ffd5b80638da5cb5b116101825780638da5cb5b146106dd5780639198e8401461070857806394ee082714610733575f5ffd5b80637ed57d47146106735780638574a20914610692578063873c0e39146106be575f5ffd5b806327f9f2cf116102725780634031234c1161021d5780635c57f6d8116101f85780635c57f6d8146106005780636a959886146106155780636aebf6301461064157806378477edc14610654575f5ffd5b80634031234c146105b75780634ac8eb5f146105cc5780634b8a3529146105e1575f5ffd5b806338d074361161024d57806338d07436146105285780633d07b176146105475780633edd112814610598575f5ffd5b806327f9f2cf146104ca57806329bc969d146104de5780632d0f9abe14610509575f5ffd5b806314211c53116102d257806321fc7ffc116102ad57806321fc7ffc1461047957806322867d78146104985780632395ed2e146104b7575f5ffd5b806314211c53146104265780631a186127146104455780631b859e4114610464575f5ffd5b806308a0c3751161030257806308a0c375146103d55780630ac89759146103f4578063129bc8f014610413575f5ffd5b806303c6c0b614610328578063062d8bc71461038757806306c46a58146103a8575b5f5ffd5b348015610333575f5ffd5b5061036d610342366004614ee8565b73ffffffffffffffffffffffffffffffffffffffff165f908152601260205260409020546011549091565b604080519283526020830191909152015b60405180910390f35b348015610392575f5ffd5b506103a66103a1366004614f03565b6109d6565b005b3480156103b3575f5ffd5b506103c76103c2366004614f1a565b610a1a565b60405190815260200161037e565b3480156103e0575f5ffd5b506103a66103ef366004614f03565b610b4e565b3480156103ff575f5ffd5b506103a661040e366004614f82565b610bc6565b6103a6610421366004614fe4565b610d5f565b348015610431575f5ffd5b506103a661044036600461502b565b610eb4565b348015610450575f5ffd5b506103a661045f366004614ee8565b610fe7565b34801561046f575f5ffd5b506103c760085481565b348015610484575f5ffd5b506103a6610493366004615311565b611062565b3480156104a3575f5ffd5b506103a66104b23660046153e6565b611250565b6103a66104c5366004615410565b611302565b3480156104d5575f5ffd5b506103a66114a5565b3480156104e9575f5ffd5b506103c76104f8366004614ee8565b60126020525f908152604090205481565b348015610514575f5ffd5b506103a6610523366004615487565b6114b7565b348015610533575f5ffd5b506103a66105423660046154f8565b611582565b348015610552575f5ffd5b50600c546105739073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161037e565b3480156105a3575f5ffd5b506103a66105b2366004615526565b611674565b3480156105c2575f5ffd5b506103c7600f5481565b3480156105d7575f5ffd5b506103c760115481565b3480156105ec575f5ffd5b506103a66105fb3660046153e6565b6117a8565b34801561060b575f5ffd5b506103c760055481565b348015610620575f5ffd5b506013546105739073ffffffffffffffffffffffffffffffffffffffff1681565b6103a661064f36600461555a565b61184d565b34801561065f575f5ffd5b506103a661066e366004615591565b611951565b34801561067e575f5ffd5b506103a661068d366004614f03565b611ab2565b34801561069d575f5ffd5b506106b16106ac3660046155c7565b611b53565b60405161037e91906155f9565b3480156106c9575f5ffd5b506103a66106d836600461565d565b611c8b565b3480156106e8575f5ffd5b505f546105739073ffffffffffffffffffffffffffffffffffffffff1681565b348015610713575f5ffd5b506103c7610722366004614ee8565b60096020525f908152604090205481565b34801561073e575f5ffd5b50600b546105739073ffffffffffffffffffffffffffffffffffffffff1681565b34801561076a575f5ffd5b506103a661077936600461502b565b611d9a565b348015610789575f5ffd5b506103a661079836600461568f565b611e96565b3480156107a8575f5ffd5b506103c7600a5481565b3480156107bd575f5ffd5b506003546105739073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107e9575f5ffd5b506103c760105481565b3480156107fe575f5ffd5b506103c760065481565b6103a66108163660046156cc565b61215f565b6103a661082936600461555a565b6122c6565b348015610839575f5ffd5b506103c760075481565b34801561084e575f5ffd5b506103a661085d366004614f03565b612421565b34801561086d575f5ffd5b506103a661087c366004615721565b61245e565b34801561088c575f5ffd5b506103a661089b366004614f03565b612599565b3480156108ab575f5ffd5b50600d546105739073ffffffffffffffffffffffffffffffffffffffff1681565b3480156108d7575f5ffd5b506014546105739073ffffffffffffffffffffffffffffffffffffffff1681565b348015610903575f5ffd5b5061057361264d565b348015610917575f5ffd5b506103a6610926366004614ee8565b61267b565b348015610936575f5ffd5b506103c7600e5481565b34801561094b575f5ffd5b506002546040805167ffffffffffffffff8084168252680100000000000000008404811660208301527001000000000000000000000000000000009093049092169082015260600161037e565b3480156109a3575f5ffd5b506103a66109b2366004614ee8565b6126e0565b3480156109c2575f5ffd5b506103a66109d1366004614f03565b612862565b6109de6128dc565b60058190556040518181527f0937edcd92487438a2b500669f3c2b5145a80d7e0390d321137ee08da1e5d81c906020015b60405180910390a150565b5f610a2361292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8781165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015288929190911690634a9bd802906064015f604051808303815f87803b158015610aaf575f5ffd5b505af1158015610ac1573d5f5f3e3d5ffd5b505050505f5f610ad489898989896129b4565b604080518b8152602081018b905290810189905260608101829052919350915073ffffffffffffffffffffffffffffffffffffffff8a16907f20843bedc56d43973249c6823b8ab2e5ea90894751a5120b2f41742835d80c199060800160405180910390a250915050610b45612b23565b95945050505050565b610b566128dc565b600f548110610b91576040517fb6aa88a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8190556040518181527f6ad6c0ca92bb285e6f642e202af7fcd6377e3b6fd6dda78384c4e3e24acc3d2a90602001610a0f565b610bce61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015610c5a575f5ffd5b505af1158015610c6c573d5f5f3e3d5ffd5b505050505f610c7a33612b4d565b90505f5f610cdd6040518060e0016040528088803603810190610c9d91906157d2565b8152602001855f01518152602001856020015181526020016011548152602001856040015181526020016008548152602001856060015181525086612be5565b9092509050337f1548292c70c1a3db5c87d3e6c926b6d456017b86ee5c4d3113ee5de211cd898183838935610d1560208b018b614ee8565b6040805194855260208501939093529183015273ffffffffffffffffffffffffffffffffffffffff1660608201526080015b60405180910390a250505050610d5b612b23565b5050565b610d6761292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015610df3575f5ffd5b505af1158015610e05573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff1691505f9050610e30848330612d41565b90505f610e3f8287855f612f2d565b9050337faebe32d9b5f423f063ee6c4998222119fce5d9f8eedf5280bf8b84cd50a5aca4838884610e7360208b018b614ee8565b6040805194855260208581019490945284019190915273ffffffffffffffffffffffffffffffffffffffff166060830152880135608082015260a001610d47565b610ebc61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015610f48575f5ffd5b505af1158015610f5a573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff169150610f8390508584612f9b565b5f610f908686845f612f2d565b604080518881526020810188905290810182905290915033907fa9535af9dc0ff2e9e0c8f578d8f9aafb7fecdd1566ac257aad5c7d3fabec12e6906060015b60405180910390a2505050610fe2612b23565b505050565b610fef6128dc565b600c80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fd3b5d1e0ffaeff528910f3663f0adace7694ab8241d58e17a91351ced2e0803190602001610a0f565b61106c8383613077565b600b54604080517f38d52e0f000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff928316928416916338d52e0f9160048083019260209291908290030181865afa1580156110dc573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061110091906157ec565b73ffffffffffffffffffffffffffffffffffffffff161461114d576040517f50e6a09c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301529091169063095ea7b3906044016020604051808303815f875af11580156111e2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112069190615807565b50601480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555050565b61125861292e565b5f5f5f6112658585613355565b5092509250925061129d85838373ffffffffffffffffffffffffffffffffffffffff9092165f90815260096020526040902055600855565b604080513381526020810185905290810183905273ffffffffffffffffffffffffffffffffffffffff8616907fe4a1ae657f49cb1fb1c7d3a94ae6093565c4c8c0e03de488f79c377c3c3a24e0906060015b60405180910390a2505050610d5b612b23565b61130a61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611396575f5ffd5b505af11580156113a8573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff1691505f90506113d3848330612d41565b90505f5f5f6114058560405180608001604052808781526020018d81526020018c81526020015f15158152508a613489565b91945092509050337fd35d526454c24890c99712173c621bbc95962d51143051ed7782a2c37aa82bd78386868e8661144060208f018f614ee8565b604080519687526020878101969096528601939093526060850191909152608084015273ffffffffffffffffffffffffffffffffffffffff1660a08301528a013560c082015260e00160405180910390a250505050505061149f612b23565b50505050565b6114ad6135fd565b6114b5612b23565b565b6114bf61292e565b6014546040517f25181bb000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906325181bb09061151990859085903090600401615822565b5f604051808303815f875af1158015611534573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611579919081019061589b565b50610d5b612b23565b61158a61292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611616575f5ffd5b505af1158015611628573d5f5f3e3d5ffd5b5050505061163683836136c3565b60405183815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a250610d5b612b23565b61167c61292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8481165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015285929190911690634a9bd802906064015f604051808303815f87803b158015611708575f5ffd5b505af115801561171a573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff16915061174390508484612f9b565b61174e85858361373d565b8473ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c8560405161179691815260200190565b60405180910390a25050610fe2612b23565b6117b061292e565b335f9081526012602052604081205481906117cf9085908590846137c3565b335f908152600960205260409020829055600881905590925090506040805173ffffffffffffffffffffffffffffffffffffffff861681526020810185905290810183905233907fc1561b330e73faa7d5d1ac03c968d8f359b0191ccdb9cc002cf7d8eb6ae038cb9060600160405180910390a25050610d5b612b23565b61185561292e565b6004545f9061187c90839073ffffffffffffffffffffffffffffffffffffffff1633612d41565b90505f5f5f61188b8685613355565b509250925092506118c386838373ffffffffffffffffffffffffffffffffffffffff9092165f90815260096020526040902055600855565b73ffffffffffffffffffffffffffffffffffffffff86167f3f64dfb3813cd414050511f815ad02154fdfd1ec318508ed886c411c42eacb4633858561190b60208b018b614ee8565b6040805173ffffffffffffffffffffffffffffffffffffffff9586168152602080820195909552908101929092529092166060830152880135608082015260a001610d47565b61195961292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b1580156119e5575f5ffd5b505af11580156119f7573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff16915050833515611a3657611a368435611a31608087016060880161592c565b612f9b565b5f8080611a5284611a4c368a90038a018a615947565b88613489565b6040805183815260208082018690528c013581830152606081018390529051939650919450925033917f247b1d4a7d9e5a9db44e04d512cc546013c9d28034db34eb63abc908ca1bf0f99181900360800190a25050505050610d5b612b23565b611aba61292e565b60075480821115611af7576040517f6b8f3dc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b0182826159de565b600755611b0e338361388a565b60408051338152602081018490527f489f8907efd42611728dc7378e422a9f505a041b1b48831593145b62cc30cc3a910160405180910390a150611b50612b23565b50565b6060611b5d61292e565b600d545f80805260126020527f7e7fa33969761a458e04f477e039a608702b4f924981d6653935a8319a08ad7b546011546040517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101929092526044820152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611c01575f5ffd5b505af1158015611c13573d5f5f3e3d5ffd5b5050600d5473ffffffffffffffffffffffffffffffffffffffff1633149150611c6a9050576040517fc008bfc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c72613917565b611c7b83613a93565b915050611c86612b23565b919050565b611c9361292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8481165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015285929190911690634a9bd802906064015f604051808303815f87803b158015611d1f575f5ffd5b505af1158015611d31573d5f5f3e3d5ffd5b505050505f611d41858585613c6f565b604080518681526020810186905290810182905290915073ffffffffffffffffffffffffffffffffffffffff8616907f6c8724ad04a771490ffee385dfa3b678038e31a6fde3f32666c681b0b7443b2490606001611796565b611da261292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b158015611e2e575f5ffd5b505af1158015611e40573d5f5f3e3d5ffd5b505050505f5f611e51868686613dad565b6040805189815260208101849052908101829052919350915033907f1d7597506f537c4ec23388b55909c8ca6a6a39bedb13fe958a7e2eba31f5d24e90606001610fcf565b611e9e61292e565b611eab6020830183614ee8565b600d5473ffffffffffffffffffffffffffffffffffffffff8281165f81815260126020526040908190205460115491517f4a9bd802000000000000000000000000000000000000000000000000000000008152600481019390935260248301526044820152911690634a9bd802906064015f604051808303815f87803b158015611f33575f5ffd5b505af1158015611f45573d5f5f3e3d5ffd5b505f9250611f629150611f5d90506020860186614ee8565b612b4d565b90505f611f6f6001613e03565b60608301519091507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9015611fff57620186a08360600151611fb191906159f1565b600f5483600a546012611fc491906159de565b611fcf90600a615b21565b8660200151611fde91906159f1565b611fe891906159f1565b611ff291906159f1565b611ffc9190615b59565b90505b670de0b6b3a76400008110612040576040517f1bad36df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f5f5f6120aa6040518061010001604052808c8036038101906120649190615b6c565b8152602001888152602001895f0151815260200189602001518152602001601154815260200189604001518152602001600854815260200189606001518152508a613e9c565b929650909450925090506120c160208b018b614ee8565b73ffffffffffffffffffffffffffffffffffffffff167fdde0adb27be857d0db946bcab48f6a9f4b90b721fa0672622d5ec3de019bee3e848385888e5f01602081019061210e9190614ee8565b60408051958652602086019490945292840191909152606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a00160405180910390a25050505050505050610d5b612b23565b61216761292e565b600d54335f81815260126020526040908190205460115491517f4a9bd8020000000000000000000000000000000000000000000000000000000081526004810184905260248101919091526044810191909152909173ffffffffffffffffffffffffffffffffffffffff1690634a9bd802906064015f604051808303815f87803b1580156121f3575f5ffd5b505af1158015612205573d5f5f3e3d5ffd5b50506004545f92506122309150849073ffffffffffffffffffffffffffffffffffffffff1633612d41565b90505f5f61223f878488613dad565b9092509050337f249be7ccf5d800b92c9d775dcd88d9e1bbb1b26eac70852c203a0f79f4bf9a7088848461227660208b018b614ee8565b6040805194855260208581019490945284019190915273ffffffffffffffffffffffffffffffffffffffff166060830152880135608082015260a00160405180910390a250505050610fe2612b23565b6122ce61292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8381165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015284929190911690634a9bd802906064015f604051808303815f87803b15801561235a575f5ffd5b505af115801561236c573d5f5f3e3d5ffd5b5050600b5473ffffffffffffffffffffffffffffffffffffffff1691505f9050612397848330612d41565b90506123a485828461373d565b73ffffffffffffffffffffffffffffffffffffffff85167fe61106c51c4c591aeba5b8340c4271817aa7d1d2e8c360f568cea6aa43c7bc5c826123ea6020880188614ee8565b6040805192835273ffffffffffffffffffffffffffffffffffffffff909116602083810191909152880135908201526060016112ef565b6124296128dc565b60068190556040518181527f0278b9e7389dd0abae8ab123abafedb45c523c7d6fa5aff191a6ed0541e0174e90602001610a0f565b612466614120565b5f82600281111561247957612479615bd5565b036124b757600280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831617905561255c565b60018260028111156124cb576124cb615bd5565b0361251457600280547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff84160217905561255c565b600280547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000067ffffffffffffffff8416021790555b7f4c47716be4fe501c50cc9446e3c627be438c5d4865413f0444fbb33d74f03218828260405161258d929190615c02565b60405180910390a15050565b6125a16128dc565b620186a081106125dd576040517f15f85eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e548111612618576040517f7c07cff900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f8190556040518181527fde1cb344f21d9f06ecaf12cc8a2029fee63238f03db53e66234ce6f86c72a90390602001610a0f565b5f61265661292e565b61265e6135fd565b50600b5473ffffffffffffffffffffffffffffffffffffffff1690565b6126836128dc565b73ffffffffffffffffffffffffffffffffffffffff81166126d7576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024015b60405180910390fd5b611b50816141e6565b6126e861292e565b600d5473ffffffffffffffffffffffffffffffffffffffff8281165f81815260126020526040908190205460115491517f4a9bd80200000000000000000000000000000000000000000000000000000000815260048101939093526024830152604482015283929190911690634a9bd802906064015f604051808303815f87803b158015612774575f5ffd5b505af1158015612786573d5f5f3e3d5ffd5b505050505f61279483612b4d565b905080606001516127aa8260200151600161425a565b106127e1576040517fd42d4f2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127ff83826020015160115484604001516008548660600151614275565b6060810151602080830151604080519384529183015273ffffffffffffffffffffffffffffffffffffffff8516917f0f175fe8ca3f35beba045eef36a95c6067ed110972d5fe4e104ade3e9e6f0403910160405180910390a25050611b50612b23565b61286a6128dc565b620138808111156128a7576040517fde61ab3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60108190556040518181527f76d62e6b12d0246e4dbc36a0207cb0bb2136ab4d758da9a4fadc4b09197bf41390602001610a0f565b5f5473ffffffffffffffffffffffffffffffffffffffff1633146114b5576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016126ce565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15612987576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114b560017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90614344565b5f5f6129be6135fd565b5f6129c761434b565b73ffffffffffffffffffffffffffffffffffffffff89165f908152600960205260408120549192506129fb828460016143dc565b73ffffffffffffffffffffffffffffffffffffffff8b165f9081526012602052604081205491925090612a2f908b906159de565b90505f5f898b1015612a6d576040517f6246601800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b838b10612a8a57849150839a50838a10612a85578399505b612ab7565b612a958b875f6143fd565b9150612aa18b856159de565b9050612aac81614416565b612ab783825f614452565b5f612ac283876159de565b9050612aeb8e858f601154612ad791906159de565b8487600854612ae691906159de565b6144a4565b612af68a8e5f61450d565b8a15612b0657612b068e8c61388a565b612b108b8d6159de565b9e909d509b505050505050505050505050565b6114b55f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006129ae565b612b7460405180608001604052805f81526020015f81526020015f81526020015f81525090565b5f612b7d61434b565b73ffffffffffffffffffffffffffffffffffffffff84165f81815260096020908152604080832054815160808101835286815294845260128352928190205491840191909152820181905291925060608101612bdb838560016143dc565b9052949350505050565b8151515f908190612bf590614612565b83515160408501515f91612c08916159de565b85516020015160c08701519192505f918110612c3057505060c0850151608086015190612ca9565b612c3f8188602001515f6143fd565b91508015612c8057815f03612c80576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818860c00151612c9191906159de565b9050612c9c81614416565b612ca784825f614452565b505b5f828860800151612cba91906159de565b9050612ce833858a5f01515f01518b60600151612cd791906159de565b84878d60a00151612ae691906159de565b6040805160a0810182528951518152895160609081015160208301528a5183015192820192909252895151918101919091528851608090810151151590820152612d349083908961464b565b9097909650945050505050565b5f83602001355f03612d7f576040517f3133a04300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60135473ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee612dba6020870187614ee8565b73ffffffffffffffffffffffffffffffffffffffff1614612e46573415612e0d576040517f3133a04300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e41338260208801803590612e23908a614ee8565b73ffffffffffffffffffffffffffffffffffffffff1692919061483f565b612e83565b84602001353414612e83576040517f3133a04300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811663fb3eb4b634612ead6020890189614ee8565b8760408a013588612ec160608d018d615c54565b6040518763ffffffff1660e01b8152600401612ee1959493929190615d64565b60206040518083038185885af1158015612efd573d5f5f3e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190612f229190615ddb565b9150505b9392505050565b5f612f366148c8565b612f3f85614612565b335f90815260126020526040812054612f59908790615df2565b90505f5f612f69338885886137c3565b91509150612f8733848a601154612f809190615df2565b85856144a4565b612f908661490c565b509695505050505050565b5f81612fbf57600b5473ffffffffffffffffffffffffffffffffffffffff16612fd9565b60145473ffffffffffffffffffffffffffffffffffffffff165b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810185905290915073ffffffffffffffffffffffffffffffffffffffff8216906323b872dd906064015b6020604051808303815f875af1158015613053573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061149f9190615807565b60015474010000000000000000000000000000000000000000900467ffffffffffffffff16156130d3576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018054602084810151600480547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff938416179091556040870151740100000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000090951690831617939093179093556060808601516003805485169186169190911790556080860151600d8054851691861691909117905560a08601516013805485169186169190911790558451600b8054851691861691909117905590840151600c80549093169316929092179055810151620186a01161320a576040517f15f85eb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806040015181606001511161324b576040517f7c07cff900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620138808160800151111561328c576040517fde61ab3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080820151600e556060820151600f55608082015160105560a082015160055560c0820151600655600b5481517f313ce567000000000000000000000000000000000000000000000000000000008152915173ffffffffffffffffffffffffffffffffffffffff9091169163313ce5679160048083019260209291908290030181865afa158015613320573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133449190615e05565b60ff16600a558151610d5b906141e6565b5f5f5f5f61336285614adf565b5f61336b61434b565b73ffffffffffffffffffffffffffffffffffffffff88165f9081526009602052604081205491925061339f828460016143dc565b9050815f036133da576040517fbe6b0c1e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f5f838b106133f257839a505f9250849150613420565b6133fc8b856159de565b90506134098b875f6143fd565b915061341582866159de565b925061342081614416565b815f03613459576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613463338c61388a565b8a838360085461347391906159de565b919e909d50909b50909950975050505050505050565b5f5f5f6134946148c8565b600254700100000000000000000000000000000000900467ffffffffffffffff16156134ec576040517f8cb0972500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454601354602087015173ffffffffffffffffffffffffffffffffffffffff92831692909116906135219083908390614b18565b600b5460408089015190517ffb3eb4b60000000000000000000000000000000000000000000000000000000081525f9273ffffffffffffffffffffffffffffffffffffffff8086169363fb3eb4b69361358593899316919030908e90600401615d64565b6020604051808303815f875af11580156135a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135c59190615ddb565b90505f81895f01516135d79190615df2565b90505f6135eb828b602001518d6001612f2d565b929b919a509198509650505050505050565b6001546040517f1622c70f00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911690631622c70f90602401602060405180830381865afa158015613669573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061368d9190615807565b6114b5576040517f99277d1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6136cc61434b565b335f81815260096020526040902054919250613732916136f99086906136f4908660016143dc565b614ba0565b8560115461370791906159de565b60115573ffffffffffffffffffffffffffffffffffffffff9091165f90815260126020526040902055565b610fe233848461450d565b73ffffffffffffffffffffffffffffffffffffffff831661375c575f5ffd5b6137646148c8565b61376d82614612565b61377561434b565b5073ffffffffffffffffffffffffffffffffffffffff83165f908152601260205260409020546137ba9084906137ac908590615df2565b846011546137079190615df2565b610fe28161490c565b5f5f6137cd614bd1565b6137d685614adf565b5f6137df61434b565b335f908152600960205260408120549192506137fd828460016143dc565b6138079089615df2565b90505f613816898560016143fd565b90505f816008546138279190615df2565b90506138338186614c21565b61383c83614416565b61384789845f614452565b87613870576004546138709073ffffffffffffffffffffffffffffffffffffffff168c8c614b18565b61387a8285615df2565b9b909a5098505050505050505050565b600480546040517f936474cc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116938201939093526024810184905291169063936474cc906044015f604051808303815f87803b1580156138fd575f5ffd5b505af115801561390f573d5f5f3e3d5ffd5b505050505050565b6040805160018082528183019092525f91602080830190803683375050601454604080517fa6f19c84000000000000000000000000000000000000000000000000000000008152905193945073ffffffffffffffffffffffffffffffffffffffff9091169263a6f19c84925060048083019260209291908290030181865afa1580156139a5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139c991906157ec565b815f815181106139db576139db615e25565b73ffffffffffffffffffffffffffffffffffffffff929092166020928302919091018201526040805160018082528183019092527393b4b9bd266ffa8af68e39edfa8cfe2a62011ce09263ef933df09285929182015b6060815260200190600190039081613a31579050506040518363ffffffff1660e01b8152600401613a63929190615e52565b5f604051808303815f87803b158015613a7a575f5ffd5b505af1925050508015613a8b575060015b15611b505750565b80516060905f8167ffffffffffffffff811115613ab257613ab2615061565b604051908082528060200260200182016040528015613af657816020015b604080518082019091525f8082526020820152815260200190600190039081613ad05790505b50600d5490915073ffffffffffffffffffffffffffffffffffffffff165f805b84811015613c54575f878281518110613b3157613b31615e25565b60209081029190910101516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015613ba9573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613bcd9190615ddb565b90508015613c4a5760405180604001604052808373ffffffffffffffffffffffffffffffffffffffff16815260200182815250868580613c0c90615f64565b965081518110613c1e57613c1e615e25565b6020908102919091010152613c4a73ffffffffffffffffffffffffffffffffffffffff83168683614c75565b5050600101613b16565b50825115613c655780840383510383525b5090949350505050565b5f613c786135fd565b8215613c8657613c866148c8565b8115613c9457613c94614bd1565b5f613c9d61434b565b73ffffffffffffffffffffffffffffffffffffffff86165f9081526009602052604081205491925084613cd2838560016143dc565b613cdc9190615df2565b73ffffffffffffffffffffffffffffffffffffffff88165f9081526012602052604081205491925090613d10908890615df2565b90505f613d1f878660016143fd565b90505f81600854613d309190615df2565b90505f613d3d8387615df2565b90508415613d6357613d4e85614416565b613d5984865f614452565b613d638288614c21565b613d7d8b858c601154613d769190615df2565b84866144a4565b600b54613d9f9073ffffffffffffffffffffffffffffffffffffffff1661490c565b9a9950505050505050505050565b5f5f5f5f5f5f613dbd3389613355565b9350935093509350613de833613dd38b84614ba0565b8b601154613de191906159de565b86866144a4565b613df3338a8961450d565b509193509150505b935093915050565b600c546040517fafb4b04600000000000000000000000000000000000000000000000000000000815282151560048201525f9173ffffffffffffffffffffffffffffffffffffffff169063afb4b046906024016020604051808303815f875af1158015613e72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e969190615ddb565b92915050565b815160200151515f90819081908190613eb481614612565b5f5f88606001518310613ee257505050606086018051875160200151525160e087015160a088015190613f2b565b606089015160e08a0151613ef690856159f1565b613f009190615b59565b9050613f11818a604001515f6143fd565b9150613f2b818a60e00151613f2691906159de565b614416565b815f03613f64576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828a60a00151613f7591906159de565b8a515160608c0151919250613fb091613f8f9087906159de565b868d60800151613f9f91906159de565b84878f60c00151612ae691906159de565b5f5f613fcf868d60200151600a54600a613fca9190615b21565b614cb3565b8c51604001519091508190811015614016576040517f4e50c4e30000000000000000000000000000000000000000000000000000000081526004016126ce91815260200190565b508381111561404c575f61402a85836159de565b9050620186a08160105461403e91906159f1565b6140489190615b59565b9250505b5061406661405a8285615df2565b8c51602001518c61464b565b801561410d5760048054600154604080517f60dc2340000000000000000000000000000000000000000000000000000000008152905161410d9473ffffffffffffffffffffffffffffffffffffffff94851694909316926360dc2340928082019260209290918290030181865afa1580156140e3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061410791906157ec565b83614b18565b939a919950929750919550909350505050565b6001546040517f46fbf68e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff909116906346fbf68e90602401602060405180830381865afa15801561418c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141b09190615807565b6114b5576040517fd47659ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f612f268361426884613e03565b600a8054613fca91615b21565b61428f865f61428488886159de565b5f612ae688886159de565b8060075f8282546142a09190615df2565b9091555050600154604080517f60dc2340000000000000000000000000000000000000000000000000000000008152905161390f9273ffffffffffffffffffffffffffffffffffffffff16916360dc23409160048083019260209291908290030181865afa158015614314573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061433891906157ec565b865f61450d565b905090565b80825d5050565b6003546040517f73c1ca900000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906373c1ca90906024016020604051808303815f875af11580156143b8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061433f9190615ddb565b5f6143f584846b033b2e3c9fd0803ce800000085614cc9565b949350505050565b5f6143f5846b033b2e3c9fd0803ce80000008585614cc9565b600654811015611b50576040517f6abca20a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8161446c600e54614463868561425a565b620186a0614cb3565b1015610fe2576040517f70f4443900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6144d585858560115573ffffffffffffffffffffffffffffffffffffffff9091165f90815260126020526040902055565b61450685838373ffffffffffffffffffffffffffffffffffffffff9092165f90815260096020526040902055600855565b5050505050565b8015614572576014546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018590529091169063a9059cbb90604401613037565b6014546040517fb460af940000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff85811660248301523060448301529091169063b460af94906064016020604051808303815f875af11580156145ee573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061149f9190615ddb565b805f03611b50576040517f5b41c2f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160400151831115614689576040517f5b12919800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160608301518110156146cc576040517f353a52510000000000000000000000000000000000000000000000000000000081526004016126ce91815260200190565b5060135473ffffffffffffffffffffffffffffffffffffffff166147265f6146f76020850185614ee8565b73ffffffffffffffffffffffffffffffffffffffff1603614718573361471a565b815b8451608086015161450d565b5f6147346020840184614ee8565b73ffffffffffffffffffffffffffffffffffffffff16146148355782608001511561478b576040517f702275b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546004805460208601516040517ffb3eb4b600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681169563fb3eb4b6956147f39591831694929091169233918a9101615d64565b6020604051808303815f875af115801561480f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906148339190615ddb565b505b61149f338561388a565b60405173ffffffffffffffffffffffffffffffffffffffff848116602483015283811660448301526064820183905261149f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050614d0b565b60025467ffffffffffffffff16156114b5576040517f35edea3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015614976573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061499a9190615ddb565b90508015610d5b57601454600154604080517f60dc2340000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff93841693632e2d2984938693309391909216916360dc23409160048083019260209291908290030181865afa158015614a21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614a4591906157ec565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152600481019390935273ffffffffffffffffffffffffffffffffffffffff91821660248401521660448201526064016020604051808303815f875af1158015614abb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fe29190615ddb565b805f03611b50576040517fcba9a5fd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9d0bee0300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015260248201839052841690639d0bee03906044015f604051808303815f87803b158015614b85575f5ffd5b505af1158015614b97573d5f5f3e3d5ffd5b50505050505050565b5f614baa83614612565b335f90815260126020526040812054614bc49085906159de565b9050612f2681845f614452565b60025468010000000000000000900467ffffffffffffffff16156114b5576040517f12b0cb4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554614c30838360016143dc565b600754614c3d9190615df2565b1115610d5b576040517f22ab3c5700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff838116602483015260448201839052610fe291859182169063a9059cbb90606401614881565b5f81614cbf84866159f1565b6143f59190615b59565b5f614cf6614cd683614daa565b8015614cf157505f8480614cec57614cec615b2c565b868809115b151590565b614d01868686614dd6565b610b459190615df2565b5f5f60205f8451602086015f885af180614d2a576040513d5f823e3d81fd5b50505f513d91508115614d41578060011415614d5b565b73ffffffffffffffffffffffffffffffffffffffff84163b155b1561149f576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016126ce565b5f6002826003811115614dbf57614dbf615bd5565b614dc99190615f9b565b60ff166001149050919050565b5f838302817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870982811083820303915050805f03614e2957838281614e1f57614e1f615b2c565b0492505050612f26565b808411614e4057614e406003851502601118614eab565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b634e487b715f52806020526024601cfd5b73ffffffffffffffffffffffffffffffffffffffff81168114611b50575f5ffd5b8035611c8681614ebc565b5f60208284031215614ef8575f5ffd5b8135612f2681614ebc565b5f60208284031215614f13575f5ffd5b5035919050565b5f5f5f5f5f60a08688031215614f2e575f5ffd5b8535614f3981614ebc565b94506020860135935060408601359250606086013591506080860135614f5e81614ebc565b809150509295509295909350565b5f60408284031215614f7c575f5ffd5b50919050565b5f5f82840360c0811215614f94575f5ffd5b60a0811215614fa1575f5ffd5b5082915060a083013567ffffffffffffffff811115614fbe575f5ffd5b614fca85828601614f6c565b9150509250929050565b5f60808284031215614f7c575f5ffd5b5f5f60408385031215614ff5575f5ffd5b82359150602083013567ffffffffffffffff811115615012575f5ffd5b614fca85828601614fd4565b8015158114611b50575f5ffd5b5f5f5f6060848603121561503d575f5ffd5b833592506020840135915060408401356150568161501e565b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff811182821017156150b2576150b2615061565b60405290565b60405160c0810167ffffffffffffffff811182821017156150b2576150b2615061565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561512257615122615061565b604052919050565b5f67ffffffffffffffff82111561514357615143615061565b5060051b60200190565b5f82601f83011261515c575f5ffd5b813561516f61516a8261512a565b6150db565b8082825260208201915060208360051b860101925085831115615190575f5ffd5b602085015b838110156151b65780356151a881614ebc565b835260209283019201615195565b5095945050505050565b5f82601f8301126151cf575f5ffd5b813567ffffffffffffffff8111156151e9576151e9615061565b61521a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016150db565b81815284602083860101111561522e575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f610120828403121561525b575f5ffd5b61526361508e565b905061526e82614edd565b815261527c60208301614edd565b602082015260408281013590820152606080830135908201526080808301359082015260a0808301359082015260c0808301359082015260e082013567ffffffffffffffff8111156152cc575f5ffd5b6152d88482850161514d565b60e08301525061010082013567ffffffffffffffff8111156152f8575f5ffd5b615304848285016151c0565b6101008301525092915050565b5f5f5f838503610100811215615325575f5ffd5b60c0811215615332575f5ffd5b5061533b6150b8565b843561534681614ebc565b8152602085013561535681614ebc565b6020820152604085013561536981614ebc565b6040820152606085013561537c81614ebc565b6060820152608085013561538f81614ebc565b608082015260a08501356153a281614ebc565b60a0820152925060c084013567ffffffffffffffff8111156153c2575f5ffd5b6153ce8682870161524a565b9250506153dd60e08501614edd565b90509250925092565b5f5f604083850312156153f7575f5ffd5b823561540281614ebc565b946020939093013593505050565b5f5f5f5f60808587031215615423575f5ffd5b8435935060208501359250604085013567ffffffffffffffff811115615447575f5ffd5b61545387828801614f6c565b925050606085013567ffffffffffffffff81111561546f575f5ffd5b61547b87828801614fd4565b91505092959194509250565b5f5f60208385031215615498575f5ffd5b823567ffffffffffffffff8111156154ae575f5ffd5b8301601f810185136154be575f5ffd5b803567ffffffffffffffff8111156154d4575f5ffd5b8560208260051b84010111156154e8575f5ffd5b6020919091019590945092505050565b5f5f60408385031215615509575f5ffd5b82359150602083013561551b8161501e565b809150509250929050565b5f5f5f60608486031215615538575f5ffd5b833561554381614ebc565b92506020840135915060408401356150568161501e565b5f5f6040838503121561556b575f5ffd5b823561557681614ebc565b9150602083013567ffffffffffffffff811115615012575f5ffd5b5f5f60a083850312156155a2575f5ffd5b6155ac8484614fd4565b9150608083013567ffffffffffffffff811115614fbe575f5ffd5b5f602082840312156155d7575f5ffd5b813567ffffffffffffffff8111156155ed575f5ffd5b6143f58482850161514d565b602080825282518282018190525f918401906040840190835b81811015615652578351805173ffffffffffffffffffffffffffffffffffffffff1684526020908101518185015290930192604090920191600101615612565b509095945050505050565b5f5f5f6060848603121561566f575f5ffd5b833561567a81614ebc565b95602085013595506040909401359392505050565b5f5f8284036101008112156156a2575f5ffd5b60e08112156156af575f5ffd5b5082915060e083013567ffffffffffffffff811115614fbe575f5ffd5b5f5f5f606084860312156156de575f5ffd5b8335925060208401356156f08161501e565b9150604084013567ffffffffffffffff81111561570b575f5ffd5b61571786828701614fd4565b9150509250925092565b5f5f60408385031215615732575f5ffd5b823560038110615740575f5ffd5b9150602083013567ffffffffffffffff8116811461551b575f5ffd5b5f60a0828403121561576c575f5ffd5b60405160a0810167ffffffffffffffff8111828210171561578f5761578f615061565b6040908152833582526020808501359083015283810135908201526060808401359082015290508060808301356157c58161501e565b6080919091015292915050565b5f60a082840312156157e2575f5ffd5b612f26838361575c565b5f602082840312156157fc575f5ffd5b8151612f2681614ebc565b5f60208284031215615817575f5ffd5b8151612f268161501e565b604080825281018390525f8460608301825b8681101561587157823561584781614ebc565b73ffffffffffffffffffffffffffffffffffffffff16825260209283019290910190600101615834565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b5f602082840312156158ab575f5ffd5b815167ffffffffffffffff8111156158c1575f5ffd5b8201601f810184136158d1575f5ffd5b80516158df61516a8261512a565b8082825260208201915060208360051b850101925086831115615900575f5ffd5b6020840193505b82841015615922578351825260209384019390910190615907565b9695505050505050565b5f6020828403121561593c575f5ffd5b8135612f268161501e565b5f6080828403128015615958575f5ffd5b506040516080810167ffffffffffffffff8111828210171561597c5761597c615061565b60409081528335825260208085013590830152838101359082015260608301356159a58161501e565b60608201529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115613e9657613e966159b1565b8082028115828204841417613e9657613e966159b1565b6001815b6001841115613dfb57808504811115615a2757615a276159b1565b6001841615615a3557908102905b60019390931c928002615a0c565b5f82615a5157506001613e96565b81615a5d57505f613e96565b8160018114615a735760028114615a7d57615a99565b6001915050613e96565b60ff841115615a8e57615a8e6159b1565b50506001821b613e96565b5060208310610133831016604e8410600b8410161715615abc575081810a613e96565b615ae77fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615a08565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b1957615b196159b1565b029392505050565b5f612f268383615a43565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82615b6757615b67615b2c565b500490565b5f60e0828403128015615b7d575f5ffd5b506040516060810167ffffffffffffffff81118282101715615ba157615ba1615061565b6040528235615baf81614ebc565b8152615bbe846020850161575c565b602082015260c09290920135604083015250919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6040810160038410615c3b577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b92815267ffffffffffffffff9190911660209091015290565b5f82357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112615c86575f5ffd5b9190910192915050565b5f8135615c9c81614ebc565b73ffffffffffffffffffffffffffffffffffffffff1683526020820135368390037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1018112615ce9575f5ffd5b820160208101903567ffffffffffffffff811115615d05575f5ffd5b803603821315615d13575f5ffd5b60406020860152806040860152808260608701375f6060828701015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168601019250505092915050565b73ffffffffffffffffffffffffffffffffffffffff8616815273ffffffffffffffffffffffffffffffffffffffff8516602082015283604082015273ffffffffffffffffffffffffffffffffffffffff8316606082015260a060808201525f615dd060a0830184615c90565b979650505050505050565b5f60208284031215615deb575f5ffd5b5051919050565b80820180821115613e9657613e966159b1565b5f60208284031215615e15575f5ffd5b815160ff81168114612f26575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b604080825283519082018190525f9060208501906060840190835b81811015615ea157835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101615e6d565b50508381036020850152809150845180825260208201925060208160051b830101602087015f5b83811015615f56577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0858403018652815180518085528060208301602087015e5f6020828701015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010194505050602082019150602086019550600181019050615ec8565b509098975050505050505050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615f9457615f946159b1565b5060010190565b5f60ff831680615fad57615fad615b2c565b8060ff8416069150509291505056fea2646970667358221220bfb13f04be390016add095ef49ca264b379c292cc1754fb43ce3d0b1fd1a9fd664736f6c634300081c0033","name":"StakeDaoVaultV2Market","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/utils/Panic.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n *      using Panic for uint256;\n *\n *      // Use any of the declared internal constants\n *      function foo() { Panic.GENERIC.panic(); }\n *\n *      // Alternatively\n *      function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n    /// @dev generic / unspecified error\n    uint256 internal constant GENERIC = 0x00;\n    /// @dev used by the assert() builtin\n    uint256 internal constant ASSERT = 0x01;\n    /// @dev arithmetic underflow or overflow\n    uint256 internal constant UNDER_OVERFLOW = 0x11;\n    /// @dev division or modulo by zero\n    uint256 internal constant DIVISION_BY_ZERO = 0x12;\n    /// @dev enum conversion error\n    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n    /// @dev invalid encoding in storage\n    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n    /// @dev empty array pop\n    uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n    /// @dev array out of bounds access\n    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n    /// @dev resource error (too large allocation or too large array)\n    uint256 internal constant RESOURCE_ERROR = 0x41;\n    /// @dev calling invalid internal function\n    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n    /// @dev Reverts with a panic code. Recommended to use with\n    /// the internal constants with predefined codes.\n    function panic(uint256 code) internal pure {\n        assembly (\"memory-safe\") {\n            mstore(0x00, 0x4e487b71)\n            mstore(0x20, code)\n            revert(0x1c, 0x24)\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\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":"src/USG/Utilities/abstract/LightReentrancyGuardTransient.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol)\n\npragma solidity ^0.8.24;\n\nimport {LightTransientSlot} from \"../../../libs/LightTransientSlot.sol\";\n\n/**\n * @dev Variant of {ReentrancyGuard} that uses transient storage.\n *\n * NOTE: This variant only works on networks where EIP-1153 is available.\n *\n * _Available since v5.1._\n */\nabstract contract LightReentrancyGuardTransient {\n    using LightTransientSlot for *;\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant REENTRANCY_GUARD_STORAGE = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() internal {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_reentrancyGuardEntered()) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);\n    }\n\n    function _nonReentrantAfter() internal {\n        REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return REENTRANCY_GUARD_STORAGE.asBoolean().tload();\n    }\n}\n"},{"file_path":"src/USG/Market/abstract/MarketCore.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport {IUSG} from \"../../../interfaces/internals/USG/IUSG.sol\";\nimport {IControlTower} from \"../../../interfaces/internals/USG/IControlTower.sol\";\nimport {IRewardAccumulator} from \"../../../interfaces/internals/USG/IRewardAccumulator.sol\";\nimport {TokenAmount, ZapStruct, ZapStructDeposit} from \"../../../interfaces/internals/ICommonStruct.sol\";\n\nimport {PauseSettings} from \"./PauseSettings.sol\";\nimport {Collateral} from \"./Collateral.sol\";\nimport {ZappingUtil} from \"../../Utilities/abstract/ZappingUtil.sol\";\n\nimport {\n    GlobalMarketInitParams,\n    MarketInit,\n    LiquidationPre,\n    LiquidateIn,\n    LiquidateTransitionStruct,\n    SelfLiquidateIn,\n    SelfLiquidateTransitionStruct,\n    PostLiquidate,\n    LeverageIn,\n    IZappingProxy,\n    IERC20\n} from \"../../../interfaces/internals/USG/IMarketCore.sol\";\n\n/// @title MarketCore\n/// @author Tangent Finance\n/// @notice Abstract base contract implementing core functionality for USG markets.\n/// @dev Inherits PauseSettings, Collateral and ZappingUtil to provide collateral management\n/// Includes core logic for deposits, withdrawals, borrowing, repayment, liquidation, and leverage.\nabstract contract MarketCore is PauseSettings, Collateral, ZappingUtil {\n    using SafeERC20 for IERC20;\n\n    /// @notice Errors to signal specific failure conditions in market operations.\n\n    error AlreadyInitialized();\n    error NotLiquidablePosition();\n    error PositionWithoutBadDebt();\n    error NotAMigratoor();\n    error DebtToRepayTooBig();\n    error MaxUSGToBurn();\n    error NotEnoughCollateralToLiquidate(uint256 collatBalance);\n    error CollatValueToLiquidateTooLow(uint256 collatValue);\n    error MinCollatToLiquidate(uint256 collatAmount);\n    error NoZapLiquidateWithReceipt();\n\n    /// @notice Constructor marks the contract as initialized.\n    constructor() {\n        isInitialized = 1;\n    }\n\n    /// @notice Modifier to update rewards for a given account before running function logic.\n    /// @param _for Address for which to update rewards.\n    modifier updateRewards(address _for) {\n        rewardAccumulator.updateRewards(_for, collateralBalances[_for], totalCollateral);\n        _;\n    }\n\n    /// @notice Internal common initialization called during market setup.\n    /// @param _globalParams Global parameters such as USG, controlTower, interest rate calculator, etc.\n    /// @param _marketInit Market specific initialization parameters including collateral token, oracles, LTVs.\n    function _initializationCommon(GlobalMarketInitParams memory _globalParams, MarketInit memory _marketInit) internal {\n        require(isInitialized == 0, AlreadyInitialized());\n        isInitialized = 1;\n\n        // Core references initialization\n        usg = _globalParams._USG;\n        controlTower = _globalParams._controlTower;\n        irCalculator = _globalParams._irCalculator;\n        rewardAccumulator = _globalParams._rewardAccumulator;\n        zappingProxy = _globalParams._zappingProxy;\n\n        collatToken = _marketInit.collatToken;\n        collatOracle = _marketInit.collatOracle;\n\n        // Can't be more than 100%\n        require(_marketInit.liquidationThreshold < DENOMINATOR, LiquidationThresholdTooHigh());\n        // Can't be less than the maxLTV\n        require(_marketInit.liquidationThreshold > _marketInit.maxLTV, LiquidationThresholdTooLow());\n        // Can't be more than 80%\n        require(_marketInit.liquidationFee <= 80_000, LiquidationFeeTooHigh());\n\n        maxLTV = _marketInit.maxLTV;\n        liquidationThreshold = _marketInit.liquidationThreshold;\n        liquidationFee = _marketInit.liquidationFee;\n        maxMarketDebt = _marketInit.maxMarketDebt;\n        minimumLoan = _marketInit.minimumLoan;\n\n        collatDecimals = collatToken.decimals();\n\n        // Transfer ownership to the DAO\n        _transferOwnership(_globalParams._owner);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    INTERNAL STORAGE UPDATE \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Updates storage values related to collateral and debt for an account.\n     * @dev    Called on deposit/borrow, withdraw/repay, liquidation and self liquidation.\n     * @param account            Address of the user whose state is updated.\n     * @param newCollatBalance   Updated collateral balance of the user.\n     * @param newTotalCollat     Updated total collateral of the market.\n     * @param newUserDebtShares  Updated user debt shares.\n     * @param newTotalDebtShares Updated total debt shares of the market.\n     */\n    function _updateCollatAndDebts(address account, uint256 newCollatBalance, uint256 newTotalCollat, uint256 newUserDebtShares, uint256 newTotalDebtShares) internal {\n        // Updates total and use collateral\n        _updateCollateral(account, newCollatBalance, newTotalCollat);\n\n        // Updates total and user debt shares\n        _updateDebts(account, newUserDebtShares, newTotalDebtShares);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        DEPOSITS\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @dev Internal function called during 'deposit' external function.\n     * @param _for            Address of the user/position receiving collateral.\n     * @param amountDeposited Amount of collateral deposited.\n     */\n    function _deposit(address _for, uint256 amountDeposited, IERC20 _collatToken) internal {\n        require(_for != address(0));\n        // Cannot deposit on a market with paused deposits\n        _verifyIsDepositNotPaused();\n        // Cannot deposit 0\n        _verifyCollatInputNotZero(amountDeposited);\n        // Checkpoint the IR and indexes\n        _checkpointIR();\n        // Increase collateral balance of the position and update total debt\n        _updateCollateral(_for, collateralBalances[_for] + amountDeposited, totalCollateral + amountDeposited);\n\n        _postDeposit(_collatToken);\n    }\n\n    /**\n     * @dev Hook after deposit to allow extended logic such as staking the collateral in an underlying protocol.\n     *      When not override, does nothing. Otherwise, refers to the overriding implementation.\n     * @param _collatToken Collateral token being deposited.\n     */\n    function _postDeposit(IERC20 _collatToken) internal virtual {}\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        WITHDRAW\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @dev   Internal function called during 'withdraw' external function.\n     * @param amountToWithdraw Amount of collateral to withdraw.\n     * @param isReceiptOut     When true, receipt token is sent back, when false it's the underlying\n     */\n    function _withdraw(uint256 amountToWithdraw, bool isReceiptOut) internal {\n        // Checkpoint the IR and indexes\n        uint256 newDebtIndex = _checkpointIR();\n\n        // Increase collateral deposited by the user\n        _updateCollateral(\n            msg.sender,\n            _getBalanceAfterWithdrawAndCheckMaxBorrowable(amountToWithdraw, _convertToAmount(userDebtShares[msg.sender], newDebtIndex, Math.Rounding.Ceil)),\n            totalCollateral - amountToWithdraw\n        );\n\n        _transferCollateralWithdraw(msg.sender, amountToWithdraw, isReceiptOut);\n    }\n\n    /**\n     * @dev Computes new collateral balance after withdrawal and checks borrowing limit of maxLTV.\n     * @param amountToWithdraw Amount of collateral to withdraw.\n     * @param newUserDebt      New user debt of the user.\n     * @return Collateral of the user post withdraw\n     */\n    function _getBalanceAfterWithdrawAndCheckMaxBorrowable(uint256 amountToWithdraw, uint256 newUserDebt) internal returns (uint256) {\n        // Prevent to withdraw 0 collateral from the market\n        _verifyCollatInputNotZero(amountToWithdraw);\n        // Computes the decremented collateral balance of the user after the withdraw\n        uint256 newCollatAmount = collateralBalances[msg.sender] - amountToWithdraw;\n\n        // Verify that the newDebt of the loan is not over the maximum borrrowable regarding the LTV of the position\n        _verifyMaxLTV(newCollatAmount, newUserDebt, false);\n\n        return newCollatAmount;\n    }\n\n    /**\n     * @dev Hook transfering collateral to the user.\n     *      When not override, transfer the collateral from the market to the user. Otherwise, refers to the overriding implementation.\n     * @param collatToDeposit Amount of collateral to withdraw from the market.\n     * @param isReceiptIn     Choose to deposit with the receipt token or the LP.\n     */\n    function _transferCollateralDeposit(uint256 collatToDeposit, bool isReceiptIn) internal virtual {\n        collatToken.transferFrom(msg.sender, address(this), collatToDeposit);\n    }\n\n    /**\n     * @dev Hook transfering collateral to the user.\n     *      When not override, transfer the collateral from the market to the user. Otherwise, refers to the overriding implementation.\n     * @param to               Receiver of the collatToken withdrawn\n     * @param collatToWithdraw Amount of collateral to withdraw from the market.\n     * @param isReceiptOut     When true, receipt token is sent back, when false it's the underlying\n     */\n    function _transferCollateralWithdraw(address to, uint256 collatToWithdraw, bool isReceiptOut) internal virtual {\n        collatToken.transfer(to, collatToWithdraw);\n    }\n\n    /* --------\n                            BORROW \n                                                    ------ */\n\n    /**\n     * @dev  Internal function called during 'borrow', 'depositAndBorrow' and 'leverage' external functions.\n     * @param  receiver      Address receiving the borrowed USG.\n     * @param  usgToBorrow Amount of USG to borrow.\n     * @param  collatAmount  Amount of collateral owned by borrower.\n     * @param  isLeverage    Whether this borrow is part of a leverage transaction.\n     * @return userDebtShares updated after borrow\n     * @return totalDebtShares updated of the market after borrow\n     */\n    function _borrow(address receiver, uint256 usgToBorrow, uint256 collatAmount, bool isLeverage) internal returns (uint256, uint256) {\n        _verifyIsBorrowNotPaused();\n        _verifyDebtInputNotZero(usgToBorrow);\n        uint256 newDebtIndex = _checkpointIR();\n\n        uint256 _userDebtShares = userDebtShares[msg.sender];\n\n        uint256 newUserDebt = usgToBorrow + _convertToAmount(_userDebtShares, newDebtIndex, Math.Rounding.Ceil);\n\n        //  Cache the new value in USG of the debt\n        uint256 newUserDebtShares = _convertToShares(usgToBorrow, newDebtIndex, Math.Rounding.Ceil);\n        uint256 newTotalDebtShares = totalDebtShares + newUserDebtShares;\n\n        _verifyDebtCap(newTotalDebtShares, newDebtIndex);\n\n        //  Verify that newDebt is over the minimum loan\n        _verifyMinimumDebt(newUserDebt);\n\n        // Verify that the newDebt of the loan is not over the maximum borrrowable\n        _verifyMaxLTV(collatAmount, newUserDebt, false);\n\n        // If it's a leverage transaction, USG is already minted before\n        if (!isLeverage) {\n            // Mint USG to the receiver\n            _mintUSG(usg, receiver, usgToBorrow);\n        }\n\n        return (_userDebtShares + newUserDebtShares, newTotalDebtShares);\n    }\n\n    /**\n     * @dev  Internal function called during 'depositAndBorrow' and 'leverage' external functions.\n     * @param amountDeposited Amount of collateral to deposit.\n     * @param usgToBorrow   Amount of USG to borrow.\n     * @param isLeverage      Whether this borrow is part of a leverage transaction.\n     */\n    function _depositAndBorrow(uint256 amountDeposited, uint256 usgToBorrow, IERC20 _collatToken, bool isLeverage) internal returns (uint256) {\n        _verifyIsDepositNotPaused();\n        // Cannot deposit 0\n        _verifyCollatInputNotZero(amountDeposited);\n        // Collat amount after the deposit\n        uint256 newCollatAmount = collateralBalances[msg.sender] + amountDeposited;\n\n        (uint256 newUserDebtShare, uint256 newTotalDebtShares) = _borrow(msg.sender, usgToBorrow, newCollatAmount, isLeverage);\n\n        _updateCollatAndDebts(msg.sender, newCollatAmount, totalCollateral + amountDeposited, newUserDebtShare, newTotalDebtShares);\n\n        _postDeposit(_collatToken);\n\n        return newUserDebtShare;\n    }\n\n    /* --------\n                            REPAY\n                                                    ------ */\n\n    /**\n     * @dev  Internal function called during 'repay' and 'repayAndWithdraw' external functions.\n     * @param account        Address that will have its debt repaid\n     * @param USGToRepay   Amount of USG to repay. When this amount is bigger than the actual debt of the user, is replaced by the real debt afterwards.\n     * @return Amount of USG to burn from the sender\n     * @return New user debt shares\n     * @return New total debt shares\n     * @return New user debt\n     */\n    function _repay(address account, uint256 USGToRepay) internal returns (uint256, uint256, uint256, uint256) {\n        // Cannot repay 0 debt\n        _verifyDebtInputNotZero(USGToRepay);\n\n        // Update interests rate, computes new debt index and total debt.\n        uint256 newDebtIndex = _checkpointIR();\n\n        uint256 _userDebtShares = userDebtShares[account];\n\n        uint256 oldUserDebt = _convertToAmount(_userDebtShares, newDebtIndex, Math.Rounding.Ceil);\n\n        // Cannot repay an empty position\n        require(_userDebtShares != 0, UserDebtZero());\n\n        uint256 newUserDebtShares;\n        uint256 sharesToRemove;\n        uint256 newUserDebt;\n\n        // Repay all case\n        // When IR != 0, debt of the user is increasing every block.\n        // It is so complicated to provide the exact amount that a user has to repay to close his loan.\n        // To cover this, any debt given in parameter that is equal or bigger than the debt will close the loan.\n        if (USGToRepay >= oldUserDebt) {\n            // User shouldn't repay more than his debt so we rearrange the amount of USG to repay.\n            USGToRepay = oldUserDebt;\n            // As we are repaying all the debt, the new debt of the user is 0.\n            newUserDebtShares = 0;\n\n            sharesToRemove = _userDebtShares;\n        }\n        // Partial repay case\n        else {\n            // Retrieve the real debt of the user\n            newUserDebt = oldUserDebt - USGToRepay;\n\n            sharesToRemove = _convertToShares(USGToRepay, newDebtIndex, Math.Rounding.Floor);\n\n            newUserDebtShares = _userDebtShares - sharesToRemove;\n\n            // We need to verify that the partial repay is not decreasing the debt lower than the minimum loan.\n            _verifyMinimumDebt(newUserDebt);\n        }\n\n        require(sharesToRemove != 0, ZeroDebtAmount());\n\n        _burnUSG(msg.sender, USGToRepay);\n\n        return (USGToRepay, newUserDebtShares, totalDebtShares - sharesToRemove, newUserDebt);\n    }\n\n    /**\n     * @dev  Internal function called during 'repayAndWithdraw' external functions.\n     * @param amountToWithdraw  Amount of collateral to withdraw\n     * @param USGToRepay        Amount of USG to repay. When this amount is bigger than the actual debt of the user, is replaced by the real debt afterwards.\n     * @return Amount of USG to burn from the sender\n     */\n    function _repayAndWithdraw(uint256 amountToWithdraw, uint256 USGToRepay, bool isReceiptOut) internal returns (uint256, uint256) {\n        // Call _repay function in order to checkpoint the total debt, computes new User debt and burn corresponding amount of USG.\n        (uint256 USGToBurn, uint256 newUserDebtShares, uint256 newTotalDebtShares, uint256 newUserDebt) = _repay(msg.sender, USGToRepay);\n\n        _updateCollatAndDebts(\n            msg.sender,\n            _getBalanceAfterWithdrawAndCheckMaxBorrowable(amountToWithdraw, newUserDebt),\n            totalCollateral - amountToWithdraw,\n            newUserDebtShares,\n            newTotalDebtShares\n        );\n\n        _transferCollateralWithdraw(msg.sender, amountToWithdraw, isReceiptOut);\n\n        return (USGToBurn, newUserDebtShares);\n    }\n\n    /* --------\n                            LIQUIDATION\n                                                    ------ */\n\n    /**\n     * @dev  Internal function called at the begining of 'liquidate', 'selfLiquidate' and 'seizeCollateral' external functions.\n     *       Performs the IR checkpoint and fetch loan parameters\n     * @param account   Address of the position to liquidate\n     * @return LiquidatePre struct composed of :\n     *   -  New index of the debt after the checkpoint\n     *   -  Collateral balances of the 'account'\n     *   -  Debt shares of the 'account'\n     *   -  Debt updated with the new index of the 'account'\n     */\n    function _preLiquidate(address account) internal returns (LiquidationPre memory) {\n        uint256 newDebtIndex = _checkpointIR();\n        uint256 userDebtShares_ = userDebtShares[account];\n        return\n            LiquidationPre({\n                newDebtIndex: newDebtIndex,\n                collatBalance: collateralBalances[account],\n                _userDebtShares: userDebtShares_,\n                userDebt_: _convertToAmount(userDebtShares_, newDebtIndex, Math.Rounding.Ceil)\n            });\n    }\n\n    /**\n     * @dev  Internal function called during 'selfLiquidate' external function.\n     * @param selfLiquidateStruct  Struct containing all variables needed for the self liquidation\n     * @param liquidateCall        Contains address and bytes of the contract selling the collateral for USG\n     * @return The real amount of USG to burn from the account\n     */\n    function _selfLiquidate(SelfLiquidateTransitionStruct memory selfLiquidateStruct, ZapStruct calldata liquidateCall) internal returns (uint256, uint256) {\n        // Need to some collateral\n        _verifyCollatInputNotZero(selfLiquidateStruct.selfLiquidateIn.collatAmountToLiquidate);\n\n        // Computes the new collat balance after liquidating the collateral\n        uint256 newCollatBalance = selfLiquidateStruct._collateralBalance - selfLiquidateStruct.selfLiquidateIn.collatAmountToLiquidate;\n        uint256 debtSharesToRemove;\n        uint256 usgToRepay = selfLiquidateStruct.selfLiquidateIn.usgToRepay;\n\n        // Liquidate All\n        if (usgToRepay >= selfLiquidateStruct.userDebt) {\n            // We override USGToRepay to don't over repay\n            usgToRepay = selfLiquidateStruct.userDebt;\n            // As we liquidate everything, the shares to remove are all the debt shares of the position\n            debtSharesToRemove = selfLiquidateStruct._userDebtShares;\n        }\n        // Liquidate partial\n        else {\n            // As it's a partial liquidation, we have to compute the amount of shares to remove that match with the USG amount to repay.\n            debtSharesToRemove = _convertToShares(usgToRepay, selfLiquidateStruct.newDebtIndex, Math.Rounding.Floor);\n\n            // In case the usgToRepay is very small, we don't want debtShares being equal to 0\n            if (usgToRepay != 0) {\n                require(debtSharesToRemove != 0, ZeroDebtAmount());\n            }\n\n            uint256 newUserDebt = selfLiquidateStruct.userDebt - usgToRepay;\n            // Ensure that the remaining debt is bigger than a minimum in order to leave profitable liquidation\n\n            _verifyMinimumDebt(newUserDebt);\n            // Verify that maxLTV condition is still respected\n            _verifyMaxLTV(newCollatBalance, newUserDebt, false);\n        }\n\n        uint256 newUserDebtShares = selfLiquidateStruct._userDebtShares - debtSharesToRemove;\n\n        // Modify the collateral balance, the user debt and the total debt\n        _updateCollatAndDebts(\n            msg.sender,\n            newCollatBalance,\n            selfLiquidateStruct._totalCollateral - selfLiquidateStruct.selfLiquidateIn.collatAmountToLiquidate,\n            newUserDebtShares,\n            selfLiquidateStruct._totalDebtShares - debtSharesToRemove\n        );\n\n        _postLiquidate(\n            usgToRepay,\n            PostLiquidate({\n                collatAmountToLiquidate: selfLiquidateStruct.selfLiquidateIn.collatAmountToLiquidate,\n                minUsgOut: selfLiquidateStruct.selfLiquidateIn.minUsgOut,\n                maxUsgToBurn: selfLiquidateStruct.selfLiquidateIn.maxUsgToBurn,\n                minCollatAmountToLiquidate: selfLiquidateStruct.selfLiquidateIn.collatAmountToLiquidate,\n                isReceiptOut: selfLiquidateStruct.selfLiquidateIn.isReceiptOut\n            }),\n            liquidateCall\n        );\n\n        return (usgToRepay, newUserDebtShares);\n    }\n    /**\n     * @dev  Internal function called during 'liquidate' external function.\n     * @param liquidateStruct  Struct containing all variables needed for the liquidation\n     * @param liquidateCall   Contains address and bytes of the contract selling the collateral for USG\n     * @return The amount of collateral to liquidate\n     * @return The amount of USG debt repaid\n     * @return The amount of USG taken in liquidation fee\n     */\n    function _liquidate(LiquidateTransitionStruct memory liquidateStruct, ZapStruct calldata liquidateCall) internal returns (uint256, uint256, uint256, uint256) {\n        uint256 collatAmountToLiquidate = liquidateStruct.liquidateIn.postLiquidate.collatAmountToLiquidate;\n        _verifyCollatInputNotZero(collatAmountToLiquidate);\n\n        // Prepare params as if it was a full liquidation\n        uint256 debtSharesToRemove;\n        uint256 usgToRepay;\n\n        // Full liquidation\n        if (collatAmountToLiquidate >= liquidateStruct._collateralBalance) {\n            liquidateStruct.liquidateIn.postLiquidate.collatAmountToLiquidate = liquidateStruct._collateralBalance;\n            collatAmountToLiquidate = liquidateStruct._collateralBalance;\n            usgToRepay = liquidateStruct.userDebt;\n            debtSharesToRemove = liquidateStruct._userDebtShares;\n        }\n        // Partial liquidation\n        else {\n            usgToRepay = (collatAmountToLiquidate * liquidateStruct.userDebt) / liquidateStruct._collateralBalance;\n            debtSharesToRemove = _convertToShares(usgToRepay, liquidateStruct.newDebtIndex, Math.Rounding.Floor);\n            // Ensure that the remaining debt is bigger than a minimum in order to leave profitable liquidation\n            _verifyMinimumDebt(liquidateStruct.userDebt - usgToRepay);\n        }\n\n        // Prevent small amount liquidation that doesn't remove shares\n        require(debtSharesToRemove != 0, ZeroDebtAmount());\n\n        uint256 newUserDebtShares = liquidateStruct._userDebtShares - debtSharesToRemove;\n        // Modify the collateral balance, the user debt and the total debt\n        _updateCollatAndDebts(\n            liquidateStruct.liquidateIn.account,\n            liquidateStruct._collateralBalance - collatAmountToLiquidate,\n            liquidateStruct._totalCollateral - collatAmountToLiquidate,\n            newUserDebtShares,\n            liquidateStruct._totalDebtShares - debtSharesToRemove\n        );\n\n        uint256 fee;\n        {\n            uint256 collatValue = _mulDiv(collatAmountToLiquidate, liquidateStruct.collatPrice, 10 ** collatDecimals);\n            require(collatValue >= liquidateStruct.liquidateIn.minCollatValueToLiquidate, CollatValueToLiquidateTooLow(collatValue));\n            if (collatValue > usgToRepay) {\n                // Fee is taken on the liquidation profits\n                uint256 delta = collatValue - usgToRepay;\n                fee = (liquidationFee * delta) / DENOMINATOR;\n            }\n        }\n        _postLiquidate(usgToRepay + fee, liquidateStruct.liquidateIn.postLiquidate, liquidateCall);\n\n        if (fee != 0) {\n            _mintUSG(usg, controlTower.feeTreasury(), fee);\n        }\n\n        return (collatAmountToLiquidate, usgToRepay, fee, newUserDebtShares);\n    }\n\n    /**\n     * @dev  Internal function called at the end of 'liquidate' and 'selfLiquidate' external function.\n     *       Withdraw the collateral from the underlying protocol\n     *       Transfer the collateral to the caller or to the zapping proxy\n     *       When the collateral is sent to the zapping proxy, the 'liquidationCall' handles the selling of the collateral\n     * @param usgToBurn      Amount of collateral to sell during the liquidation\n     * @param postLiquidate  Struct containing :\n     *                          - collatAmountToLiquidate : Amount of token to send to the liquidator\n     *                          - minUsgOut : Minimum amount of USG to receive from the sell of the collateral if a router is used.\n     *                          - maxUsgToBurn : Maximum amount of USG to be burnt from the caller of the function at the end of the tx.\n     *                          - minAmountToLiquidate : Minimum amount of collateral to liquidate, used to protect liquidator from potential partial liquidation coming before its liquidation.\n     *                          - isReceiptOut :\n     * @param liquidationCall          Contains address and bytes of the contract selling the collateral for USG\n     */\n    function _postLiquidate(uint256 usgToBurn, PostLiquidate memory postLiquidate, ZapStruct calldata liquidationCall) internal {\n        require(usgToBurn <= postLiquidate.maxUsgToBurn, MaxUSGToBurn());\n        require(postLiquidate.minCollatAmountToLiquidate <= postLiquidate.collatAmountToLiquidate, MinCollatToLiquidate(postLiquidate.collatAmountToLiquidate));\n        IZappingProxy _zappingProxy = zappingProxy;\n        // Withdraw the collateral from the underlying protocol if needed and\n        // Transfer it to the caller when there is no liquidator passed in parameter\n        // If a liquidator is passed, we send the collateral to the Zapping Proxy that will handle the selling of the collateral.\n        _transferCollateralWithdraw(liquidationCall.router != address(0) ? address(_zappingProxy) : msg.sender, postLiquidate.collatAmountToLiquidate, postLiquidate.isReceiptOut);\n        // When liquidator is not zero, it allows to the LiquidatorProxy to receive the collateral.\n        // Then, if needed, liquidator will allow the custom Liquidator to sell the collateral for USG in the same transaction.\n        if (liquidationCall.router != address(0)) {\n            // Block the zap liquidation with the receipt, can only be done with the collateral directly.\n            require(!postLiquidate.isReceiptOut, NoZapLiquidateWithReceipt());\n            _zappingProxy.zapProxy(collatToken, usg, postLiquidate.minUsgOut, msg.sender, liquidationCall);\n        }\n\n        // Burns USG from the sender.\n        // The debt has to be on the caller of the transaction.\n        // In case a liquidator is passed in parameter, it needs to send it back to the sender of the tx.\n        _burnUSG(msg.sender, usgToBurn);\n    }\n\n    /**\n     * @dev  Internal function called during 'seizeCollateral' external function.\n     * @param account              Address that gets its collateral seized\n     * @param _collateralBalance   Balance of collateral of the 'account'\n     * @param _totalCollateral     Total collateral deposited on the market\n     * @param _userDebtShares      Debt shares of the 'account'\n     * @param _totalDebtShares     Total debt shares of the market\n     * @param _accountDebt         Debt of the 'account'\n     */\n    function _seizeCollateral(\n        address account,\n        uint256 _collateralBalance,\n        uint256 _totalCollateral,\n        uint256 _userDebtShares,\n        uint256 _totalDebtShares,\n        uint256 _accountDebt\n    ) internal {\n        // Updates total and user values for collaterals & debts\n        // Collat Balance and user debt are updated to 0 because the whole position is liquidated\n        _updateCollatAndDebts(account, 0, _totalCollateral - _collateralBalance, 0, _totalDebtShares - _userDebtShares);\n\n        // Bad debt is written in the market\n        badDebt += _accountDebt;\n\n        // The collateral is sent to the DAO to decide what to do with it\n        _transferCollateralWithdraw(controlTower.feeTreasury(), _collateralBalance, false);\n    }\n\n    /* --------\n                        LEVERAGE\n                                                    ------ */\n\n    /**\n     * @dev  Internal function called during 'leverage' external function.\n     * @param _collatToken       Collateral token interface\n     * @param  leverageIn    Struct containing :\n     *                                            - Amount of collateral to deposit, can be 0\n     *                                            - Amount of USG to mint that is sold for collateral, will be incremented to userDebt.\n     *                                            - Slippage, minimum amount of collatAmount to receive from the selling of USG.\n     *                                            - Contract and data allowing to sell the USG for collateral.\n     * @param  dumpUSGCall  Contains address and bytes of the contract to sell USG for collateral\n     * @return Amount of collateral bought with the 'USGToFlashMint'\n     * @return Amount of collareal to stake for the sender\n     */\n    function _leverage(IERC20 _collatToken, LeverageIn memory leverageIn, ZapStruct calldata dumpUSGCall) internal returns (uint256, uint256, uint256) {\n        _verifyIsDepositNotPaused();\n        require(isLeveragePaused == 0, LeveragePaused());\n\n        IUSG _usg = usg;\n\n        IZappingProxy _zappingProxy = zappingProxy;\n\n        // Mint the USG on the Zapper, ready to be exchanged through the router\n        _mintUSG(_usg, address(_zappingProxy), leverageIn.usgToFlashMint);\n\n        // Exchange the USG that has just been minted on the Zapper for the collateral of the market\n        uint256 collatBought = _zappingProxy.zapProxy(_usg, collatToken, leverageIn.minCollatAmountOut, address(this), dumpUSGCall);\n\n        uint256 stakedAmount = leverageIn.collatToDeposit + collatBought;\n\n        // Performs same modification as in depositAndBorrow\n        uint256 newUserDebtShares = _depositAndBorrow(stakedAmount, leverageIn.usgToFlashMint, _collatToken, true);\n\n        return (collatBought, stakedAmount, newUserDebtShares);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                     REWARDS\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n    /**\n     * @dev  Internal function called during 'claimUnderlyingRewards' external function.\n     *\n     * @param _rewardTokens       Collateral token interface\n     * @return Amount of collateral bought with the 'USGToFlashMint'\n     */\n    function _claimUnderlyingRewards(IERC20[] memory _rewardTokens) internal returns (TokenAmount[] memory) {\n        uint256 rewardLen = _rewardTokens.length;\n        TokenAmount[] memory rewardAmounts = new TokenAmount[](rewardLen);\n        address _rewardAccumulator = address(rewardAccumulator);\n\n        uint256 counter;\n\n        for (uint256 i; i < rewardLen; ) {\n            IERC20 rewardToken = _rewardTokens[i];\n            uint256 balance = rewardToken.balanceOf(address(this));\n            if (balance != 0) {\n                rewardAmounts[counter++] = TokenAmount({token: rewardToken, amount: balance});\n                rewardToken.safeTransfer(address(_rewardAccumulator), balance);\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        /// @dev Reduce length of tokenAmounts struct to not return useless 0\n        if (rewardAmounts.length != 0) {\n            // solhint-disable-next-line no-inline-assembly\n            assembly {\n                mstore(rewardAmounts, sub(mload(rewardAmounts), sub(rewardLen, counter)))\n            }\n        }\n\n        return rewardAmounts;\n    }\n    /**\n     * @dev  Function to override to claim rewards given by the collateral\n     */\n    function _claimRewards() internal virtual {}\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    MIGRATE\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    function _verifySenderMigrator() internal view {\n        require(controlTower.isPositionMigrator(msg.sender), NotAMigratoor());\n    }\n\n    function _migrateFrom(address account, uint256 collateralToRemove, uint256 debtToRemove, uint256 debtToRepay, address receiver) internal returns (uint256, uint256) {\n        _verifySenderMigrator();\n        uint256 newDebtIndex = _checkpointIR();\n\n        uint256 uDebtShares = userDebtShares[account];\n        uint256 debtUser = _convertToAmount(uDebtShares, newDebtIndex, Math.Rounding.Ceil);\n        uint256 newCollatBalance = collateralBalances[account] - collateralToRemove;\n        uint256 sharesToRemove;\n        uint256 newUserDebt;\n\n        // Debt to remove from source market is bigger than the one to repay\n        require(debtToRemove >= debtToRepay, DebtToRepayTooBig());\n\n        // All the debt is removed from marketFrom\n        if (debtToRemove >= debtUser) {\n            sharesToRemove = uDebtShares;\n            debtToRemove = debtUser;\n\n            // All the user debt is repaid from marketFrom\n            if (debtToRepay >= debtUser) {\n                debtToRepay = debtUser;\n            }\n        }\n        // Only a part of the debt is removed from marketFrom\n        else {\n            sharesToRemove = _convertToShares(debtToRemove, newDebtIndex, Math.Rounding.Floor);\n            newUserDebt = debtUser - debtToRemove;\n            // We check both condition on minimum loan and maxLTV\n            // Dont need to check them when the new user debt is equal to 0\n            _verifyMinimumDebt(newUserDebt);\n            _verifyMaxLTV(newCollatBalance, newUserDebt, false);\n        }\n\n        uint256 newUDebtShares = uDebtShares - sharesToRemove;\n        // Update user and total debts and collaterals.\n        _updateCollatAndDebts(account, newCollatBalance, totalCollateral - collateralToRemove, newUDebtShares, totalDebtShares - sharesToRemove);\n        // Transfer the collateral :\n        //      - Zapping proxy, if collats are different\n        //      OR\n        //      - Market to, if collats are the same\n        _transferCollateralWithdraw(receiver, collateralToRemove, false);\n\n        // If some debt are to repay, burn it from the caller of the migrator\n        if (debtToRepay != 0) {\n            _burnUSG(account, debtToRepay);\n        }\n\n        return (debtToRemove - debtToRepay, newUDebtShares);\n    }\n\n    function _migrateTo(address account, uint256 collatToAdd, uint256 debtToAdd) internal returns (uint256) {\n        _verifySenderMigrator();\n        if (collatToAdd != 0) {\n            _verifyIsDepositNotPaused();\n        }\n        if (debtToAdd != 0) {\n            _verifyIsBorrowNotPaused();\n        }\n        uint256 debtIndex = _checkpointIR();\n\n        uint256 uDebtShares = userDebtShares[account];\n        uint256 newUserDebt = _convertToAmount(uDebtShares, debtIndex, Math.Rounding.Ceil) + debtToAdd;\n        uint256 newCollatBalance = collateralBalances[account] + collatToAdd;\n        uint256 sharesToAdd = _convertToShares(debtToAdd, debtIndex, Math.Rounding.Ceil);\n        uint256 newTotalDebtShares = totalDebtShares + sharesToAdd;\n        uint256 newUserDebtShares = uDebtShares + sharesToAdd;\n\n        // We check both condition on minimum loan and maxLTV\n        // Dont need to check them when the new user debt is equal to 0\n        if (newUserDebt != 0) {\n            _verifyMinimumDebt(newUserDebt);\n            _verifyMaxLTV(newCollatBalance, newUserDebt, false);\n            _verifyDebtCap(newTotalDebtShares, debtIndex);\n        }\n\n        _updateCollatAndDebts(account, newCollatBalance, totalCollateral + collatToAdd, newUserDebtShares, newTotalDebtShares);\n\n        _postDeposit(collatToken);\n\n        return newUserDebtShares;\n    }\n}\n"},{"file_path":"src/USG/Utilities/abstract/LightOwnable.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nabstract contract LightOwnable {\n    address public owner;\n\n    error OwnableUnauthorizedAccount(address account);\n\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner != msg.sender) {\n            revert OwnableUnauthorizedAccount(msg.sender);\n        }\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = owner;\n        owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"src/USG/Market/abstract/PauseSettings.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {LightOwnable} from \"../../Utilities/abstract/LightOwnable.sol\";\nimport {IControlTower} from \"../../../interfaces/internals/USG/IControlTower.sol\";\n\n/// @author Tangent Finance\n\nabstract contract PauseSettings is LightOwnable {\n    enum PauseEnum {\n        DepositPaused,\n        BorrowPaused,\n        LeveragePaused\n    }\n    /// @notice Reference to the ControlTower contract managing market governance and treasury.\n    IControlTower controlTower;\n\n    uint64 isInitialized;\n\n    /// @notice Pauses new deposits on the market\n    uint64 isDepositPaused;\n\n    /// @notice Pauses new borrows on the market\n    uint64 isBorrowPaused;\n\n    /// @notice Pauses new leverages on the market\n    uint64 isLeveragePaused;\n\n    error DepositPaused();\n    error BorrowPaused();\n    error LeveragePaused();\n    error CallerNotPauser();\n\n    event PauseTrigger(PauseEnum pauseType, uint64 isPaused);\n\n    modifier isCallerPauser() {\n        _verifyIsCallerPauser();\n        _;\n    }\n\n    function _verifyIsCallerPauser() internal view {\n        require(controlTower.isPauser(msg.sender), CallerNotPauser());\n    }\n\n    function _verifyIsDepositNotPaused() internal view {\n        require(isDepositPaused == 0, DepositPaused());\n    }\n\n    function _verifyIsBorrowNotPaused() internal view {\n        require(isBorrowPaused == 0, BorrowPaused());\n    }\n\n    function setPause(PauseEnum pauseType, uint64 isPaused) external isCallerPauser {\n        if (pauseType == PauseEnum.DepositPaused) {\n            isDepositPaused = isPaused;\n        } else if (pauseType == PauseEnum.BorrowPaused) {\n            isBorrowPaused = isPaused;\n        } else {\n            isLeveragePaused = isPaused;\n        }\n        emit PauseTrigger(pauseType, isPaused);\n    }\n\n    function getPausedSettings() external view returns (uint64, uint64, uint64) {\n        return (isDepositPaused, isBorrowPaused, isLeveragePaused);\n    }\n}\n"},{"file_path":"src/USG/Market/abstract/DebtIR.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\n\nimport {IUSG} from \"../../../interfaces/internals/USG/IUSG.sol\";\nimport {IDebtIR} from \"../../../interfaces/internals/USG/IDebtIR.sol\";\nimport {IIRCalculator} from \"../../../interfaces/internals/USG/IIRCalculator.sol\";\nimport {LightOwnable} from \"../../Utilities/abstract/LightOwnable.sol\";\nimport {LightReentrancyGuardTransient} from \"../../Utilities/abstract/LightReentrancyGuardTransient.sol\";\n\n/// @title DebtIR - Computes debts for a market\n/// @author Tangent Finance\n/// @notice Abstract contract to track debt issuance and bad debt\n/// @dev Inherits access control (LightOwnable) and reentrancy protection\nabstract contract DebtIR is LightOwnable, IDebtIR, LightReentrancyGuardTransient {\n    /// @notice Precision factor (10^27)\n    uint256 constant RAY = 1e27;\n\n    /// @notice Contract that calculates and updates interest rate and debt indexes\n    IIRCalculator public irCalculator;\n\n    /// @notice The USG token contract\n    IUSG usg;\n\n    /// @notice Maximum allowable total debt in the market (in USG units)\n    uint256 public maxMarketDebt;\n\n    /// @notice Minimum loan size allowed, used to ensure economic viability of liquidations (especially on L1)\n    uint256 public minimumLoan;\n\n    /// @notice Total amount of bad debt in the system (unrecoverable or defaulted loans)\n    uint256 public badDebt;\n\n    /// @notice Aggregate of all user debt shares\n    uint256 public totalDebtShares;\n\n    /// @notice Mapping of user addresses to their debt shares\n    mapping(address => uint256) public userDebtShares;\n\n    /// @notice Error raised when attempting to repay more bad debt than exists\n    error RepayMoreThanBadDebt();\n    error TotalDebtTooHigh();\n    error UserDebtTooLow();\n    error UserDebtZero();\n    error ZeroDebtAmount();\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        OWNER ACTIONS \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    event SetMaxMarketDebt(uint256 newMaxMarketDebt);\n    event SetMinimumLoan(uint256 newMinimumLoan);\n    event RepayBadDebt(address user, uint256 badDebtRepaid);\n\n    /**\n     * @notice Sets a new maximum market debt\n     * @dev Callable only by the DAO governance\n     * @param _maxMarketDebt The new maximum debt allowed in the system\n     */\n    function setMaxMarketDebt(uint256 _maxMarketDebt) external onlyOwner {\n        maxMarketDebt = _maxMarketDebt;\n        emit SetMaxMarketDebt(_maxMarketDebt);\n    }\n\n    /**\n     * @notice Sets the minimum loan size a user can borrow\n     * @dev Used to discourage small loans that are unprofitable to liquidate\n     * @param _minimumLoan The new minimum loan size in USG\n     */\n    function setMinimumLoan(uint256 _minimumLoan) external onlyOwner {\n        minimumLoan = _minimumLoan;\n        emit SetMinimumLoan(_minimumLoan);\n    }\n\n    /**\n     * @notice Allows anyone to repay bad debt by burning USG\n     * @dev Burns `amount` of USG from the sender, reducing the global bad debt\n     * @param amount The amount of USG to repay from bad debt\n     */\n    function repayBadDebt(uint256 amount) external nonReentrant {\n        uint256 _badDebt = badDebt;\n        require(amount <= _badDebt, RepayMoreThanBadDebt());\n        badDebt = _badDebt - amount;\n        _burnUSG(msg.sender, amount);\n\n        emit RepayBadDebt(msg.sender, amount);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    INTERNAL STORAGE UPDATE \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Updates debt shares for a user and the market total\n     * @dev Must be called whenever borrowing or repaying to sync the internal accounting\n     * @param account            Address of the user\n     * @param newUserDebtShare   New debt share for the user\n     * @param newTotalDebtShares New total market debt shares\n     */\n    function _updateDebts(address account, uint256 newUserDebtShare, uint256 newTotalDebtShares) internal {\n        userDebtShares[account] = newUserDebtShare;\n        totalDebtShares = newTotalDebtShares;\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    INTERNAL VIEWS \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @dev   Convert a debt amount to a debt shares\n     * @param  debt  Debt amount\n     * @param  index Debt index of the market\n     * @return debtShares\n     */\n    function _convertToShares(uint256 debt, uint256 index, Math.Rounding roundingType) internal pure returns (uint256) {\n        return Math.mulDiv(debt, RAY, index, roundingType);\n    }\n\n    /**\n     * @dev   Convert a debt shares to a debt amount\n     * @param  debtShares  Debt shares\n     * @param  index       Debt index of the market\n     * @return debtAmount\n     */\n    function _convertToAmount(uint256 debtShares, uint256 index, Math.Rounding roundingType) internal pure returns (uint256) {\n        return Math.mulDiv(debtShares, index, RAY, roundingType);\n    }\n\n    /**\n     * @dev   Multiply two numbers `a` and `b`then divide the result by `d`\n     * @param a  First number of the product\n     * @param b  Second number of the product\n     * @param d  Denominator\n     * @return Result of the operation\n     */\n    function _mulDiv(uint256 a, uint256 b, uint256 d) internal pure returns (uint256) {\n        return (a * b) / d;\n    }\n\n    /**\n     * @dev   Burns some USG from an account\n     * @param account Account from where to burn USG\n     * @param amount  Amount of USG to burn\n     */\n    function _burnUSG(address account, uint256 amount) internal {\n        usg.burnDebt(account, amount);\n    }\n\n    /**\n     * @dev   Mints an USG `amount` on an `account`\n     * @param _usg    USG token\n     * @param account Account to mint USG on\n     * @param amount  Amount of USG to mint\n     */\n    function _mintUSG(IUSG _usg, address account, uint256 amount) internal {\n        _usg.mintDebt(account, amount);\n    }\n\n    /**\n     * @dev  Computes and update the debtIndex on the IRCalculator and returns the new one\n     * @return The new debt index of the market\n     */\n    function _checkpointIR() internal returns (uint256) {\n        return irCalculator.checkpointIR(address(this));\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        VERIFIERS \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @dev Fails if the new amount of total debt is over the maximum debt of the market\n     * @param totalShares Total debt shares on the market\n     * @param debtIndex   Debt index of the market\n\n     */\n    function _verifyDebtCap(uint256 totalShares, uint256 debtIndex) internal view {\n        require(badDebt + _convertToAmount(totalShares, debtIndex, Math.Rounding.Ceil) <= maxMarketDebt, TotalDebtTooHigh());\n    }\n\n    /**\n     * @dev Fails if the amount of debt for an account is under the minimum loan allowed\n     * @param debt  Debt amount of the user\n     */\n    function _verifyMinimumDebt(uint256 debt) internal view {\n        require(debt >= minimumLoan, UserDebtTooLow());\n    }\n\n    /**\n     * @dev Fails if the amount of debt in input is null\n     * @param debt  Debt amount to borrow or repay\n     */\n    function _verifyDebtInputNotZero(uint256 debt) internal pure {\n        require(debt != 0, ZeroDebtAmount());\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with an success flag (no overflow).\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n     *\n     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n     * one branch when needed, making this function more expensive.\n     */\n    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n        unchecked {\n            // branchless ternary works because:\n            // b ^ (a ^ b) == a\n            // b ^ 0 == b\n            return b ^ ((a ^ b) * SafeCast.toUint(condition));\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return ternary(a > b, a, b);\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return ternary(a < b, a, b);\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n\n        // The following calculation ensures accurate ceiling division without overflow.\n        // Since a is non-zero, (a - 1) / b will not overflow.\n        // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n        // but the largest value we can obtain is type(uint256).max - 1, which happens\n        // when a = type(uint256).max and b = 1.\n        unchecked {\n            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n        }\n    }\n\n    /**\n     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     *\n     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n            // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2²⁵⁶ + prod0.\n            uint256 prod0 = x * y; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n            if (denominator <= prod1) {\n                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n            inverse *= 2 - denominator * inverse; // inverse mod 2³²\n            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n    }\n\n    /**\n     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n     *\n     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n     *\n     * If the input value is not inversible, 0 is returned.\n     *\n     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n     */\n    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n        unchecked {\n            if (n == 0) return 0;\n\n            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n            // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n            // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n            // ax + ny = 1\n            // ax = 1 + (-y)n\n            // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n            // If the remainder is 0 the gcd is n right away.\n            uint256 remainder = a % n;\n            uint256 gcd = n;\n\n            // Therefore the initial coefficients are:\n            // ax + ny = gcd(a, n) = n\n            // 0a + 1n = n\n            int256 x = 0;\n            int256 y = 1;\n\n            while (remainder != 0) {\n                uint256 quotient = gcd / remainder;\n\n                (gcd, remainder) = (\n                    // The old remainder is the next gcd to try.\n                    remainder,\n                    // Compute the next remainder.\n                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n                    // where gcd is at most n (capped to type(uint256).max)\n                    gcd - remainder * quotient\n                );\n\n                (x, y) = (\n                    // Increment the coefficient of a.\n                    y,\n                    // Decrement the coefficient of n.\n                    // Can overflow, but the result is casted to uint256 so that the\n                    // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n                    x - y * int256(quotient)\n                );\n            }\n\n            if (gcd != 1) return 0; // No inverse exists.\n            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n        }\n    }\n\n    /**\n     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n     *\n     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n     *\n     * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n     */\n    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n        unchecked {\n            return Math.modExp(a, p - 2, p);\n        }\n    }\n\n    /**\n     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n     *\n     * Requirements:\n     * - modulus can't be zero\n     * - underlying staticcall to precompile must succeed\n     *\n     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n     * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n     * interpreted as 0.\n     */\n    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n        (bool success, uint256 result) = tryModExp(b, e, m);\n        if (!success) {\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n     * to operate modulo 0 or if the underlying precompile reverted.\n     *\n     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n     * of a revert, but the result may be incorrectly interpreted as 0.\n     */\n    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n        if (m == 0) return (false, 0);\n        assembly (\"memory-safe\") {\n            let ptr := mload(0x40)\n            // | Offset    | Content    | Content (Hex)                                                      |\n            // |-----------|------------|--------------------------------------------------------------------|\n            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n            // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n            mstore(ptr, 0x20)\n            mstore(add(ptr, 0x20), 0x20)\n            mstore(add(ptr, 0x40), 0x20)\n            mstore(add(ptr, 0x60), b)\n            mstore(add(ptr, 0x80), e)\n            mstore(add(ptr, 0xa0), m)\n\n            // Given the result < m, it's guaranteed to fit in 32 bytes,\n            // so we can use the memory scratch space located at offset 0.\n            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n            result := mload(0x00)\n        }\n    }\n\n    /**\n     * @dev Variant of {modExp} that supports inputs of arbitrary length.\n     */\n    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n        (bool success, bytes memory result) = tryModExp(b, e, m);\n        if (!success) {\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n     */\n    function tryModExp(\n        bytes memory b,\n        bytes memory e,\n        bytes memory m\n    ) internal view returns (bool success, bytes memory result) {\n        if (_zeroBytes(m)) return (false, new bytes(0));\n\n        uint256 mLen = m.length;\n\n        // Encode call args in result and move the free memory pointer\n        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n        assembly (\"memory-safe\") {\n            let dataPtr := add(result, 0x20)\n            // Write result on top of args to avoid allocating extra memory.\n            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n            // Overwrite the length.\n            // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n            mstore(result, mLen)\n            // Set the memory pointer after the returned data.\n            mstore(0x40, add(dataPtr, mLen))\n        }\n    }\n\n    /**\n     * @dev Returns whether the provided byte array is zero.\n     */\n    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n        for (uint256 i = 0; i < byteArray.length; ++i) {\n            if (byteArray[i] != 0) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n     * using integer operations.\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        unchecked {\n            // Take care of easy edge cases when a == 0 or a == 1\n            if (a <= 1) {\n                return a;\n            }\n\n            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n            // the current value as `ε_n = | x_n - sqrt(a) |`.\n            //\n            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n            // bigger than any uint256.\n            //\n            // By noticing that\n            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n            // to the msb function.\n            uint256 aa = a;\n            uint256 xn = 1;\n\n            if (aa >= (1 << 128)) {\n                aa >>= 128;\n                xn <<= 64;\n            }\n            if (aa >= (1 << 64)) {\n                aa >>= 64;\n                xn <<= 32;\n            }\n            if (aa >= (1 << 32)) {\n                aa >>= 32;\n                xn <<= 16;\n            }\n            if (aa >= (1 << 16)) {\n                aa >>= 16;\n                xn <<= 8;\n            }\n            if (aa >= (1 << 8)) {\n                aa >>= 8;\n                xn <<= 4;\n            }\n            if (aa >= (1 << 4)) {\n                aa >>= 4;\n                xn <<= 2;\n            }\n            if (aa >= (1 << 2)) {\n                xn <<= 1;\n            }\n\n            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n            //\n            // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n            // This is going to be our x_0 (and ε_0)\n            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n            // From here, Newton's method give us:\n            // x_{n+1} = (x_n + a / x_n) / 2\n            //\n            // One should note that:\n            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n            //              = ((x_n² + a) / (2 * x_n))² - a\n            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n            //              = (x_n² - a)² / (2 * x_n)²\n            //              = ((x_n² - a) / (2 * x_n))²\n            //              ≥ 0\n            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n            //\n            // This gives us the proof of quadratic convergence of the sequence:\n            // ε_{n+1} = | x_{n+1} - sqrt(a) |\n            //         = | (x_n + a / x_n) / 2 - sqrt(a) |\n            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n            //         = | (x_n - sqrt(a))² / (2 * x_n) |\n            //         = | ε_n² / (2 * x_n) |\n            //         = ε_n² / | (2 * x_n) |\n            //\n            // For the first iteration, we have a special case where x_0 is known:\n            // ε_1 = ε_0² / | (2 * x_0) |\n            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))\n            //     ≤ 2**(e-3) / 3\n            //     ≤ 2**(e-3-log2(3))\n            //     ≤ 2**(e-4.5)\n            //\n            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n            // ε_{n+1} = ε_n² / | (2 * x_n) |\n            //         ≤ (2**(e-k))² / (2 * 2**(e-1))\n            //         ≤ 2**(2*e-2*k) / 2**e\n            //         ≤ 2**(e-2*k)\n            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above\n            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5\n            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9\n            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18\n            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36\n            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72\n\n            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n            // sqrt(a) or sqrt(a) + 1.\n            return xn - SafeCast.toUint(xn > a / xn);\n        }\n    }\n\n    /**\n     * @dev Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        uint256 exp;\n        unchecked {\n            exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);\n            value >>= exp;\n            result += exp;\n\n            result += SafeCast.toUint(value > 1);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        uint256 isGt;\n        unchecked {\n            isGt = SafeCast.toUint(value > (1 << 128) - 1);\n            value >>= isGt * 128;\n            result += isGt * 16;\n\n            isGt = SafeCast.toUint(value > (1 << 64) - 1);\n            value >>= isGt * 64;\n            result += isGt * 8;\n\n            isGt = SafeCast.toUint(value > (1 << 32) - 1);\n            value >>= isGt * 32;\n            result += isGt * 4;\n\n            isGt = SafeCast.toUint(value > (1 << 16) - 1);\n            value >>= isGt * 16;\n            result += isGt * 2;\n\n            result += SafeCast.toUint(value > (1 << 8) - 1);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"},{"file_path":"src/interfaces/internals/USG/IControlTower.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IERC20, IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport {IDebtIR} from \"./IDebtIR.sol\";\n\ninterface IControlTower {\n    function isMarketCreator(address marketCreator) external view returns (bool);\n\n    function isPositionMigrator(address migrator) external view returns (bool);\n\n    function isPauser(address pauser) external view returns (bool);\n\n    function feeTreasury() external view returns (address);\n}\n"},{"file_path":"src/USG/Market/abstract/Collateral.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {IERC20, IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {IPriceOracle} from \"../../../interfaces/internals/USG/IPriceOracle.sol\";\nimport {ICollateral} from \"../../../interfaces/internals/USG/ICollateral.sol\";\nimport {IRewardAccumulator} from \"../../../interfaces/internals/USG/IRewardAccumulator.sol\";\n\nimport {DebtIR} from \"./DebtIR.sol\";\n\n/// @title Collateral\n/// @author Tangent Finance\n/// @notice Abstract contract that defines collateral management logic\nabstract contract Collateral is DebtIR, ICollateral {\n    /// @dev Maximum uint256 value\n    uint256 constant MAX_UINT = uint256(int256(-1));\n\n    /// @notice Denominator used for percentage calculations (e.g. 100% = 100_000)\n    uint256 constant DENOMINATOR = 100_000;\n\n    /// @notice The amount of decimals of the collateral\n    uint256 public collatDecimals;\n\n    /// @notice Collateral token\n    IERC20Metadata public collatToken;\n\n    /// @notice Oracle for retrieving collateral price in USD (1e18 precision)\n    IPriceOracle public collatOracle;\n\n    /// @notice Contract to track or distribute collateral rewards\n    IRewardAccumulator public rewardAccumulator;\n\n    /// @notice Maximum Loan-to-Value ratio (e.g., 75% = 75,000)\n    uint256 public maxLTV;\n\n    /// @notice Threshold where liquidation begins (must be > maxLTV)\n    uint256 public liquidationThreshold;\n\n    /// @notice Liquidation fee charged in USG (e.g., 5% = 5,000)\n    uint256 public liquidationFee;\n\n    /// @notice Total collateral deposited across all users\n    uint256 public totalCollateral;\n\n    /// @notice Mapping of user address to their collateral balance\n    mapping(address => uint256) public collateralBalances;\n\n    // Error declarations for specific failure conditions\n    error MaxLTVBiggerThanLiquidationThreshold();\n    error LiquidationThresholdTooHigh();\n    error LiquidationThresholdTooLow();\n    error LiquidationFeeTooHigh();\n    error MaxLTVTooHigh();\n    error MaxLTVTooLow();\n    error OverMaxLTV();\n    error ZeroCollatAmount();\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    OWNER ACTIONS \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    event SetOracle(IPriceOracle newOracle);\n    event SetMaxLTV(uint256 newMaxLTV);\n    event SetLiquidationThreshold(uint256 newLiquidationThreshold);\n    event SetLiquidationFee(uint256 newLiquidationFee);\n\n    /**\n     * @notice Updates the oracle used to fetch collateral price\n     * @dev Callable only by contract owner (DAO or governance)\n     * @param _collatOracle Address of the new oracle contract\n     */\n    function setCollatOracle(IPriceOracle _collatOracle) external onlyOwner {\n        collatOracle = _collatOracle;\n        emit SetOracle(_collatOracle);\n    }\n\n    /**\n     * @notice Updates the max LTV (Loan to Value) ratio\n     * @dev Must be less than the current liquidation threshold\n     * @param _maxLTV New maxLTV value (e.g., 75,000 for 75%)\n     */\n    function setMaxLTV(uint256 _maxLTV) external onlyOwner {\n        require(_maxLTV < liquidationThreshold, MaxLTVBiggerThanLiquidationThreshold());\n        maxLTV = _maxLTV;\n        emit SetMaxLTV(_maxLTV);\n    }\n\n    /**\n     * @notice Updates the liquidation threshold\n     * @dev Must be between maxLTV and 100% (DENOMINATOR)\n     * @param _liquidationThreshold New liquidation threshold value\n     */\n    function setLiquidationThreshold(uint256 _liquidationThreshold) external onlyOwner {\n        require(_liquidationThreshold < DENOMINATOR, LiquidationThresholdTooHigh());\n        require(_liquidationThreshold > maxLTV, LiquidationThresholdTooLow());\n        liquidationThreshold = _liquidationThreshold;\n        emit SetLiquidationThreshold(_liquidationThreshold);\n    }\n\n    /**\n     * @notice Updates the liquidation fee\n     * @dev Cannot exceed 80% (80,000)\n     * @param _liquidationFee New liquidation fee in base 100,000\n     */\n    function setLiquidationFee(uint256 _liquidationFee) external onlyOwner {\n        require(_liquidationFee <= 80_000, LiquidationFeeTooHigh());\n        liquidationFee = _liquidationFee;\n        emit SetLiquidationFee(_liquidationFee);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    INTERNAL STORAGE UPDATE \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @dev Internal function to update a user's collateral balance and the total collateral\n     * @param account The user account to update\n     * @param newCollatBalance The new collateral amount for the user\n     * @param newTotalCollat The new total collateral amount across all users\n     */\n    function _updateCollateral(address account, uint256 newCollatBalance, uint256 newTotalCollat) internal {\n        totalCollateral = newTotalCollat;\n        collateralBalances[account] = newCollatBalance;\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                         PUBLIC VIEWS\n     =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Returns both user collateral balance and total system collateral\n     * @param account Address of the user\n     * @return balance User's collateral balance\n     * @return total Total system collateral\n     */\n    function getBalanceAndTotalCollateral(address account) external view returns (uint256, uint256) {\n        return (collateralBalances[account], totalCollateral);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        INTERNAL UPDATES\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n    /**\n     * @dev Returns the current price of 1 unit of collateral in USD (1e18 precision) and store last good value in oracle if needed\n     */\n    function _collateralPriceUpdate(bool isNoFailMode) internal returns (uint256) {\n        return collatOracle.latestAnswerUpdate(isNoFailMode);\n    }\n\n    /**\n     * @dev Computes USD value of the given amount of collateral and store last good value in oracle if needed\n     * @param collatAmount Amount of collateral\n     * @return Value in USD (1e18 base)\n     */\n    function _positionValueUpdate(uint256 collatAmount, bool isNoFailMode) internal returns (uint256) {\n        return _mulDiv(collatAmount, _collateralPriceUpdate(isNoFailMode), 10 ** collatDecimals);\n    }\n\n    /**\n     * @dev Compare the value of an amount of collateral with an amount of debt to the maxLTV of the market\n     *      and fails if it's not respected + store last good value in oracle if needed\n     * @param collatAmount Amount of collateral\n     * @param debt         Amount of debt\n     * @param isNoFailMode If true, will fail if the oracle is stale\n     */\n    function _verifyMaxLTV(uint256 collatAmount, uint256 debt, bool isNoFailMode) internal {\n        require(_mulDiv(maxLTV, _positionValueUpdate(collatAmount, isNoFailMode), DENOMINATOR) >= debt, OverMaxLTV());\n    }\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        INTERNAL VIEWS\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @dev Fails if the amount of collateral to deposit or withdraw is null\n     * @param collatAmount Collat amount to deposit or withdraw\n     */\n    function _verifyCollatInputNotZero(uint256 collatAmount) internal pure {\n        require(collatAmount != 0, ZeroCollatAmount());\n    }\n}\n"},{"file_path":"src/interfaces/internals/ICommonStruct.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nstruct TokenAmount {\n    IERC20 token;\n    uint256 amount;\n}\nstruct ZapStruct {\n    address router;\n    bytes routerCall;\n}\nstruct ZapStructDeposit {\n    IERC20 tokenIn;\n    uint256 amountIn;\n    uint256 minAmountOut;\n    ZapStruct zap;\n}\n\nstruct ZapStructDepositNoMinAmount {\n    IERC20 tokenIn;\n    uint256 amountIn;\n    ZapStruct zap;\n}\n"},{"file_path":"src/USG/Utilities/abstract/ZappingUtil.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\nimport {IZappingProxy} from \"../../../interfaces/internals/USG/IZappingProxy.sol\";\nimport {ZapStructDeposit, IERC20} from \"../../../interfaces/internals/ICommonStruct.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nabstract contract ZappingUtil {\n    using SafeERC20 for IERC20;\n    address constant CHAIN_COIN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n    IZappingProxy public zappingProxy;\n\n    error InvalidZapValue();\n\n    /**\n     *  @dev   Verify zap input and transfer ERC20 (if not ETH ) to the ZappingProxy before calling the zapProxy on it.  \n     *         \n     *  @param zapCall   Contains tokenIn, amountIn, minAmountOut and the router with the associated raw call to execute on it to zap.\n     *  @param tokenOut  Token received on the receiver and zapped for tokenIn\n     *  @param receiver  Receiver of the tokenOut.\n\n     */\n    function _zapDeposit(ZapStructDeposit calldata zapCall, IERC20 tokenOut, address receiver) internal returns (uint256) {\n        require(0 != zapCall.amountIn, InvalidZapValue());\n        IZappingProxy _zappingProxy = zappingProxy;\n\n        if (address(zapCall.tokenIn) != CHAIN_COIN) {\n            require(0 == msg.value, InvalidZapValue());\n            zapCall.tokenIn.safeTransferFrom(msg.sender, address(_zappingProxy), zapCall.amountIn);\n        } else {\n            require(msg.value == zapCall.amountIn, InvalidZapValue());\n        }\n\n        return _zappingProxy.zapProxy{value: msg.value}(zapCall.tokenIn, tokenOut, zapCall.minAmountOut, receiver, zapCall.zap);\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"@openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\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":"@openzeppelin/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"src/interfaces/internals/USG/IRewardAccumulator.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {TokenAmount, IERC20} from \"../ICommonStruct.sol\";\n\nstruct Reward {\n    uint128 lastUpdateTime;\n    uint128 periodFinish;\n    uint256 rewardRate;\n    uint256 rewardPerTokenStored;\n}\nstruct RCParams {\n    uint16 harvestFeePercentage;\n    /// @dev Amount of distincts reward cut steps.\n    uint16 stepAmount;\n    /// @dev Percentage minimum of the reward cut.\n    uint32 startCutPercentage;\n    /// @dev Percentage maximum of the reward cut.\n    uint32 endCutPercentage;\n    /// @dev Price of USG on which the reward cut starts to increase.\n    uint80 startCutPrice;\n    /// @dev Price of USG on which the reward cut is at its maximum\n    uint80 endCutPrice;\n}\ninterface IRewardAccumulator {\n    function cutFeeForToken(IERC20 token) external view returns (uint256);\n\n    function getRewardData(address market, IERC20 token) external view returns (Reward memory);\n\n    function updateRewards(address account, uint256 collateralBalances, uint256 totalCollateral) external;\n\n    function processRewards(address market, address harvestFeeReceiver) external;\n\n    function getRewardTokens(address markets) external view returns (IERC20[] memory);\n\n    function lastRewardCuts(address market) external view returns (uint256);\n\n    function claimableRewards(address market, address _account) external view returns (TokenAmount[] memory userRewards);\n\n    function simulateRC(uint256 USGPrice, RCParams calldata rcParams) external pure returns (uint256);\n\n    function computeRCForMarket(address market) external returns (uint256);\n\n    function initializeMarket(address market, IERC20[] calldata rewardTokens, RCParams calldata _rcParams) external;\n\n    function getRCParams(address markets) external view returns (RCParams memory);\n}\n"},{"file_path":"src/interfaces/internals/USG/IDebtIR.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IIRCalculator} from \"./IIRCalculator.sol\";\n\ninterface IDebtIR {\n    function maxMarketDebt() external view returns (uint256);\n    function irCalculator() external view returns (IIRCalculator);\n    function minimumLoan() external view returns (uint256);\n    function userDebtShares(address user) external view returns (uint256);\n    function totalDebtShares() external view returns (uint256);\n    function badDebt() external view returns (uint256);\n}\n"},{"file_path":"src/interfaces/internals/USG/IZapper.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {IERC20} from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\n\ninterface IZapper {\n    function zapLeverage(IERC20 collatToken, uint256 minCollatReceived, bytes calldata routerCall) external returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/SafeCast.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.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 an uint of `bits` size.\n     */\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n    /**\n     * @dev An int value doesn't fit in an 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 An 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":"src/interfaces/internals/USG/IPriceOracle.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\ninterface IPriceOracle {\n    function latestAnswer(bool isNoFailMode) external view returns (uint256);\n\n    function latestAnswerUpdate(bool isNoFailMode) external returns (uint256);\n\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"src/libs/LightTransientSlot.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.\n\npragma solidity ^0.8.24;\n\n/**\n * @dev Library for reading and writing value-types to specific transient storage slots.\n *\n * Transient slots are often used to store temporary values that are removed after the current transaction.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n *  * Example reading and writing values using transient storage:\n * ```solidity\n * contract Lock {\n *     using TransientSlot for *;\n *\n *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n *     bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;\n *\n *     modifier locked() {\n *         require(!_LOCK_SLOT.asBoolean().tload());\n *\n *         _LOCK_SLOT.asBoolean().tstore(true);\n *         _;\n *         _LOCK_SLOT.asBoolean().tstore(false);\n *     }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary LightTransientSlot {\n    /**\n     * @dev UDVT that represent a slot holding a bool.\n     */\n    type BooleanSlot is bytes32;\n\n    /**\n     * @dev Cast an arbitrary slot to a BooleanSlot.\n     */\n    function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {\n        return BooleanSlot.wrap(slot);\n    }\n\n    /**\n     * @dev Load the value held at location `slot` in transient storage.\n     */\n    function tload(BooleanSlot slot) internal view returns (bool value) {\n        assembly (\"memory-safe\") {\n            value := tload(slot)\n        }\n    }\n\n    /**\n     * @dev Store `value` at location `slot` in transient storage.\n     */\n    function tstore(BooleanSlot slot, bool value) internal {\n        assembly (\"memory-safe\") {\n            tstore(slot, value)\n        }\n    }\n}\n"},{"file_path":"src/interfaces/internals/USG/IUSG.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {IERC20} from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\n\ninterface IUSG is IERC20 {\n    function mintDebt(address to, uint256 amount) external;\n\n    function burnDebt(address from, uint256 amount) external;\n\n    function mintIR(uint256 amount) external;\n\n    function initializeMarket(address market) external;\n}\n"},{"file_path":"src/USG/Market/abstract/MarketExternalActions.sol","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport {\n    MarketCore,\n    LiquidateIn,\n    LiquidateTransitionStruct,\n    SelfLiquidateIn,\n    SelfLiquidateTransitionStruct,\n    LiquidationPre,\n    ZapStructDeposit,\n    LeverageIn,\n    IZappingProxy\n} from \"./MarketCore.sol\";\n\nimport {IMarketExternalActions, IControlTower} from \"../../../interfaces/internals/USG/IMarketExternalActions.sol\";\n\nimport {IZapper} from \"../../../interfaces/internals/USG/IZapper.sol\";\nimport {IUSG} from \"../../../interfaces/internals/USG/IUSG.sol\";\n\nimport {TokenAmount, ZapStruct} from \"../../../interfaces/internals/ICommonStruct.sol\";\n\n/// @title MarketExternalActions\n/// @author Tangent Finance\n/// @notice Abstract base contract exposing external user functions\n/// @dev Inherits MarketCore\n/// Expose deposits, withdrawals, borrowing, repayment, liquidation, leverage and migrate functions\nabstract contract MarketExternalActions is MarketCore, IMarketExternalActions {\n    event Deposit(address indexed account, uint256 stakedAmount);\n    event ZapDeposit(address indexed account, uint256 stakedAmount, IERC20 tokenIn, uint256 amountIn);\n\n    event DepositAndBorrow(address indexed account, uint256 stakedAmount, uint256 borrowedAmount, uint256 debtShares);\n    event ZapDepositAndBorrow(address indexed account, uint256 stakedAmount, uint256 borrowedAmount, uint256 debtShares, IERC20 tokenIn, uint256 amountIn);\n\n    event Withdraw(address indexed account, uint256 amount);\n\n    event RepayAndWithdraw(address indexed account, uint256 withdrawnAmount, uint256 repaidAmount, uint256 debtShares);\n    event ZapRepayAndWithdraw(address indexed account, uint256 withdrawnAmount, uint256 repaidAmount, uint256 debtShares, IERC20 tokenIn, uint256 amountIn);\n\n    event Borrow(address indexed account, address receiver, uint256 borrowedAmount, uint256 debtShares);\n\n    event Repay(address indexed account, address repayer, uint256 repaidAmount, uint256 debtShares);\n    event ZapRepay(address indexed account, address repayer, uint256 repaidAmount, uint256 debtShares, IERC20 tokenIn, uint256 amountIn);\n\n    event Leverage(address indexed account, uint256 stakedAmount, uint256 collatBought, uint256 borrowedAmount, uint256 debtShares);\n    event ZapLeverage(\n        address indexed account,\n        uint256 stakedAmount,\n        uint256 collatZapDeposit,\n        uint256 collatLeverage,\n        uint256 borrowedAmount,\n        uint256 debtShares,\n        IERC20 tokenIn,\n        uint256 amountIn\n    );\n\n    event Liquidate(address indexed account, uint256 repaidAmount, uint256 debtShares, uint256 fee, uint256 collateralLiquidated, address liquidator);\n    event SelfLiquidate(address indexed account, uint256 repaidAmount, uint256 debtShares, uint256 collateralLiquidated, address liquidator);\n    event SeizeCollateral(address indexed account, uint256 newBadDebt, uint256 collateralSeized);\n\n    event MigrateFrom(address indexed account, uint256 collatRemoved, uint256 debtRemoved, uint256 debtRepaid, uint256 newUserDebtShares);\n    event MigrateTo(address indexed account, uint256 collatAdded, uint256 debtAdded, uint256 newUserDebtShares);\n\n    error NotRewardAccumulator();\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    DEPOSIT / BORROW \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Deposit some collateral on the market for an account.\n     * @dev    Collateral is always taken from the sender. Sender needs to allow the 'collatToken' to be spent by the market.\n     * @param  _for             Address for who the collateral is deposited.\n     * @param  depositedAmount  Amount of collateral to deposit\n     * @param isReceiptIn       Choose to deposit with the receipt token or the LP.\n     */\n    function deposit(address _for, uint256 depositedAmount, bool isReceiptIn) external nonReentrant updateRewards(_for) {\n        IERC20 _collatToken = collatToken;\n\n        _transferCollateralDeposit(depositedAmount, isReceiptIn);\n\n        _deposit(_for, depositedAmount, _collatToken);\n\n        emit Deposit(_for, depositedAmount);\n    }\n\n    /**\n     * @notice Zap from a token to the collateral and deposit the collateral into the market.\n     * @dev    Zaped asset is always taken from the sender. Sender needs to allow the 'asset' to be spent by the market.\n     * @param  _for           Address for who the collateral is deposited.\n     * @param  zapCall        Contains address and bytes of the contract selling the zapped asset to the collateral.\n     */\n    function zapDeposit(address _for, ZapStructDeposit calldata zapCall) external payable nonReentrant updateRewards(_for) {\n        IERC20 _collatToken = collatToken;\n        uint256 collatReceived = _zapDeposit(zapCall, _collatToken, address(this));\n\n        _deposit(_for, collatReceived, _collatToken);\n\n        emit ZapDeposit(_for, collatReceived, zapCall.tokenIn, zapCall.amountIn);\n    }\n\n    /**\n     * @notice Deposit the collateral into the market and borrow some USG.\n     * @dev    Collateral is always taken from the sender. Sender needs to allow the 'collatToken' to be spent by the market.\n     * @param  depositedAmount Amount of collateral to deposit\n     * @param  debtBorrow      Amount of USG to borrow\n     * @param  isReceiptIn     Choose to deposit with the receipt token or the LP.\n     */\n    function depositAndBorrow(uint256 depositedAmount, uint256 debtBorrow, bool isReceiptIn) external nonReentrant updateRewards(msg.sender) {\n        IERC20 _collatToken = collatToken;\n        _transferCollateralDeposit(depositedAmount, isReceiptIn);\n\n        uint256 debtShares = _depositAndBorrow(depositedAmount, debtBorrow, _collatToken, false);\n\n        emit DepositAndBorrow(msg.sender, depositedAmount, debtBorrow, debtShares);\n    }\n\n    /**\n     * @notice Zap from a token to the collateral, deposit the collateral into the market and borrow some USG.\n     * @dev    Zaped asset is always taken from the sender. Sender needs to allow the 'asset' to be spent by the market.\n     * @param  debtBorrow     The collateral is deposited to this address\n     * @param  zapCall        Stake or not the collateral. Cost less gas when is false but a deposit sociabilization fee is applied.\n     */\n    function zapDepositAndBorrow(uint256 debtBorrow, ZapStructDeposit calldata zapCall) external payable nonReentrant updateRewards(msg.sender) {\n        IERC20 _collatToken = collatToken;\n        uint256 collatReceived = _zapDeposit(zapCall, _collatToken, address(this));\n\n        uint256 debtShares = _depositAndBorrow(collatReceived, debtBorrow, _collatToken, false);\n\n        emit ZapDepositAndBorrow(msg.sender, collatReceived, debtBorrow, debtShares, zapCall.tokenIn, zapCall.amountIn);\n    }\n\n    /**\n     * @notice Borrow some USG from the market\n     * @dev    The debt is always incremented from the sender account.\n     * @param  receiver       Receiver of the USG that is borrowed by the sender\n     * @param  USGToBorrow  Amount of USG to mint to the receiver.\n     */\n    function borrow(address receiver, uint256 USGToBorrow) external nonReentrant {\n        (uint256 newUserDebtShares, uint256 newTotalDebtShares) = _borrow(receiver, USGToBorrow, collateralBalances[msg.sender], false);\n        _updateDebts(msg.sender, newUserDebtShares, newTotalDebtShares);\n\n        emit Borrow(msg.sender, receiver, USGToBorrow, newUserDebtShares);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    REPAY / WITHDRAW \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Withdraw the collateral and send it to the caller.\n     * @param  withdrawAmount Amount of collateral to withdraw\n     * @param  isReceiptOut   Choose to withdraw with the receipt token or the LP.\n     */\n    function withdraw(uint256 withdrawAmount, bool isReceiptOut) external nonReentrant updateRewards(msg.sender) {\n        _withdraw(withdrawAmount, isReceiptOut);\n\n        emit Withdraw(msg.sender, withdrawAmount);\n    }\n\n    /**\n     * @notice Withdraw the collateral, send it back to the caller and repay the whole or a part of the debt.\n     * @dev    When repaying fully a loan, inputing a 'usgToRepay' bigger than the user debt will repay exactly the full debt without excess.\n     * @param  withdrawAmount Amount of collateral to withdraw\n     * @param  usgToRepay     Amount of debt to repay. This amount will be burnt.\n     * @param  isReceiptOut   Choose to withdraw with the receipt token or the LP.\n     */\n    function repayAndWithdraw(uint256 withdrawAmount, uint256 usgToRepay, bool isReceiptOut) external nonReentrant updateRewards(msg.sender) {\n        (uint256 usgToBurn, uint256 newUserDebtShares) = _repayAndWithdraw(withdrawAmount, usgToRepay, isReceiptOut);\n\n        emit RepayAndWithdraw(msg.sender, withdrawAmount, usgToBurn, newUserDebtShares);\n    }\n\n    /**\n     * @notice Withdraw the collateral, send it back to the caller, zap an asset to USG and repay the whole or a part of the debt.\n     * @dev\n     * @param  withdrawAmount Amount of collateral to withdraw\n     * @param  isReceiptOut   Choose to withdraw with the receipt token or the LP.\n     * @param  zapCall        Zap details\n     */\n    function zapRepayAndWithdraw(uint256 withdrawAmount, bool isReceiptOut, ZapStructDeposit calldata zapCall) external payable nonReentrant updateRewards(msg.sender) {\n        uint256 USGToRepay = _zapDeposit(zapCall, usg, msg.sender);\n        (uint256 USGToBurn, uint256 newUserDebtShares) = _repayAndWithdraw(withdrawAmount, USGToRepay, isReceiptOut);\n\n        emit ZapRepayAndWithdraw(msg.sender, withdrawAmount, USGToBurn, newUserDebtShares, zapCall.tokenIn, zapCall.amountIn);\n    }\n\n    /**\n     * @notice Repay some USG debt on the market\n     * @param  account        Account of the position to repay debt on.\n     * @param  USGToRepay   Amount of USG to repay\n     */\n    function repay(address account, uint256 USGToRepay) external nonReentrant {\n        (uint256 USGToBurn, uint256 newUserDebtShares, uint256 newTotalDebtShares, ) = _repay(account, USGToRepay);\n\n        _updateDebts(account, newUserDebtShares, newTotalDebtShares);\n\n        emit Repay(account, msg.sender, USGToBurn, newUserDebtShares);\n    }\n\n    /**\n     * @notice Repay some usg debt on the market\n     * @param  account        Account of the position to repay debt on.\n     * @param  zapCall   Only used on zapAndRepay. It's the address calling the zapper and that will receive the USG during the zapping.\n     */\n    function zapRepay(address account, ZapStructDeposit calldata zapCall) external payable nonReentrant {\n        uint256 USGToRepay = _zapDeposit(zapCall, usg, msg.sender);\n\n        (uint256 USGToBurn, uint256 newUserDebtShares, uint256 newTotalDebtShares, ) = _repay(account, USGToRepay);\n\n        _updateDebts(account, newUserDebtShares, newTotalDebtShares);\n\n        emit ZapRepay(account, msg.sender, USGToBurn, newUserDebtShares, zapCall.tokenIn, zapCall.amountIn);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                       LIQUIDATE \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Liquidate a position that have an health ratio < 1.\n     * @dev    Two liquidation modes are possibles : \n     *           - Buy USG with a flashloan, repay the debt, get the collateral and do whatever you want with it.\n                 - Selling the collateral for USG directly through ZappingProxy by providing a route then repay the debt and keep the difference in USG\n     * @param  liquidateIn  Struct with parameters proper to the liquidation.\n     *                         - account : Account position to liquidate\n     *                         - PostLiquidateStruct : \n     *                             - collatAmountToLiquidate : Amount of collateral to liquidate from the position.   \n     *                             - minUsgOut : Min USG to be returned after the swap through ZapProxy\n     *                             - maxUsgToBurn : Maximum amount of USG to be burnt\n     *                             - minCollatAmountToLiquidate : Minimum amount of collateral to be liquidate\n     *                             - isReceiptOut : When true, receipt token is sent back to the liquidator, when false it's the underlying\n     *                         - minCollatValueToLiquidat : Minimum value in dollar to liquidate\n     * @param  liquidationCall  Contract and data allowing to sell the collateral for USG.\n     */\n    function liquidate(LiquidateIn calldata liquidateIn, ZapStruct calldata liquidationCall) external nonReentrant updateRewards(liquidateIn.account) {\n        LiquidationPre memory pre = _preLiquidate(liquidateIn.account);\n        uint256 collatPrice = _collateralPriceUpdate(true);\n\n        uint256 healthRatio = MAX_UINT; // Fully healthy if no debt\n        if (pre.userDebt_ != 0) {\n            healthRatio = (pre.collatBalance * 10 ** (18 - collatDecimals) * collatPrice * liquidationThreshold) / (pre.userDebt_ * DENOMINATOR);\n        }\n\n        // Can liquidate only if the health ratio is below 1\n        require(healthRatio < 1 ether, NotLiquidablePosition());\n\n        (uint256 collatLiquidated, uint256 repaidDebt, uint256 fee, uint256 newUserDebtShares) = _liquidate(\n            LiquidateTransitionStruct({\n                liquidateIn: liquidateIn,\n                collatPrice: collatPrice,\n                newDebtIndex: pre.newDebtIndex,\n                _collateralBalance: pre.collatBalance,\n                _totalCollateral: totalCollateral,\n                _userDebtShares: pre._userDebtShares,\n                _totalDebtShares: totalDebtShares,\n                userDebt: pre.userDebt_\n            }),\n            liquidationCall\n        );\n\n        emit Liquidate(liquidateIn.account, repaidDebt, newUserDebtShares, fee, collatLiquidated, liquidationCall.router);\n    }\n\n    /**\n     * @notice Liquidate a part or the full collateral of the position of the caller.\n     * @param  selfLiquidateIn   Parameters proper to the self liquidation\n     *                             - collatAmountToLiquidate : Amount of collateral to liquidate from the position.\n     *                             - usgToRepay : Amount of usg to repay, in the case this amount is bigger than the position debt, it repays the whole position.\n     *                             - maxUsgToBurn : Maximum amount of USG to be burnt in total by the user.\n     *                             - minUsgOut : Min USG to be returned after the swap through ZapProxy\n     *                             - isReceiptOut : When true, receipt token is sent back to the position owner, when false it's the underlying\n     * @param  liquidationCall   Contract and data allowing to sell the collateral for USG.\n     */\n    function selfLiquidate(SelfLiquidateIn calldata selfLiquidateIn, ZapStruct calldata liquidationCall) external nonReentrant updateRewards(msg.sender) {\n        LiquidationPre memory pre = _preLiquidate(msg.sender);\n\n        (uint256 repaidDebt, uint256 newUserDebtShares) = _selfLiquidate(\n            SelfLiquidateTransitionStruct({\n                selfLiquidateIn: selfLiquidateIn,\n                newDebtIndex: pre.newDebtIndex,\n                _collateralBalance: pre.collatBalance,\n                _totalCollateral: totalCollateral,\n                _userDebtShares: pre._userDebtShares,\n                _totalDebtShares: totalDebtShares,\n                userDebt: pre.userDebt_\n            }),\n            liquidationCall\n        );\n\n        emit SelfLiquidate(msg.sender, repaidDebt, newUserDebtShares, selfLiquidateIn.collatAmountToLiquidate, liquidationCall.router);\n    }\n\n    /**\n     * @notice Seize the collateral of a position where collateral value is less than the user debt.\n     * @dev    Collateral is sent to dao for management and bad debt of the market is incremented with the user debt.\n     * @param  account  Account of the position to seize collateral\n     */\n    function seizeCollateral(address account) external nonReentrant updateRewards(account) {\n        // Checkpoint IR\n        LiquidationPre memory pre = _preLiquidate(account);\n\n        // Can liquidate bad debt only if the value of the collateral is below the debt\n        require(_positionValueUpdate(pre.collatBalance, true) < pre.userDebt_, PositionWithoutBadDebt());\n\n        _seizeCollateral(account, pre.collatBalance, totalCollateral, pre._userDebtShares, totalDebtShares, pre.userDebt_);\n\n        emit SeizeCollateral(account, pre.userDebt_, pre.collatBalance);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                       LEVERAGE \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Leverage the collateral amount of a position. Mint USG that are fully sold for collateral on the fly.\n     * @dev    The route and liquidator contract must be specified and setup properlly.\n     * @param  leverageIn    Struct containing :\n     *                           - collatToDeposit : Amount of collateral to deposit, can be 0\n     *                           - usgToFlashMint : Amount of USG to mint that is sold for collateral, will be incremented to userDebt.\n     *                           - minCollatAmountOut : Slippage, minimum amount of collat to receive from the sell of USG.\n     *                           - isReceiptIn :  When true, receipt token is taken from the msg.sender, when false it's the underlying.\n     * @param  leverageCall  Struct containing router and data to be able to sell the USG for collateral through the ZappingProxy\n     */\n    function leverage(LeverageIn calldata leverageIn, ZapStruct calldata leverageCall) external nonReentrant updateRewards(msg.sender) {\n        IERC20 _collatToken = collatToken;\n        if (leverageIn.collatToDeposit != 0) {\n            // Transfer the collateral coming from the user on the market\n            _transferCollateralDeposit(leverageIn.collatToDeposit, leverageIn.isReceiptIn);\n        }\n\n        (uint256 collatBought, uint256 stakedAmount, uint256 newUserDebtShares) = _leverage(_collatToken, leverageIn, leverageCall);\n\n        emit Leverage(msg.sender, stakedAmount, collatBought, leverageIn.usgToFlashMint, newUserDebtShares);\n    }\n\n    /**\n     * @notice Leverage the collateral amount of a position. Mint USG that are fully sold for collateral on the fly.\n     * @dev    The route and liquidator contract must be specified and setup properlly.\n     * @param  usgToFlashMint   Amount of USG to mint that is sold for collateral, will be incremented to userDebt.\n     * @param  minCollatAmountOut Slippage, minimum amount of collatAmount to receive from the selling of USG.\n     * @param  leverageCall       Struct containing router and data to be able to sell the USG for collateral through the ZappingProxy\n     * @param  zapDepositCall     Contract and data allowing to sell the zapToken for collateral.\n     */\n    function zapLeverage(\n        uint256 usgToFlashMint,\n        uint256 minCollatAmountOut,\n        ZapStruct calldata leverageCall,\n        ZapStructDeposit calldata zapDepositCall\n    ) external payable nonReentrant updateRewards(msg.sender) {\n        IERC20 _collatToken = collatToken;\n        uint256 collatToDeposit = _zapDeposit(zapDepositCall, _collatToken, address(this));\n\n        (uint256 collatBought, uint256 stakedAmount, uint256 newUserDebtShares) = _leverage(\n            _collatToken,\n            LeverageIn({collatToDeposit: collatToDeposit, usgToFlashMint: usgToFlashMint, minCollatAmountOut: minCollatAmountOut, isReceiptIn: false}),\n            leverageCall\n        );\n\n        emit ZapLeverage(msg.sender, stakedAmount, collatToDeposit, collatBought, usgToFlashMint, newUserDebtShares, zapDepositCall.tokenIn, zapDepositCall.amountIn);\n    }\n\n    /**\n     * @notice Claim and process the governance rewards\n     * @dev Claim rewards from the corresponding ConvexReward SC and streams them for the stakers.\n     *      Anyone can trigger this function and will be incentivized with a processor fee.\n     */\n    function claimUnderlyingRewards(IERC20[] memory _rewardTokens) external nonReentrant updateRewards(address(0)) returns (TokenAmount[] memory) {\n        require(msg.sender == address(rewardAccumulator), NotRewardAccumulator());\n        _claimRewards();\n        return _claimUnderlyingRewards(_rewardTokens);\n    }\n\n    /**\n     * @dev Callable only by a verified Migrator.\n     *      Remove and if wanted, repay a part of the debt and withdraw a part of the collateral.\n     * @param  account            Account that will be affected by the modifications\n     * @param  collatToRemove     Amount of collateral to remove from the contract\n     * @param  debtToRemove       Amount of debt to remove from the contract\n     * @param  debtToRepay        Amount of USG to burn that will be removed from the debt transfered to the `TO` market\n     * @param  receiver           Receiver of the colllateral\n     */\n    function migrateFrom(\n        address account,\n        uint256 collatToRemove,\n        uint256 debtToRemove,\n        uint256 debtToRepay,\n        address receiver\n    ) external nonReentrant updateRewards(account) returns (uint256) {\n        (uint256 debtRepaid, uint256 newUserDebtShares) = _migrateFrom(account, collatToRemove, debtToRemove, debtToRepay, receiver);\n        emit MigrateFrom(account, collatToRemove, debtToRemove, debtToRepay, newUserDebtShares);\n        return debtRepaid;\n    }\n\n    /**\n     * @dev Callable only by a verified Migrator.\n     *      Received the debt from the `FROM` market and the zapped collateral.\n     * @param  account        Account that will be affected by the modifications\n     * @param  collatToAdd    Amount of collateral to add to the contract\n     * @param  debtToAdd      Amount of debt to add to the contract\n     */\n    function migrateTo(address account, uint256 collatToAdd, uint256 debtToAdd) external nonReentrant updateRewards(account) {\n        uint256 newUserDebtShares = _migrateTo(account, collatToAdd, debtToAdd);\n        emit MigrateTo(account, collatToAdd, debtToAdd, newUserDebtShares);\n    }\n\n    /**\n     * @dev Callable only by a verified Migrator.\n     *      Block all the actions of the contract to prevent reentrancy exploits\n     */\n    function reeantrancyOn() external returns (IERC20) {\n        _nonReentrantBefore();\n        _verifySenderMigrator();\n        return collatToken;\n    }\n\n    /**\n     * @dev Callable only by a verified Migrator.\n     *      Unlock all the actions of the contract.\n     */\n    function reeantrancyOff() external {\n        _verifySenderMigrator();\n        _nonReentrantAfter();\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.2.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        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\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        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\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        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\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 rely 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 rely 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     * Opposedly, 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 high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"src/interfaces/externals/StakeDao/IAccountant.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.27;\n\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IAccountant {\n    function claim(address[] calldata _gauges, bytes[] calldata harvestData) external;\n}\n"},{"file_path":"src/interfaces/internals/USG/IZappingProxy.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {IERC20} from \"@openzeppelin/contracts/interfaces/IERC20.sol\";\n\nimport {ZapStruct} from \"../ICommonStruct.sol\";\n\ninterface IZappingProxy {\n    function zapProxy(IERC20 tokenIn, IERC20 tokenOut, uint256 minAmountOut, address receiver, ZapStruct calldata routerCall) external payable returns (uint256);\n}\n"},{"file_path":"src/interfaces/externals/StakeDao/IStakeDaoVaultV2.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.27;\n\nimport {IERC20Metadata, IERC20} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IStakeDaoVaultV2 is IERC20Metadata {\n    function ACCOUNTANT() external view returns (address);\n    function DEFAULT_REWARDS_DURATION() external view returns (uint32);\n    function POLICY() external view returns (uint8);\n    function PROTOCOL_CONTROLLER() external view returns (address);\n    function PROTOCOL_ID() external view returns (bytes4);\n    function accountData(address account, address rewardToken) external view returns (uint128 rewardPerTokenPaid, uint128 claimable);\n    function addRewardToken(address rewardToken, address distributor) external;\n    function allocator() external view returns (address _allocator);\n    function allowance(address owner, address spender) external view returns (uint256);\n    function approve(address spender, uint256 value) external returns (bool);\n    function asset() external view returns (address);\n    function balanceOf(address account) external view returns (uint256);\n    function checkpoint(address account) external;\n    function claim(address[] calldata tokens, address receiver) external returns (uint256[] memory amounts);\n    function claim(address account, address[] calldata tokens, address receiver) external returns (uint256[] memory amounts);\n    function convertToAssets(uint256 shares) external pure returns (uint256);\n    function convertToShares(uint256 assets) external pure returns (uint256);\n    function decimals() external view returns (uint8);\n    function deposit(uint256 assets, address receiver, address referrer) external returns (uint256);\n    function deposit(address account, address receiver, uint256 assets, address referrer) external returns (uint256);\n    function deposit(uint256 assets, address receiver) external returns (uint256);\n    function depositRewards(address rewardToken, uint128 amount) external;\n    function earned(address account, address token) external view returns (uint128);\n    function gauge() external view returns (address _gauge);\n    function getClaimable(address token, address account) external view returns (uint128);\n    function getLastUpdateTime(address token) external view returns (uint32);\n    function getPeriodFinish(address token) external view returns (uint32);\n    function getRewardPerTokenPaid(address token, address account) external view returns (uint128);\n    function getRewardPerTokenStored(address token) external view returns (uint128);\n    function getRewardRate(address token) external view returns (uint128);\n    function getRewardTokens() external view returns (address[] memory);\n    function getRewardsDistributor(address token) external view returns (address);\n    function isRewardToken(address rewardToken) external view returns (bool);\n    function lastTimeRewardApplicable(address token) external view returns (uint256);\n    function maxDeposit(address) external pure returns (uint256);\n    function maxMint(address _account) external pure returns (uint256);\n    function maxRedeem(address owner) external view returns (uint256);\n    function maxWithdraw(address owner) external view returns (uint256);\n    function mint(uint256 shares, address receiver) external returns (uint256);\n    function mint(uint256 shares, address receiver, address referrer) external returns (uint256);\n    function name() external view returns (string memory);\n    function previewDeposit(uint256 shares) external pure returns (uint256);\n    function previewMint(uint256 assets) external pure returns (uint256);\n    function previewRedeem(uint256 shares) external pure returns (uint256);\n    function previewWithdraw(uint256 assets) external pure returns (uint256);\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256);\n    function resumeVault() external;\n    function rewardData(\n        address rewardToken\n    ) external view returns (address rewardsDistributor, uint32 lastUpdateTime, uint32 periodFinish, uint128 rewardRate, uint128 rewardPerTokenStored);\n    function rewardPerToken(address token) external view returns (uint128);\n    function strategy() external view returns (address _strategy);\n    function symbol() external view returns (string memory);\n    function totalAssets() external view returns (uint256);\n    function totalSupply() external view returns (uint256);\n    function transfer(address to, uint256 value) external returns (bool);\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256);\n}\n"},{"file_path":"@openzeppelin/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\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":"src/interfaces/internals/USG/IMarketCore.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {ZapStruct} from \"../ICommonStruct.sol\";\nimport {IIRCalculator} from \"./IIRCalculator.sol\";\nimport {IUSG} from \"./IUSG.sol\";\nimport {ICollateral, IERC20Metadata} from \"./ICollateral.sol\";\nimport {IControlTower} from \"./IControlTower.sol\";\nimport {IPriceOracle} from \"./IPriceOracle.sol\";\nimport {IZappingProxy} from \"./IZappingProxy.sol\";\nimport {IRewardAccumulator} from \"./IRewardAccumulator.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nstruct LiquidationPre {\n    uint256 newDebtIndex;\n    uint256 collatBalance;\n    uint256 _userDebtShares;\n    uint256 userDebt_;\n}\n\nstruct LiquidateIn {\n    address account;\n    PostLiquidate postLiquidate;\n    uint256 minCollatValueToLiquidate;\n}\n\nstruct LiquidateTransitionStruct {\n    LiquidateIn liquidateIn;\n    uint256 collatPrice;\n    uint256 newDebtIndex;\n    uint256 _collateralBalance;\n    uint256 _totalCollateral;\n    uint256 _userDebtShares;\n    uint256 _totalDebtShares;\n    uint256 userDebt;\n}\n\nstruct PostLiquidate {\n    uint256 collatAmountToLiquidate;\n    uint256 minUsgOut;\n    uint256 maxUsgToBurn;\n    uint256 minCollatAmountToLiquidate;\n    bool isReceiptOut;\n}\n\nstruct SelfLiquidateIn {\n    uint256 collatAmountToLiquidate;\n    uint256 usgToRepay;\n    uint256 maxUsgToBurn;\n    uint256 minUsgOut;\n    bool isReceiptOut;\n}\n\nstruct SelfLiquidateTransitionStruct {\n    SelfLiquidateIn selfLiquidateIn;\n    uint256 newDebtIndex;\n    uint256 _collateralBalance;\n    uint256 _totalCollateral;\n    uint256 _userDebtShares;\n    uint256 _totalDebtShares;\n    uint256 userDebt;\n}\n\nstruct LeverageIn {\n    uint256 collatToDeposit;\n    uint256 usgToFlashMint;\n    uint256 minCollatAmountOut;\n    bool isReceiptIn;\n}\n\nstruct GlobalMarketInitParams {\n    address _owner;\n    IUSG _USG;\n    IControlTower _controlTower;\n    IIRCalculator _irCalculator;\n    IRewardAccumulator _rewardAccumulator;\n    IZappingProxy _zappingProxy;\n}\n\nstruct MarketInit {\n    IERC20Metadata collatToken;\n    IPriceOracle collatOracle;\n    uint256 maxLTV;\n    uint256 liquidationThreshold;\n    uint256 liquidationFee;\n    uint256 maxMarketDebt;\n    uint256 minimumLoan;\n    IERC20[] rewardTokens;\n    string name;\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\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":"src/interfaces/internals/USG/IMarketExternalActions.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {IERC20, TokenAmount, ZapStruct} from \"../ICommonStruct.sol\";\n\nimport {IERC20, IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport {LiquidateIn, LeverageIn} from \"./IMarketCore.sol\";\nimport {IMigratoor, MigrateStruct} from \"./IMigratoor.sol\";\nimport {IControlTower} from \"./IControlTower.sol\";\ninterface IMarketExternalActions {\n    function deposit(address _for, uint256 lpDeposited, bool isReceiptIn) external;\n\n    function borrow(address receiver, uint256 USGToBorrow) external;\n\n    function depositAndBorrow(uint256 lpDeposited, uint256 debtBorrow, bool isReceiptIn) external;\n\n    function repay(address account, uint256 USGToRepay) external;\n\n    function liquidate(LiquidateIn calldata liquidateIn, ZapStruct calldata liquidationCall) external;\n\n    function leverage(LeverageIn calldata leverageIn, ZapStruct calldata zap) external;\n\n    function claimUnderlyingRewards(IERC20[] memory _rewardTokens) external returns (TokenAmount[] memory);\n\n    function migrateFrom(address account, uint256 collateralToRemove, uint256 debtToRemove, uint256 debtToRepay, address collatReceiver) external returns (uint256);\n\n    function migrateTo(address account, uint256 collatToAdd, uint256 debtToAdd) external;\n\n    function reeantrancyOn() external returns (IERC20);\n\n    function reeantrancyOff() external;\n}\n"},{"file_path":"src/interfaces/internals/USG/ICollateral.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IERC20, IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport {IDebtIR} from \"./IDebtIR.sol\";\nimport {IRewardAccumulator} from \"./IRewardAccumulator.sol\";\nimport {IPriceOracle} from \"./IPriceOracle.sol\";\n\ninterface ICollateral {\n    function collatOracle() external view returns (IPriceOracle);\n\n    function collatToken() external view returns (IERC20Metadata);\n\n    function collatDecimals() external view returns (uint256);\n\n    function collateralBalances(address account) external view returns (uint256);\n\n    function totalCollateral() external view returns (uint256);\n\n    function maxLTV() external view returns (uint256);\n\n    function liquidationThreshold() external view returns (uint256);\n\n    function rewardAccumulator() external view returns (IRewardAccumulator);\n\n    function getBalanceAndTotalCollateral(address account) external view returns (uint256, uint256);\n}\n"},{"file_path":"src/interfaces/internals/USG/IMigratoor.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {IMarketExternalActions} from \"./IMarketExternalActions.sol\";\n\nimport {ZapStruct} from \"../ICommonStruct.sol\";\nstruct MigrateStruct {\n    address marketFrom;\n    address marketTo;\n    uint256 collatToWithdraw;\n    uint256 debtToRemove;\n    uint256 debtToRepay;\n}\n\nstruct ZapMigrateStruct {\n    ZapStruct zap;\n    uint256 minCollatToOut;\n}\n\ninterface IMigratoor {}\n"},{"file_path":"src/interfaces/internals/USG/IIRCalculator.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nstruct IRParams {\n    /// @dev Flag to determine if a Market is HEC or LEC\n    bool isHEC;\n    /// @dev Minimum IR reached at pMax.\n    ///      1_000 <=> 1% / 100_000 <=> 100%.\n    uint24 rMin;\n    /// @dev Maximum IR reached at pMin.\n    ///      1_000 <=> 1% / 100_000 <=> 100%.\n    uint32 rMax;\n    /// @dev Minimum price of USG where rMax is reached.\n    ///      980_000 <=> 0.98$ / 1_000_000 <=> 1$\n    uint32 pMin;\n    /// @dev Inflexion price of USG where IR starts to increases more significantly.\n    ///      980_000 <=> 0.98$ / 1_000_000 <=> 1$\n    uint32 pInf;\n    /// @dev Maximum price of USG where IR increases more significantly.\n    ///      980_000 <=> 0.98$ / 1_000_000 <=> 1$\n    uint32 pMax;\n    /// @dev Convexity of the curve before pInf\n    ///      2_000 <=> 2 / 4_500 <=> 4.5\n    uint32 a1;\n    /// @dev Convexity of the curve after pInf\n    ///      2_000 <=> 2 / 4_500 <=> 4.5\n    uint32 a2;\n    /// @dev Velocity of the transition between a1 and a2\n    ///      It's an integer. 250 <=> 250\n    uint32 k;\n}\n\nstruct IRCheckpoint {\n    uint216 ir;\n    uint40 timestamp;\n}\ninterface IIRCalculator {\n    function initializeMarket(address market, IRParams calldata _irParam) external;\n\n    function simulateIR(uint256 USGPrice, IRParams memory irParam) external view returns (uint256);\n\n    function computeIRForMarket(address market) external returns (uint256);\n\n    function checkpointIR(address market) external returns (uint256);\n\n    function newDebtIndex(address market) external view returns (uint256);\n\n    function irCheckpoints(address market) external view returns (uint216, uint40);\n\n    function debtIndexes(address market) external view returns (uint256);\n\n    function indexDelta(address market) external view returns (uint256);\n\n    function mintableInterests() external view returns (uint256);\n\n    function getIRParams(address market) external view returns (IRParams memory);\n\n    function getIRCheckpoint(address market) external view returns (IRCheckpoint memory);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BorrowPaused","type":"error"},{"inputs":[],"name":"CallerNotPauser","type":"error"},{"inputs":[{"internalType":"uint256","name":"collatValue","type":"uint256"}],"name":"CollatValueToLiquidateTooLow","type":"error"},{"inputs":[],"name":"DebtToRepayTooBig","type":"error"},{"inputs":[],"name":"DepositPaused","type":"error"},{"inputs":[],"name":"InvalidZapValue","type":"error"},{"inputs":[],"name":"LeveragePaused","type":"error"},{"inputs":[],"name":"LiquidationFeeTooHigh","type":"error"},{"inputs":[],"name":"LiquidationThresholdTooHigh","type":"error"},{"inputs":[],"name":"LiquidationThresholdTooLow","type":"error"},{"inputs":[],"name":"MaxLTVBiggerThanLiquidationThreshold","type":"error"},{"inputs":[],"name":"MaxLTVTooHigh","type":"error"},{"inputs":[],"name":"MaxLTVTooLow","type":"error"},{"inputs":[],"name":"MaxUSGToBurn","type":"error"},{"inputs":[{"internalType":"uint256","name":"collatAmount","type":"uint256"}],"name":"MinCollatToLiquidate","type":"error"},{"inputs":[],"name":"NoZapLiquidateWithReceipt","type":"error"},{"inputs":[],"name":"NotAMigratoor","type":"error"},{"inputs":[{"internalType":"uint256","name":"collatBalance","type":"uint256"}],"name":"NotEnoughCollateralToLiquidate","type":"error"},{"inputs":[],"name":"NotLiquidablePosition","type":"error"},{"inputs":[],"name":"NotRewardAccumulator","type":"error"},{"inputs":[],"name":"OverMaxLTV","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PositionWithoutBadDebt","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"RepayMoreThanBadDebt","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TotalDebtTooHigh","type":"error"},{"inputs":[],"name":"UserDebtTooLow","type":"error"},{"inputs":[],"name":"UserDebtZero","type":"error"},{"inputs":[],"name":"WrongVaultToken","type":"error"},{"inputs":[],"name":"ZeroCollatAmount","type":"error"},{"inputs":[],"name":"ZeroDebtAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"}],"name":"DepositAndBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collatBought","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"}],"name":"Leverage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralLiquidated","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"collatRemoved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtRemoved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtRepaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUserDebtShares","type":"uint256"}],"name":"MigrateFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"collatAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUserDebtShares","type":"uint256"}],"name":"MigrateTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum PauseSettings.PauseEnum","name":"pauseType","type":"uint8"},{"indexed":false,"internalType":"uint64","name":"isPaused","type":"uint64"}],"name":"PauseTrigger","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"repayer","type":"address"},{"indexed":false,"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"}],"name":"RepayAndWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"badDebtRepaid","type":"uint256"}],"name":"RepayBadDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBadDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralSeized","type":"uint256"}],"name":"SeizeCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralLiquidated","type":"uint256"},{"indexed":false,"internalType":"address","name":"liquidator","type":"address"}],"name":"SelfLiquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLiquidationFee","type":"uint256"}],"name":"SetLiquidationFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLiquidationThreshold","type":"uint256"}],"name":"SetLiquidationThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxLTV","type":"uint256"}],"name":"SetMaxLTV","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxMarketDebt","type":"uint256"}],"name":"SetMaxMarketDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMinimumLoan","type":"uint256"}],"name":"SetMinimumLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IPriceOracle","name":"newOracle","type":"address"}],"name":"SetOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"ZapDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"ZapDepositAndBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collatZapDeposit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collatLeverage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"ZapLeverage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"repayer","type":"address"},{"indexed":false,"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"ZapRepay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawnAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repaidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShares","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"ZapRepayAndWithdraw","type":"event"},{"inputs":[],"name":"badDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"USGToBorrow","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"rewards","type":"address[]"}],"name":"claimExtraRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"_rewardTokens","type":"address[]"}],"name":"claimUnderlyingRewards","outputs":[{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collatDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collatOracle","outputs":[{"internalType":"contract IPriceOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collatToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collateralBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"internalType":"uint256","name":"depositedAmount","type":"uint256"},{"internalType":"bool","name":"isReceiptIn","type":"bool"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositedAmount","type":"uint256"},{"internalType":"uint256","name":"debtBorrow","type":"uint256"},{"internalType":"bool","name":"isReceiptIn","type":"bool"}],"name":"depositAndBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getBalanceAndTotalCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPausedSettings","outputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"contract IUSG","name":"_USG","type":"address"},{"internalType":"contract IControlTower","name":"_controlTower","type":"address"},{"internalType":"contract IIRCalculator","name":"_irCalculator","type":"address"},{"internalType":"contract IRewardAccumulator","name":"_rewardAccumulator","type":"address"},{"internalType":"contract IZappingProxy","name":"_zappingProxy","type":"address"}],"internalType":"struct GlobalMarketInitParams","name":"_marketConstants","type":"tuple"},{"components":[{"internalType":"contract IERC20Metadata","name":"collatToken","type":"address"},{"internalType":"contract IPriceOracle","name":"collatOracle","type":"address"},{"internalType":"uint256","name":"maxLTV","type":"uint256"},{"internalType":"uint256","name":"liquidationThreshold","type":"uint256"},{"internalType":"uint256","name":"liquidationFee","type":"uint256"},{"internalType":"uint256","name":"maxMarketDebt","type":"uint256"},{"internalType":"uint256","name":"minimumLoan","type":"uint256"},{"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct MarketInit","name":"_marketInit","type":"tuple"},{"internalType":"address","name":"_receipt","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"irCalculator","outputs":[{"internalType":"contract IIRCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"collatToDeposit","type":"uint256"},{"internalType":"uint256","name":"usgToFlashMint","type":"uint256"},{"internalType":"uint256","name":"minCollatAmountOut","type":"uint256"},{"internalType":"bool","name":"isReceiptIn","type":"bool"}],"internalType":"struct LeverageIn","name":"leverageIn","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"leverageCall","type":"tuple"}],"name":"leverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"components":[{"internalType":"uint256","name":"collatAmountToLiquidate","type":"uint256"},{"internalType":"uint256","name":"minUsgOut","type":"uint256"},{"internalType":"uint256","name":"maxUsgToBurn","type":"uint256"},{"internalType":"uint256","name":"minCollatAmountToLiquidate","type":"uint256"},{"internalType":"bool","name":"isReceiptOut","type":"bool"}],"internalType":"struct PostLiquidate","name":"postLiquidate","type":"tuple"},{"internalType":"uint256","name":"minCollatValueToLiquidate","type":"uint256"}],"internalType":"struct LiquidateIn","name":"liquidateIn","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"liquidationCall","type":"tuple"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLTV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMarketDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"collatToRemove","type":"uint256"},{"internalType":"uint256","name":"debtToRemove","type":"uint256"},{"internalType":"uint256","name":"debtToRepay","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"migrateFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"collatToAdd","type":"uint256"},{"internalType":"uint256","name":"debtToAdd","type":"uint256"}],"name":"migrateTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minimumLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiptToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reeantrancyOff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reeantrancyOn","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"USGToRepay","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"internalType":"uint256","name":"usgToRepay","type":"uint256"},{"internalType":"bool","name":"isReceiptOut","type":"bool"}],"name":"repayAndWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repayBadDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardAccumulator","outputs":[{"internalType":"contract IRewardAccumulator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"seizeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"collatAmountToLiquidate","type":"uint256"},{"internalType":"uint256","name":"usgToRepay","type":"uint256"},{"internalType":"uint256","name":"maxUsgToBurn","type":"uint256"},{"internalType":"uint256","name":"minUsgOut","type":"uint256"},{"internalType":"bool","name":"isReceiptOut","type":"bool"}],"internalType":"struct SelfLiquidateIn","name":"selfLiquidateIn","type":"tuple"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"liquidationCall","type":"tuple"}],"name":"selfLiquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IPriceOracle","name":"_collatOracle","type":"address"}],"name":"setCollatOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liquidationFee","type":"uint256"}],"name":"setLiquidationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liquidationThreshold","type":"uint256"}],"name":"setLiquidationThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLTV","type":"uint256"}],"name":"setMaxLTV","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMarketDebt","type":"uint256"}],"name":"setMaxMarketDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumLoan","type":"uint256"}],"name":"setMinimumLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum PauseSettings.PauseEnum","name":"pauseType","type":"uint8"},{"internalType":"uint64","name":"isPaused","type":"uint64"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebtShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userDebtShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"internalType":"bool","name":"isReceiptOut","type":"bool"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"zap","type":"tuple"}],"internalType":"struct ZapStructDeposit","name":"zapCall","type":"tuple"}],"name":"zapDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"debtBorrow","type":"uint256"},{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"zap","type":"tuple"}],"internalType":"struct ZapStructDeposit","name":"zapCall","type":"tuple"}],"name":"zapDepositAndBorrow","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usgToFlashMint","type":"uint256"},{"internalType":"uint256","name":"minCollatAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"leverageCall","type":"tuple"},{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"zap","type":"tuple"}],"internalType":"struct ZapStructDeposit","name":"zapDepositCall","type":"tuple"}],"name":"zapLeverage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"zap","type":"tuple"}],"internalType":"struct ZapStructDeposit","name":"zapCall","type":"tuple"}],"name":"zapRepay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"internalType":"bool","name":"isReceiptOut","type":"bool"},{"components":[{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"bytes","name":"routerCall","type":"bytes"}],"internalType":"struct ZapStruct","name":"zap","type":"tuple"}],"internalType":"struct ZapStructDeposit","name":"zapCall","type":"tuple"}],"name":"zapRepayAndWithdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"zappingProxy","outputs":[{"internalType":"contract IZappingProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}