{"file_path":"src/USG/Utilities/IRCalculator.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.22;\n\nimport {LightReentrancyGuardTransient} from \"../Utilities/abstract/LightReentrancyGuardTransient.sol\";\n\nimport {LightOwnable} from \"../Utilities/abstract/LightOwnable.sol\";\n\nimport {IRParams, IIRCalculator, IRCheckpoint} from \"../../interfaces/internals/USG/IIRCalculator.sol\";\nimport {IControlTower} from \"../../interfaces/internals/USG/IControlTower.sol\";\nimport {IAggregatorStablePriceV3} from \"../../interfaces/externals/LlamaLend/IAggregatorStablePriceV3.sol\";\nimport {IDebtIR} from \"../../interfaces/internals/USG/IDebtIR.sol\";\nimport {IUSG} from \"../../interfaces/internals/USG/IUSG.sol\";\n\nimport {ABDKMath64x64} from \"../../libs/ABDKMath64x64.sol\";\n\n/// @title IRCalculator\n/// @author Tangent Finance\n/// @notice Calculates and stores interest rates for all markets.\ncontract IRCalculator is IIRCalculator, LightOwnable, LightReentrancyGuardTransient {\n    uint256 public constant DENOMINATOR = 100_000;\n\n    uint256 constant RAY = 1e27;\n    uint256 constant ONE_ETHER = 1e18;\n\n    uint256 constant E12 = 1e12;\n    uint256 constant E13 = 1e13;\n\n    int256 constant MAX_EXP = 43;\n\n    IControlTower public controlTower;\n\n    /// @notice Contract allowing to retrieve the price in dollar of USG.\n    IAggregatorStablePriceV3 public USGOracle;\n\n    IUSG public USG;\n\n    /// @notice Interests from loan are accumulated in this value on each _checkpointIR.\n    uint256 public mintableInterests;\n\n    /// @notice Gives the parameter of the market\n    mapping(address => IRParams) public irParams;\n\n    /// @notice Last interest rate and timestamp stored during the last interaction. In RAY.\n    mapping(address => IRCheckpoint) public irCheckpoints;\n\n    /// @notice Last debt indexes per market.\n    mapping(address => uint256) public debtIndexes;\n\n    error IRStartPriceLtOne();\n    error CallerNotMarketCreator();\n    error NotAMarket();\n    error A1TooBig();\n    error A2TooBig();\n    error KTooBig();\n    error RMaxTooBig();\n    error RMinBiggerThanRMax();\n    error PMinBiggerThanPInf();\n    error PInfBiggerThanPMax();\n    error PMinBiggerThanPMax();\n    error PMaxBiggerThanOneDollar();\n\n    event CheckpointIR(address indexed market, uint256 irAmount, uint256 newIndex);\n    event SetUSGOracle(IAggregatorStablePriceV3 usgOracle);\n    event SetIRParams(address market, IRParams _irParam);\n\n    constructor(address _owner, IControlTower _controlTower, IAggregatorStablePriceV3 _USGOracle, IUSG _USG) {\n        controlTower = _controlTower;\n        USGOracle = _USGOracle;\n        USG = _USG;\n        _transferOwnership(_owner);\n    }\n\n    function _verifyIRParams(IRParams calldata _irParam) internal pure {\n        require(_irParam.a1 <= 20_000, A1TooBig());\n        require(_irParam.a2 <= 20_000, A2TooBig());\n        require(_irParam.k <= 20_000, KTooBig());\n        require(_irParam.rMax <= 400_000, RMaxTooBig());\n        require(_irParam.rMin <= _irParam.rMax, RMinBiggerThanRMax());\n        require(_irParam.pMin <= _irParam.pInf, PMinBiggerThanPInf());\n        require(_irParam.pInf <= _irParam.pMax, PInfBiggerThanPMax());\n        require(_irParam.pMin < _irParam.pMax, PMinBiggerThanPMax());\n        require(_irParam.pMax <= 1_000_000, PMaxBiggerThanOneDollar());\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                        OWNER ACTIONS \n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    function setUSGOracle(IAggregatorStablePriceV3 _USGOracle) external onlyOwner {\n        USGOracle = _USGOracle;\n        emit SetUSGOracle(_USGOracle);\n    }\n\n    function initializeMarket(address market, IRParams calldata _irParam) external nonReentrant {\n        _verifyIRParams(_irParam);\n        require(controlTower.isMarketCreator(msg.sender), CallerNotMarketCreator());\n        debtIndexes[market] = RAY;\n        irParams[market] = _irParam;\n        irCheckpoints[market] = IRCheckpoint({ir: _computeIR(USGOracle.price_w(), _irParam), timestamp: uint40(block.timestamp)});\n    }\n\n    /**\n     *  @notice Updates the IRParameters for a\n     *  @dev    Example :\n     *                    - On a market with 2M debt with 10% interests on 6 month\n     *                    - IndexIncrease = 0.1 * 6 month / 1 year = 5%\n     *                    - Interest Generated = 2M * 5% = 100 000\n     *  @param market Market to checkpoint the index for\n     */\n    function updateIRParams(address market, IRParams calldata _irParam) external nonReentrant onlyOwner {\n        _verifyIRParams(_irParam);\n        irParams[market] = _irParam;\n        _checkpointIR(market);\n        emit SetIRParams(market, _irParam);\n    }\n\n    /**\n     *  @notice Computes and returns the new debt index regarding interests generated allowing to readjust the total debt of the market\n     *          If some interests are generated, it increments the value in USG to be able to mint them later.\n     *  @dev    Example :\n     *                    - On a market with 2M debt with 10% interests on 6 month\n     *                    - IndexIncrease = 0.1 * 6 month / 1 year = 5%\n     *                    - Interest Generated = 2M * 5% = 100 000\n     *  @param market Market to checkpoint the index for\n     */\n    function checkpointIR(address market) external nonReentrant returns (uint256) {\n        return _checkpointIR(market);\n    }\n\n    function _checkpointIR(address market) internal returns (uint256) {\n        uint256 oldIndex = debtIndexes[market];\n        // If the old index is 0, for `market`, it means it has never been initialized\n        require(oldIndex != 0, NotAMarket());\n\n        IRCheckpoint memory _irCheckpoint = irCheckpoints[market];\n        uint216 newIR;\n        // In case price_w fails\n        try USGOracle.price_w() returns (uint256 usgPrice) {\n            newIR = _computeIR(usgPrice, irParams[market]);\n        } catch {\n            // Fall back to prior IR if oracle reverts\n            newIR = _irCheckpoint.ir;\n        }\n        irCheckpoints[market] = IRCheckpoint({ir: newIR, timestamp: uint40(block.timestamp)});\n\n        uint256 newIndex = _computeNewDebtIndex(oldIndex, _irCheckpoint);\n\n        uint256 interests = (IDebtIR(market).totalDebtShares() * (newIndex - oldIndex)) / RAY;\n        if (interests != 0) {\n            mintableInterests += interests;\n        }\n\n        debtIndexes[market] = newIndex;\n        emit CheckpointIR(market, interests, newIndex);\n\n        return newIndex;\n    }\n\n    /**\n     *  @notice Computes the new IR on several markets at the same time in an optimized way.\n     *  @dev    Retrive only one time the USG price, and increments only once the mintable interests\n     *  @param markets Markets to checkpoint the indexes for\n     */\n    function checkpointIRMulti(address[] calldata markets) external nonReentrant {\n        uint256 newUSGPrice;\n        bool isSuccess;\n        try USGOracle.price_w() returns (uint256 usgPrice) {\n            newUSGPrice = usgPrice;\n            isSuccess = true;\n        } catch {}\n\n        uint40 ts = uint40(block.timestamp);\n\n        uint256 _mintableInterests;\n        for (uint256 i; i < markets.length; ) {\n            address market = markets[i];\n            IRCheckpoint memory _irCheckpoint = irCheckpoints[market];\n\n            // Nominal case, when price_w is not failing\n            if (isSuccess) {\n                irCheckpoints[market] = IRCheckpoint({ir: _computeIR(newUSGPrice, irParams[market]), timestamp: ts});\n            }\n            // Else, newUSGPrice failed so we take the previous IR\n            else {\n                irCheckpoints[market] = IRCheckpoint({ir: _irCheckpoint.ir, timestamp: ts});\n            }\n\n            uint256 oldIndex = debtIndexes[market];\n            // If the old index is 0, for `market`, it means it has never been initialized\n            require(oldIndex != 0, NotAMarket());\n\n            uint256 newIndex = _computeNewDebtIndex(oldIndex, _irCheckpoint);\n\n            uint256 interests = (IDebtIR(market).totalDebtShares() * (newIndex - oldIndex)) / RAY;\n\n            if (interests != 0) {\n                _mintableInterests += interests;\n            }\n            emit CheckpointIR(market, interests, newIndex);\n\n            debtIndexes[market] = newIndex;\n\n            unchecked {\n                ++i;\n            }\n        }\n        mintableInterests += _mintableInterests;\n    }\n\n    function mintIR() external nonReentrant {\n        uint256 _mintableInterests = mintableInterests;\n        delete mintableInterests;\n        USG.mintIR(_mintableInterests);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    IR COMPUTATION\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    /**\n     * @notice Computes the intest rate regarding the USG price and parameters of the market\n     * @param  market address of the market\n     */\n    function computeIRForMarket(address market) public returns (uint256) {\n        return _computeIR(USGOracle.price_w(), irParams[market]);\n    }\n\n    function getIRParams(address market) external view returns (IRParams memory) {\n        return irParams[market];\n    }\n\n    function getIRCheckpoint(address market) external view returns (IRCheckpoint memory) {\n        return irCheckpoints[market];\n    }\n\n    /**\n     * @notice Computes the intest rate regarding the USG price and parameters sigma and r0 from the market\n     * @param  USGPrice   Price of USG in wei on 18 decimals.\n     * @param  irParam      IR parameters\n     */\n    function simulateIR(uint256 USGPrice, IRParams memory irParam) external pure returns (uint256) {\n        return _computeIR(USGPrice, irParam);\n    }\n\n    function _returnMinIR(bool isHec, uint24 irMin) internal pure returns (uint216) {\n        if (isHec) {\n            return 0;\n        }\n        return uint216(irMin * E13);\n    }\n\n    /**\n     * @notice Computes the intest rate regarding the USG price and parameters sigma and r0 from the market\n     * @param  USGPrice Price of USG in wei.\n     * @param  irParam    IR parameters\n     */\n    function _computeIR(uint256 USGPrice, IRParams memory irParam) internal pure returns (uint216) {\n        if (USGPrice <= uint256(irParam.pMin) * E12) {\n            return uint216(irParam.rMax * E13);\n        }\n        if (USGPrice >= uint256(irParam.pMax) * E12) {\n            return _returnMinIR(irParam.isHEC, irParam.rMin);\n        }\n\n        // x to pass in the σ(x) function, with x = k . (actualPrice - pInflexion)\n        int128 sigmaX = -ABDKMath64x64.mul(ABDKMath64x64.fromUInt(irParam.k), ABDKMath64x64.divi(int256(USGPrice) - int256(int32(irParam.pInf)) * int256(E12), int256(ONE_ETHER)));\n        // To prevent exp overflow\n        if (ABDKMath64x64.toInt(sigmaX) >= MAX_EXP) {\n            sigmaX = ABDKMath64x64.fromInt(MAX_EXP);\n        }\n        int128 one = ABDKMath64x64.fromUInt(1);\n        // σ(x) image with σ(x) = 1 / (1 + exp(-x)) and -x = sigmaX.\n        int128 sigma = ABDKMath64x64.div(one, one + ABDKMath64x64.exp(sigmaX));\n        int128 alpha1 = ABDKMath64x64.divu(irParam.a1, 1_000);\n\n        // α(x) image with α(x) = α1 + (α2 - α1).σ(x)\n        int128 alpha = ABDKMath64x64.add(alpha1, ABDKMath64x64.mul(ABDKMath64x64.sub(ABDKMath64x64.divu(irParam.a2, 1_000), alpha1), sigma));\n\n        // Relative delta beween pMax, pMin and actual Price\n        // quotient = (pMax - actualPrice) / (pMax - pMin )\n        int128 quotientFixedPoint = ABDKMath64x64.divu(((uint256(irParam.pMax) * E12) - USGPrice) / (irParam.pMax - irParam.pMin), E12);\n\n        // To prevent tx to fail on log(0) in _pow in the computation of the IRIncrement\n        // we return the minimum IR\n        if (quotientFixedPoint == 0) {\n            return _returnMinIR(irParam.isHEC, irParam.rMin);\n        }\n\n        // Computes the IR to increment to the minimum IR possible on the market.\n        // irIncr = (rMax - rMin) * ((pMax - actualPrice) / (pMax - pMin))^alpha\n\n        uint256 irIncrement = ABDKMath64x64.mulu(ABDKMath64x64.mul(ABDKMath64x64.fromUInt(irParam.rMax - irParam.rMin), _pow(quotientFixedPoint, alpha)), E13);\n\n        return uint216(uint256(irParam.rMin) * E13 + irIncrement);\n    }\n\n    /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=\n                    DEBT INDEX COMPUTATION\n    =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= */\n\n    // newIndex = oldIndex * exp(ir * timeRatio)\n    function simulateNewDebtIndex(uint256 oldIndex, IRCheckpoint memory _checkpoint) external view returns (uint256) {\n        return _computeNewDebtIndex(oldIndex, _checkpoint);\n    }\n\n    function newDebtIndex(address market) external view returns (uint256) {\n        IRCheckpoint memory _irCheckpoint = irCheckpoints[market];\n        return _computeNewDebtIndex(debtIndexes[market], _irCheckpoint);\n    }\n\n    function indexDelta(address market) external view returns (uint256) {\n        uint256 oldIndex = debtIndexes[market];\n        return _computeNewDebtIndex(oldIndex, irCheckpoints[market]) - oldIndex;\n    }\n\n    // newIndex = oldIndex * exp(ir * timeRatio)\n    function _computeNewDebtIndex(uint256 oldIndex, IRCheckpoint memory _checkpoint) internal view returns (uint256) {\n        uint256 timeDelta = block.timestamp - _checkpoint.timestamp;\n        if (timeDelta == 0) {\n            return oldIndex;\n        }\n\n        int128 expContent = ABDKMath64x64.mul(ABDKMath64x64.divu(_checkpoint.ir, ONE_ETHER), ABDKMath64x64.divu(timeDelta, 365 days));\n\n        // To prevent exp overflow\n        if (ABDKMath64x64.toInt(expContent) >= MAX_EXP) {\n            expContent = ABDKMath64x64.fromInt(MAX_EXP);\n        }\n\n        return (ABDKMath64x64.mulu(ABDKMath64x64.exp(expContent), RAY) * oldIndex) / RAY;\n    }\n\n    function _pow(int128 a, int128 b) private pure returns (int128) {\n        return ABDKMath64x64.exp_2(ABDKMath64x64.mul(ABDKMath64x64.log_2(a), b));\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f5ffd5b5060043610610184575f3560e01c80637d7d33d0116100dd578063bbe462ce11610088578063f2fde38b11610063578063f2fde38b14610732578063f5d30f9114610745578063fb97fd3b1461074d575f5ffd5b8063bbe462ce1461059e578063d376c4c1146105b1578063dc94c7c7146105ba575f5ffd5b806394d5a0ec116100b857806394d5a0ec146104db5780639789b8dd146104ee578063a76ad68e14610501575f5ffd5b80637d7d33d01461049f5780638da5cb5b146104b2578063918f8674146104d1575f5ffd5b806320963a631161013d578063733103b811610118578063733103b81461045957806373c1ca901461047957806379b40d081461048c575f5ffd5b806320963a631461034857806325200aa314610426578063686a503b14610446575f5ffd5b80630975bb7e1161016d5780630975bb7e146101c35780630c6c6c5f146102085780631d61d2b714610335575f5ffd5b806302e712dd1461018857806308d85659146101ae575b5f5ffd5b61019b61019636600461322e565b61076c565b6040519081526020015b60405180910390f35b6101c16101bc366004613249565b610939565b005b6001546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a5565b6102dc61021636600461322e565b60056020525f908152604090205460ff81169062ffffff6101008204169063ffffffff64010000000082048116916801000000000000000081048216916c0100000000000000000000000082048116917001000000000000000000000000000000008104821691740100000000000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000081048216917c01000000000000000000000000000000000000000000000000000000009091041689565b604080519915158a5262ffffff90981660208a015263ffffffff9687169789019790975293851660608801529184166080870152831660a0860152821660c0850152811660e084015216610100820152610120016101a5565b6101c16103433660046132ba565b610ea9565b6103e761035636600461322e565b604080518082019091525f80825260208201525073ffffffffffffffffffffffffffffffffffffffff165f908152600660209081526040918290208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff811683527b01000000000000000000000000000000000000000000000000000000900464ffffffffff169082015290565b6040805182517affffffffffffffffffffffffffffffffffffffffffffffffffffff16815260209283015164ffffffffff1692810192909252016101a5565b6002546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b6101c16104543660046132ba565b610f40565b6003546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b61019b61048736600461322e565b61119c565b61019b61049a366004613367565b6111bd565b61019b6104ad36600461322e565b6111d1565b5f546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b61019b620186a081565b6101c16104e936600461322e565b61126a565b61019b6104fc366004613553565b6112eb565b61056561050f36600461322e565b60066020525f90815260409020547affffffffffffffffffffffffffffffffffffffffffffffffffffff8116907b01000000000000000000000000000000000000000000000000000000900464ffffffffff1682565b604080517affffffffffffffffffffffffffffffffffffffffffffffffffffff909316835264ffffffffff9091166020830152016101a5565b61019b6105ac36600461322e565b61131a565b61019b60045481565b6107256105c836600461322e565b60408051610120810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091525073ffffffffffffffffffffffffffffffffffffffff165f90815260056020908152604091829020825161012081018452905460ff81161515825261010080820462ffffff1693830193909352640100000000810463ffffffff90811694830194909452680100000000000000008104841660608301526c010000000000000000000000008104841660808301527001000000000000000000000000000000008104841660a0830152740100000000000000000000000000000000000000008104841660c083015278010000000000000000000000000000000000000000000000008104841660e08301527c010000000000000000000000000000000000000000000000000000000090049092169082015290565b6040516101a5919061357f565b6101c161074036600461322e565b6113b6565b6101c161141e565b61019b61075b36600461322e565b60076020525f908152604090205481565b5f61091660025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ceb7f7596040518163ffffffff1660e01b81526004016020604051808303815f875af11580156107db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ff919061364c565b73ffffffffffffffffffffffffffffffffffffffff84165f90815260056020908152604091829020825161012081018452905460ff81161515825261010080820462ffffff1693830193909352640100000000810463ffffffff90811694830194909452680100000000000000008104841660608301526c010000000000000000000000008104841660808301527001000000000000000000000000000000008104841660a0830152740100000000000000000000000000000000000000008104841660c083015278010000000000000000000000000000000000000000000000008104841660e08301527c01000000000000000000000000000000000000000000000000000000009004909216908201526114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff1692915050565b610941611724565b5f5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ceb7f7596040518163ffffffff1660e01b81526004016020604051808303815f875af19250505080156109ea575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526109e79181019061364c565b60015b156109f6579150600190505b425f805b85811015610e80575f878783818110610a1557610a15613663565b9050602002016020810190610a2a919061322e565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600660209081526040918290208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff811683527b01000000000000000000000000000000000000000000000000000000900464ffffffffff16908201529091508515610c54576040805173ffffffffffffffffffffffffffffffffffffffff84165f9081526005602052829020610160820183525460ff8116151592820192835261010080820462ffffff166060840152640100000000820463ffffffff9081166080850152680100000000000000008304811660a08501526c010000000000000000000000008304811660c08501527001000000000000000000000000000000008304811660e08501527401000000000000000000000000000000000000000083048116918401919091527801000000000000000000000000000000000000000000000000820481166101208401527c010000000000000000000000000000000000000000000000000000000090910416610140820152908190610bce908a906114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff908116825264ffffffffff80891660209384015273ffffffffffffffffffffffffffffffffffffffff86165f908152600684526040902084519490930151167b01000000000000000000000000000000000000000000000000000000029216919091179055610ce1565b60408051808201825282517affffffffffffffffffffffffffffffffffffffffffffffffffffff908116825264ffffffffff808916602080850191825273ffffffffffffffffffffffffffffffffffffffff88165f90815260069091529490942092519351167b010000000000000000000000000000000000000000000000000000000292169190911790555b73ffffffffffffffffffffffffffffffffffffffff82165f9081526007602052604081205490819003610d40576040517ff050992300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610d4b82846117aa565b90505f6b033b2e3c9fd0803ce8000000610d6584846136bd565b8673ffffffffffffffffffffffffffffffffffffffff16631b859e416040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dae573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd2919061364c565b610ddc91906136d0565b610de69190613714565b90508015610dfb57610df8818861374c565b96505b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8716917f68ca32afbb6c97f78310c45d7fe5e6d900e815be910458a6b4290c6cb5cf31d0910160405180910390a25073ffffffffffffffffffffffffffffffffffffffff9093165f9081526007602052604090209290925550506001016109fa565b508060045f828254610e92919061374c565b9250508190555050505050610ea5611888565b5050565b610eb1611724565b610eb96118b2565b610ec281611904565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526005602052604090208190610ef2828261376b565b905050610efe82611c2c565b507f6fcb987ada067489bd2ad13d8a578439b355c2e2ab28b3b46aade9beaee0db6c8282604051610f30929190613a30565b60405180910390a1610ea5611888565b610f48611724565b610f5181611904565b6001546040517ff97b7a3b00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063f97b7a3b90602401602060405180830381865afa158015610fbd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fe19190613b33565b611017576040517f754a322000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f9081526007602090815260408083206b033b2e3c9fd0803ce80000009055600590915290208190611060828261376b565b5050604080518082018083526002547fceb7f759000000000000000000000000000000000000000000000000000000009091529151909182916111139173ffffffffffffffffffffffffffffffffffffffff169063ceb7f7599060448086019160209181880301815f875af11580156110db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ff919061364c565b61110e36869003860186613b4e565b6114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff908116825264ffffffffff42811660209384015273ffffffffffffffffffffffffffffffffffffffff86165f908152600684526040902084519490930151167b01000000000000000000000000000000000000000000000000000000029216919091179055610ea5611888565b5f6111a5611724565b6111ae82611c2c565b90506111b8611888565b919050565b5f6111c883836117aa565b90505b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602090815260408083208151808301835290547affffffffffffffffffffffffffffffffffffffffffffffffffffff811682527b01000000000000000000000000000000000000000000000000000000900464ffffffffff1681840152938352600790915281205490919061126390826117aa565b9392505050565b6112726118b2565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff96ae86bf34008ef62cc9545e90685f1d67facee461c5f7469e95655f76191f79060200160405180910390a150565b5f6112f683836114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff169392505050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260076020908152604080832054600683528184208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff811683527b01000000000000000000000000000000000000000000000000000000900464ffffffffff169282019290925281906113ac9082906117aa565b61126391906136bd565b6113be6118b2565b73ffffffffffffffffffffffffffffffffffffffff8116611412576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024015b60405180910390fd5b61141b81612078565b50565b611426611724565b600480545f82556003546040517fe9734c12000000000000000000000000000000000000000000000000000000008152928301829052909173ffffffffffffffffffffffffffffffffffffffff9091169063e9734c12906024015f604051808303815f87803b158015611497575f5ffd5b505af11580156114a9573d5f5f3e3d5ffd5b50505050506114b6611888565b565b5f64e8d4a51000826060015163ffffffff166114d491906136d0565b83116114fd576509184e72a000826040015163ffffffff166114f691906136d0565b90506111cb565b64e8d4a510008260a0015163ffffffff1661151891906136d0565b831061152f576114f6825f015183602001516120ec565b5f61157f61154784610100015163ffffffff1661210f565b61157a64e8d4a51000866080015160030b6115629190613b69565b61156c9088613bb4565b670de0b6b3a764000061212b565b6121dd565b61158890613bd3565b9050602b61159982600f0b60401d90565b60070b126115ae576115ab602b612233565b90505b5f6115b9600161210f565b90505f6115d8826115c985612274565b6115d39085613c0f565b6122e1565b90505f6115f18660c0015163ffffffff166103e8612354565b90505f6116258261162061161a6116148b60e0015163ffffffff166103e8612354565b8661239b565b866121dd565b6123ed565b90505f61168088606001518960a0015161163f9190613c5d565b63ffffffff168a64e8d4a510008b60a0015163ffffffff1661166191906136d0565b61166b91906136bd565b6116759190613714565b64e8d4a51000612354565b905080600f0b5f036116aa5761169d885f015189602001516120ec565b96505050505050506111cb565b5f6116ee6116e26116d88b6020015162ffffff168c604001516116cd9190613c5d565b63ffffffff1661210f565b61157a858761243f565b6509184e72a00061245a565b9050806509184e72a0008a6020015162ffffff1661170c91906136d0565b611716919061374c565b9a9950505050505050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c1561177d576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114b660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b906124d8565b5f5f826020015164ffffffffff16426117c391906136bd565b9050805f036117d557839150506111cb565b5f61181961180b855f01517affffffffffffffffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000612354565b61157a846301e13380612354565b9050602b61182a82600f0b60401d90565b60070b1261183f5761183c602b612233565b90505b6b033b2e3c9fd0803ce80000008561186b61185984612274565b6b033b2e3c9fd0803ce800000061245a565b61187591906136d0565b61187f9190613714565b95945050505050565b6114b65f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006117a4565b5f5473ffffffffffffffffffffffffffffffffffffffff1633146114b6576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401611409565b614e2061191760e0830160c08401613c79565b63ffffffff161115611955576040517fe9ac213800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614e20611969610100830160e08401613c79565b63ffffffff1611156119a7576040517f9bd92d0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614e206119bc61012083016101008401613c79565b63ffffffff1611156119fa576040517fefe64dec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62061a80611a0e6060830160408401613c79565b63ffffffff161115611a4c576040517f615323f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a5c6060820160408301613c79565b63ffffffff16611a726040830160208401613c94565b62ffffff161115611aaf576040517fb94549ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611abf60a0820160808301613c79565b63ffffffff16611ad56080830160608401613c79565b63ffffffff161115611b13576040517f8a2ebfa100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b2360c0820160a08301613c79565b63ffffffff16611b3960a0830160808401613c79565b63ffffffff161115611b77576040517f033821ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b8760c0820160a08301613c79565b63ffffffff16611b9d6080830160608401613c79565b63ffffffff1610611bda576040517f26b6e66400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620f4240611bee60c0830160a08401613c79565b63ffffffff16111561141b576040517fde7bffc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260076020526040812054808203611c8a576040517ff050992300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8381165f9081526006602090815260408083208151808301835290547affffffffffffffffffffffffffffffffffffffffffffffffffffff811682527b01000000000000000000000000000000000000000000000000000000900464ffffffffff168184015260025482517fceb7f75900000000000000000000000000000000000000000000000000000000815292519195169263ceb7f7599260048082019391829003018187875af1925050508015611d94575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611d919181019061364c565b60015b611da057508051611ec1565b73ffffffffffffffffffffffffffffffffffffffff86165f90815260056020908152604091829020825161012081018452905460ff81161515825261010080820462ffffff1693830193909352640100000000810463ffffffff90811694830194909452680100000000000000008104841660608301526c010000000000000000000000008104841660808301527001000000000000000000000000000000008104841660a0830152740100000000000000000000000000000000000000008104841660c083015278010000000000000000000000000000000000000000000000008104841660e08301527c0100000000000000000000000000000000000000000000000000000000900490921690820152611ebd9082906114b8565b9150505b6040805180820182527affffffffffffffffffffffffffffffffffffffffffffffffffffff808416825264ffffffffff428116602080850191825273ffffffffffffffffffffffffffffffffffffffff8b165f9081526006909152948520935190519091167b01000000000000000000000000000000000000000000000000000000029116179055611f5384846117aa565b90505f6b033b2e3c9fd0803ce8000000611f6d86846136bd565b8873ffffffffffffffffffffffffffffffffffffffff16631b859e416040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fda919061364c565b611fe491906136d0565b611fee9190613714565b9050801561200d578060045f828254612007919061374c565b90915550505b73ffffffffffffffffffffffffffffffffffffffff87165f8181526007602090815260409182902085905581518481529081018590527f68ca32afbb6c97f78310c45d7fe5e6d900e815be910458a6b4290c6cb5cf31d0910160405180910390a25095945050505050565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f82156120fa57505f6111cb565b6111c86509184e72a00062ffffff84166136d0565b5f677fffffffffffffff821115612124575f5ffd5b5060401b90565b5f815f03612137575f5ffd5b5f8084121561214a57835f039350600190505b5f83121561215a575f9290920391155b5f61216585856124df565b905081156121a6576f80000000000000000000000000000000816fffffffffffffffffffffffffffffffff16111561219b575f5ffd5b5f0391506111cb9050565b6f7fffffffffffffffffffffffffffffff816fffffffffffffffffffffffffffffffff1611156121d4575f5ffd5b91506111cb9050565b5f600f83810b9083900b0260401d7fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113155b6111c8575f5ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000821215801561226c5750677fffffffffffffff8213155b612124575f5ffd5b5f6840000000000000000082600f0b1261228c575f5ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffc0000000000000000082600f0b12156122be57505f919050565b6111cb608083600f0b700171547652b82fe1777d0ffda0d23a7d1202901d61266a565b5f81600f0b5f036122f0575f5ffd5b5f82600f0b604085600f0b901b8161230a5761230a6136e7565b0590507fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113156111c8575f5ffd5b5f815f03612360575f5ffd5b5f61236b84846124df565b90506f7fffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff821611156111c8575f5ffd5b5f600f82810b9084900b037fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113156111c8575f5ffd5b5f600f83810b9083900b017fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113156111c8575f5ffd5b5f6111c861245561244f8561310f565b846121dd565b61266a565b5f815f0361246957505f6111cb565b5f83600f0b1215612478575f5ffd5b600f83900b6fffffffffffffffffffffffffffffffff8316810260401c90608084901c0277ffffffffffffffffffffffffffffffffffffffffffffffff8111156124c0575f5ffd5b60401b81198111156124d0575f5ffd5b019392505050565b80825d5050565b5f815f036124eb575f5ffd5b5f77ffffffffffffffffffffffffffffffffffffffffffffffff84116125265782604085901b8161251e5761251e6136e7565b04905061264e565b60c084811c640100000000811061253f576020918201911c5b620100008110612551576010918201911c5b6101008110612562576008918201911c5b60108110612572576004918201911c5b60048110612582576002918201911c5b60028110612591576001820191505b60bf820360018603901c6001018260ff0387901b816125b2576125b26136e7565b0492506fffffffffffffffffffffffffffffffff8311156125d1575f5ffd5b608085901c83026fffffffffffffffffffffffffffffffff8616840260c088901c604089901b82811015612606576001820391505b608084901b9290038281101561261d576001820391505b829003608084901c8214612632576001612643565b888181612641576126416136e7565b045b870196505050505050505b6fffffffffffffffffffffffffffffffff8111156111c8575f5ffd5b5f6840000000000000000082600f0b12612682575f5ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffc0000000000000000082600f0b12156126b457505f919050565b6f800000000000000000000000000000005f6780000000000000008416600f0b13156126f15770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b5f8367400000000000000016600f0b131561271d577001306fe0a31b7152de8d5a46305c85edec0260801c5b5f8367200000000000000016600f0b1315612749577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b5f8367100000000000000016600f0b13156127755770010b5586cf9890f6298b92b71842a983630260801c5b5f8367080000000000000016600f0b13156127a1577001059b0d31585743ae7c548eb68ca417fd0260801c5b5f8367040000000000000016600f0b13156127cd57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b5f8367020000000000000016600f0b13156127f95770010163da9fb33356d84a66ae336dcdfa3f0260801c5b5f8367010000000000000016600f0b131561282557700100b1afa5abcbed6129ab13ec11dc95430260801c5b5f83668000000000000016600f0b13156128505770010058c86da1c09ea1ff19d294cf2f679b0260801c5b5f83664000000000000016600f0b131561287b577001002c605e2e8cec506d21bfc89a23a00f0260801c5b5f83662000000000000016600f0b13156128a657700100162f3904051fa128bca9c55c31e5df0260801c5b5f83661000000000000016600f0b13156128d1577001000b175effdc76ba38e31671ca9397250260801c5b5f83660800000000000016600f0b13156128fc57700100058ba01fb9f96d6cacd4b180917c3d0260801c5b5f83660400000000000016600f0b13156129275770010002c5cc37da9491d0985c348c68e7b30260801c5b5f83660200000000000016600f0b1315612952577001000162e525ee054754457d59952920260260801c5b5f83660100000000000016600f0b131561297d5770010000b17255775c040618bf4a4ade83fc0260801c5b5f836580000000000016600f0b13156129a7577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b5f836540000000000016600f0b13156129d157700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b5f836520000000000016600f0b13156129fb5770010000162e43f4f831060e02d839a9d16d0260801c5b5f836510000000000016600f0b1315612a2557700100000b1721bcfc99d9f890ea069117630260801c5b5f836508000000000016600f0b1315612a4f5770010000058b90cf1e6d97f9ca14dbcc16280260801c5b5f836504000000000016600f0b1315612a79577001000002c5c863b73f016468f6bac5ca2b0260801c5b5f836502000000000016600f0b1315612aa357700100000162e430e5a18f6119e3c02282a50260801c5b5f836501000000000016600f0b1315612acd577001000000b1721835514b86e6d96efd1bfe0260801c5b5f8364800000000016600f0b1315612af657700100000058b90c0b48c6be5df846c5b2ef0260801c5b5f8364400000000016600f0b1315612b1f5770010000002c5c8601cc6b9e94213c72737a0260801c5b5f8364200000000016600f0b1315612b48577001000000162e42fff037df38aa2b219f060260801c5b5f8364100000000016600f0b1315612b715770010000000b17217fba9c739aa5819f44f90260801c5b5f8364080000000016600f0b1315612b9a577001000000058b90bfcdee5acd3c1cedc8230260801c5b5f8364040000000016600f0b1315612bc357700100000002c5c85fe31f35a6a30da1be500260801c5b5f8364020000000016600f0b1315612bec5770010000000162e42ff0999ce3541b9fffcf0260801c5b5f8364010000000016600f0b1315612c1557700100000000b17217f80f4ef5aadda455540260801c5b5f83638000000016600f0b1315612c3d5770010000000058b90bfbf8479bd5a81b51ad0260801c5b5f83634000000016600f0b1315612c65577001000000002c5c85fdf84bd62ae30a74cc0260801c5b5f83632000000016600f0b1315612c8d57700100000000162e42fefb2fed257559bdaa0260801c5b5f83631000000016600f0b1315612cb5577001000000000b17217f7d5a7716bba4a9ae0260801c5b5f83630800000016600f0b1315612cdd57700100000000058b90bfbe9ddbac5e109cce0260801c5b5f83630400000016600f0b1315612d055770010000000002c5c85fdf4b15de6f17eb0d0260801c5b5f83630200000016600f0b1315612d2d577001000000000162e42fefa494f1478fde050260801c5b5f83630100000016600f0b1315612d555770010000000000b17217f7d20cf927c8e94c0260801c5b5f836280000016600f0b1315612d7c577001000000000058b90bfbe8f71cb4e4b33d0260801c5b5f836240000016600f0b1315612da357700100000000002c5c85fdf477b662b269450260801c5b5f836220000016600f0b1315612dca5770010000000000162e42fefa3ae53369388c0260801c5b5f836210000016600f0b1315612df157700100000000000b17217f7d1d351a389d400260801c5b5f836208000016600f0b1315612e185770010000000000058b90bfbe8e8b2d3d4ede0260801c5b5f836204000016600f0b1315612e3f577001000000000002c5c85fdf4741bea6e77e0260801c5b5f836202000016600f0b1315612e6657700100000000000162e42fefa39fe95583c20260801c5b5f836201000016600f0b1315612e8d577001000000000000b17217f7d1cfb72b45e10260801c5b5f8361800016600f0b1315612eb357700100000000000058b90bfbe8e7cc35c3f00260801c5b5f8361400016600f0b1315612ed95770010000000000002c5c85fdf473e242ea380260801c5b5f8361200016600f0b1315612eff577001000000000000162e42fefa39f02b772c0260801c5b5f8361100016600f0b1315612f255770010000000000000b17217f7d1cf7d83c1a0260801c5b5f8361080016600f0b1315612f4b577001000000000000058b90bfbe8e7bdcbe2e0260801c5b5f8361040016600f0b1315612f7157700100000000000002c5c85fdf473dea871f0260801c5b5f8361020016600f0b1315612f975770010000000000000162e42fefa39ef44d910260801c5b5f8361010016600f0b1315612fbd57700100000000000000b17217f7d1cf79e9490260801c5b5f83608016600f0b1315612fe25770010000000000000058b90bfbe8e7bce5440260801c5b5f83604016600f0b1315613007577001000000000000002c5c85fdf473de6eca0260801c5b5f83602016600f0b131561302c57700100000000000000162e42fefa39ef366f0260801c5b5f83601016600f0b1315613051577001000000000000000b17217f7d1cf79afa0260801c5b5f83600816600f0b131561307657700100000000000000058b90bfbe8e7bcd6d0260801c5b5f83600416600f0b131561309b5770010000000000000002c5c85fdf473de6b20260801c5b5f83600216600f0b13156130c0577001000000000000000162e42fefa39ef3580260801c5b5f83600116600f0b13156130e55770010000000000000000b17217f7d1cf79ab0260801c5b600f83810b60401d603f03900b1c6f7fffffffffffffffffffffffffffffff8111156111cb575f5ffd5b5f5f82600f0b1361311e575f5ffd5b5f600f83900b68010000000000000000811261313c576040918201911d5b6401000000008112613150576020918201911d5b620100008112613162576010918201911d5b6101008112613173576008918201911d5b60108112613183576004918201911d5b60048112613193576002918201911d5b600281126131a2576001820191505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820160401b600f85900b607f8490031b6780000000000000005b5f8113156132025790800260ff81901c8281029390930192607f011c9060011d6131dd565b509095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461141b575f5ffd5b5f6020828403121561323e575f5ffd5b81356111c88161320d565b5f5f6020838503121561325a575f5ffd5b823567ffffffffffffffff811115613270575f5ffd5b8301601f81018513613280575f5ffd5b803567ffffffffffffffff811115613296575f5ffd5b8560208260051b84010111156132aa575f5ffd5b6020919091019590945092505050565b5f5f8284036101408112156132cd575f5ffd5b83356132d88161320d565b92506101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561330a575f5ffd5b506020830190509250929050565b604051610120810167ffffffffffffffff81118282101715613361577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405290565b5f5f8284036060811215613379575f5ffd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820112156133ac575f5ffd5b506040805190810167ffffffffffffffff811182821017156133f5577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405260208401357affffffffffffffffffffffffffffffffffffffffffffffffffffff81168114613425575f5ffd5b8152604084013564ffffffffff8116811461343e575f5ffd5b6020820152919491935090915050565b801515811461141b575f5ffd5b80356111b88161344e565b62ffffff8116811461141b575f5ffd5b80356111b881613466565b63ffffffff8116811461141b575f5ffd5b80356111b881613481565b5f61012082840312156134ae575f5ffd5b6134b6613318565b90506134c18261345b565b81526134cf60208301613476565b60208201526134e060408301613492565b60408201526134f160608301613492565b606082015261350260808301613492565b608082015261351360a08301613492565b60a082015261352460c08301613492565b60c082015261353560e08301613492565b60e08201526135476101008301613492565b61010082015292915050565b5f5f6101408385031215613565575f5ffd5b82359150613576846020850161349d565b90509250929050565b5f6101208201905082511515825262ffffff602084015116602083015260408301516135b3604084018263ffffffff169052565b5060608301516135cb606084018263ffffffff169052565b5060808301516135e3608084018263ffffffff169052565b5060a08301516135fb60a084018263ffffffff169052565b5060c083015161361360c084018263ffffffff169052565b5060e083015161362b60e084018263ffffffff169052565b5061010083015161364561010084018263ffffffff169052565b5092915050565b5f6020828403121561365c575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156111cb576111cb613690565b80820281158282048414176111cb576111cb613690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82613747577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b808201808211156111cb576111cb613690565b5f81356111cb81613481565b81356137768161344e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541660ff8215151681178355505060208201356137b481613466565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ff1660089190911b63ffffff001617815561382f6137f66040840161375f565b82547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1660209190911b67ffffffff0000000016178255565b61387b61383e6060840161375f565b82547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1660409190911b6bffffffff000000000000000016178255565b6138cb61388a6080840161375f565b82547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff1660609190911b6fffffffff00000000000000000000000016178255565b61391f6138da60a0840161375f565b82547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1660809190911b73ffffffff0000000000000000000000000000000016178255565b61397761392e60c0840161375f565b82547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b77ffffffff000000000000000000000000000000000000000016178255565b6139d361398660e0840161375f565b82547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7bffffffff00000000000000000000000000000000000000000000000016178255565b610ea56139e3610100840161375f565b82547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09190911b7fffffffff0000000000000000000000000000000000000000000000000000000016178255565b73ffffffffffffffffffffffffffffffffffffffff8316815261014081018235613a598161344e565b801515602084015250613a6e60208401613476565b62ffffff8116604084015250613a8660408401613492565b63ffffffff8116606084015250613a9f60608401613492565b63ffffffff8116608084015250613ab860808401613492565b63ffffffff811660a084015250613ad160a08401613492565b63ffffffff811660c084015250613aea60c08401613492565b63ffffffff811660e084015250613b0360e08401613492565b63ffffffff811661010084015250613b1e6101008401613492565b63ffffffff8116610120840152509392505050565b5f60208284031215613b43575f5ffd5b81516111c88161344e565b5f6101208284031215613b5f575f5ffd5b6111c8838361349d565b8082025f82127f800000000000000000000000000000000000000000000000000000000000000084141615613ba057613ba0613690565b81810583148215176111cb576111cb613690565b8181035f83128015838313168383128216171561364557613645613690565b5f81600f0b7fffffffffffffffffffffffffffffffff800000000000000000000000000000008103613c0757613c07613690565b5f0392915050565b600f81810b9083900b016f7fffffffffffffffffffffffffffffff81137fffffffffffffffffffffffffffffffff80000000000000000000000000000000821217156111cb576111cb613690565b63ffffffff82811682821603908111156111cb576111cb613690565b5f60208284031215613c89575f5ffd5b81356111c881613481565b5f60208284031215613ca4575f5ffd5b81356111c88161346656fea2646970667358221220e67d3b84e0cdddc879cd26c699144d436214b4b23a8e7ce523755715c6b544e664736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":1000000},"remappings":[]},"optimization_runs":1000000,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/full_match/1/0xB4e1d3bBd2843263d58B4D648C599512cea6e88b/","decoded_constructor_args":[["0x461B62CB3A7e9Df8f800aE058AE92F855F2c27Ca",{"internalType":"address","name":"_owner","type":"address"}],["0xF3f7669dcEED2f985815011C19eD68F667267215",{"internalType":"contract IControlTower","name":"_controlTower","type":"address"}],["0x970b2F2cEc66F92dE81DAe6af363d1D135dD2F97",{"internalType":"contract IAggregatorStablePriceV3","name":"_USGOracle","type":"address"}],["0xB1c2Db5d6cA03FCe73dBd304d320bF76C55Ae1B1",{"internalType":"contract IUSG","name":"_USG","type":"address"}]],"compiler_version":"0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-03-01T15:14:54.522216Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801561000f575f5ffd5b50604051613e31380380613e3183398101604081905261002e916100e3565b600180546001600160a01b038086166001600160a01b0319928316179092556002805485841690831617905560038054928416929091169190911790556100748461007d565b5050505061013f565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146100e0575f5ffd5b50565b5f5f5f5f608085870312156100f6575f5ffd5b8451610101816100cc565b6020860151909450610112816100cc565b6040860151909350610123816100cc565b6060860151909250610134816100cc565b939692955090935050565b613ce58061014c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610184575f3560e01c80637d7d33d0116100dd578063bbe462ce11610088578063f2fde38b11610063578063f2fde38b14610732578063f5d30f9114610745578063fb97fd3b1461074d575f5ffd5b8063bbe462ce1461059e578063d376c4c1146105b1578063dc94c7c7146105ba575f5ffd5b806394d5a0ec116100b857806394d5a0ec146104db5780639789b8dd146104ee578063a76ad68e14610501575f5ffd5b80637d7d33d01461049f5780638da5cb5b146104b2578063918f8674146104d1575f5ffd5b806320963a631161013d578063733103b811610118578063733103b81461045957806373c1ca901461047957806379b40d081461048c575f5ffd5b806320963a631461034857806325200aa314610426578063686a503b14610446575f5ffd5b80630975bb7e1161016d5780630975bb7e146101c35780630c6c6c5f146102085780631d61d2b714610335575f5ffd5b806302e712dd1461018857806308d85659146101ae575b5f5ffd5b61019b61019636600461322e565b61076c565b6040519081526020015b60405180910390f35b6101c16101bc366004613249565b610939565b005b6001546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a5565b6102dc61021636600461322e565b60056020525f908152604090205460ff81169062ffffff6101008204169063ffffffff64010000000082048116916801000000000000000081048216916c0100000000000000000000000082048116917001000000000000000000000000000000008104821691740100000000000000000000000000000000000000008204811691780100000000000000000000000000000000000000000000000081048216917c01000000000000000000000000000000000000000000000000000000009091041689565b604080519915158a5262ffffff90981660208a015263ffffffff9687169789019790975293851660608801529184166080870152831660a0860152821660c0850152811660e084015216610100820152610120016101a5565b6101c16103433660046132ba565b610ea9565b6103e761035636600461322e565b604080518082019091525f80825260208201525073ffffffffffffffffffffffffffffffffffffffff165f908152600660209081526040918290208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff811683527b01000000000000000000000000000000000000000000000000000000900464ffffffffff169082015290565b6040805182517affffffffffffffffffffffffffffffffffffffffffffffffffffff16815260209283015164ffffffffff1692810192909252016101a5565b6002546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b6101c16104543660046132ba565b610f40565b6003546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b61019b61048736600461322e565b61119c565b61019b61049a366004613367565b6111bd565b61019b6104ad36600461322e565b6111d1565b5f546101e39073ffffffffffffffffffffffffffffffffffffffff1681565b61019b620186a081565b6101c16104e936600461322e565b61126a565b61019b6104fc366004613553565b6112eb565b61056561050f36600461322e565b60066020525f90815260409020547affffffffffffffffffffffffffffffffffffffffffffffffffffff8116907b01000000000000000000000000000000000000000000000000000000900464ffffffffff1682565b604080517affffffffffffffffffffffffffffffffffffffffffffffffffffff909316835264ffffffffff9091166020830152016101a5565b61019b6105ac36600461322e565b61131a565b61019b60045481565b6107256105c836600461322e565b60408051610120810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091525073ffffffffffffffffffffffffffffffffffffffff165f90815260056020908152604091829020825161012081018452905460ff81161515825261010080820462ffffff1693830193909352640100000000810463ffffffff90811694830194909452680100000000000000008104841660608301526c010000000000000000000000008104841660808301527001000000000000000000000000000000008104841660a0830152740100000000000000000000000000000000000000008104841660c083015278010000000000000000000000000000000000000000000000008104841660e08301527c010000000000000000000000000000000000000000000000000000000090049092169082015290565b6040516101a5919061357f565b6101c161074036600461322e565b6113b6565b6101c161141e565b61019b61075b36600461322e565b60076020525f908152604090205481565b5f61091660025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ceb7f7596040518163ffffffff1660e01b81526004016020604051808303815f875af11580156107db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ff919061364c565b73ffffffffffffffffffffffffffffffffffffffff84165f90815260056020908152604091829020825161012081018452905460ff81161515825261010080820462ffffff1693830193909352640100000000810463ffffffff90811694830194909452680100000000000000008104841660608301526c010000000000000000000000008104841660808301527001000000000000000000000000000000008104841660a0830152740100000000000000000000000000000000000000008104841660c083015278010000000000000000000000000000000000000000000000008104841660e08301527c01000000000000000000000000000000000000000000000000000000009004909216908201526114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff1692915050565b610941611724565b5f5f60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ceb7f7596040518163ffffffff1660e01b81526004016020604051808303815f875af19250505080156109ea575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526109e79181019061364c565b60015b156109f6579150600190505b425f805b85811015610e80575f878783818110610a1557610a15613663565b9050602002016020810190610a2a919061322e565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600660209081526040918290208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff811683527b01000000000000000000000000000000000000000000000000000000900464ffffffffff16908201529091508515610c54576040805173ffffffffffffffffffffffffffffffffffffffff84165f9081526005602052829020610160820183525460ff8116151592820192835261010080820462ffffff166060840152640100000000820463ffffffff9081166080850152680100000000000000008304811660a08501526c010000000000000000000000008304811660c08501527001000000000000000000000000000000008304811660e08501527401000000000000000000000000000000000000000083048116918401919091527801000000000000000000000000000000000000000000000000820481166101208401527c010000000000000000000000000000000000000000000000000000000090910416610140820152908190610bce908a906114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff908116825264ffffffffff80891660209384015273ffffffffffffffffffffffffffffffffffffffff86165f908152600684526040902084519490930151167b01000000000000000000000000000000000000000000000000000000029216919091179055610ce1565b60408051808201825282517affffffffffffffffffffffffffffffffffffffffffffffffffffff908116825264ffffffffff808916602080850191825273ffffffffffffffffffffffffffffffffffffffff88165f90815260069091529490942092519351167b010000000000000000000000000000000000000000000000000000000292169190911790555b73ffffffffffffffffffffffffffffffffffffffff82165f9081526007602052604081205490819003610d40576040517ff050992300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610d4b82846117aa565b90505f6b033b2e3c9fd0803ce8000000610d6584846136bd565b8673ffffffffffffffffffffffffffffffffffffffff16631b859e416040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dae573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd2919061364c565b610ddc91906136d0565b610de69190613714565b90508015610dfb57610df8818861374c565b96505b604080518281526020810184905273ffffffffffffffffffffffffffffffffffffffff8716917f68ca32afbb6c97f78310c45d7fe5e6d900e815be910458a6b4290c6cb5cf31d0910160405180910390a25073ffffffffffffffffffffffffffffffffffffffff9093165f9081526007602052604090209290925550506001016109fa565b508060045f828254610e92919061374c565b9250508190555050505050610ea5611888565b5050565b610eb1611724565b610eb96118b2565b610ec281611904565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526005602052604090208190610ef2828261376b565b905050610efe82611c2c565b507f6fcb987ada067489bd2ad13d8a578439b355c2e2ab28b3b46aade9beaee0db6c8282604051610f30929190613a30565b60405180910390a1610ea5611888565b610f48611724565b610f5181611904565b6001546040517ff97b7a3b00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063f97b7a3b90602401602060405180830381865afa158015610fbd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fe19190613b33565b611017576040517f754a322000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f9081526007602090815260408083206b033b2e3c9fd0803ce80000009055600590915290208190611060828261376b565b5050604080518082018083526002547fceb7f759000000000000000000000000000000000000000000000000000000009091529151909182916111139173ffffffffffffffffffffffffffffffffffffffff169063ceb7f7599060448086019160209181880301815f875af11580156110db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ff919061364c565b61110e36869003860186613b4e565b6114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff908116825264ffffffffff42811660209384015273ffffffffffffffffffffffffffffffffffffffff86165f908152600684526040902084519490930151167b01000000000000000000000000000000000000000000000000000000029216919091179055610ea5611888565b5f6111a5611724565b6111ae82611c2c565b90506111b8611888565b919050565b5f6111c883836117aa565b90505b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602090815260408083208151808301835290547affffffffffffffffffffffffffffffffffffffffffffffffffffff811682527b01000000000000000000000000000000000000000000000000000000900464ffffffffff1681840152938352600790915281205490919061126390826117aa565b9392505050565b6112726118b2565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff96ae86bf34008ef62cc9545e90685f1d67facee461c5f7469e95655f76191f79060200160405180910390a150565b5f6112f683836114b8565b7affffffffffffffffffffffffffffffffffffffffffffffffffffff169392505050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260076020908152604080832054600683528184208251808401909352547affffffffffffffffffffffffffffffffffffffffffffffffffffff811683527b01000000000000000000000000000000000000000000000000000000900464ffffffffff169282019290925281906113ac9082906117aa565b61126391906136bd565b6113be6118b2565b73ffffffffffffffffffffffffffffffffffffffff8116611412576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024015b60405180910390fd5b61141b81612078565b50565b611426611724565b600480545f82556003546040517fe9734c12000000000000000000000000000000000000000000000000000000008152928301829052909173ffffffffffffffffffffffffffffffffffffffff9091169063e9734c12906024015f604051808303815f87803b158015611497575f5ffd5b505af11580156114a9573d5f5f3e3d5ffd5b50505050506114b6611888565b565b5f64e8d4a51000826060015163ffffffff166114d491906136d0565b83116114fd576509184e72a000826040015163ffffffff166114f691906136d0565b90506111cb565b64e8d4a510008260a0015163ffffffff1661151891906136d0565b831061152f576114f6825f015183602001516120ec565b5f61157f61154784610100015163ffffffff1661210f565b61157a64e8d4a51000866080015160030b6115629190613b69565b61156c9088613bb4565b670de0b6b3a764000061212b565b6121dd565b61158890613bd3565b9050602b61159982600f0b60401d90565b60070b126115ae576115ab602b612233565b90505b5f6115b9600161210f565b90505f6115d8826115c985612274565b6115d39085613c0f565b6122e1565b90505f6115f18660c0015163ffffffff166103e8612354565b90505f6116258261162061161a6116148b60e0015163ffffffff166103e8612354565b8661239b565b866121dd565b6123ed565b90505f61168088606001518960a0015161163f9190613c5d565b63ffffffff168a64e8d4a510008b60a0015163ffffffff1661166191906136d0565b61166b91906136bd565b6116759190613714565b64e8d4a51000612354565b905080600f0b5f036116aa5761169d885f015189602001516120ec565b96505050505050506111cb565b5f6116ee6116e26116d88b6020015162ffffff168c604001516116cd9190613c5d565b63ffffffff1661210f565b61157a858761243f565b6509184e72a00061245a565b9050806509184e72a0008a6020015162ffffff1661170c91906136d0565b611716919061374c565b9a9950505050505050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c1561177d576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114b660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b906124d8565b5f5f826020015164ffffffffff16426117c391906136bd565b9050805f036117d557839150506111cb565b5f61181961180b855f01517affffffffffffffffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000612354565b61157a846301e13380612354565b9050602b61182a82600f0b60401d90565b60070b1261183f5761183c602b612233565b90505b6b033b2e3c9fd0803ce80000008561186b61185984612274565b6b033b2e3c9fd0803ce800000061245a565b61187591906136d0565b61187f9190613714565b95945050505050565b6114b65f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006117a4565b5f5473ffffffffffffffffffffffffffffffffffffffff1633146114b6576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401611409565b614e2061191760e0830160c08401613c79565b63ffffffff161115611955576040517fe9ac213800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614e20611969610100830160e08401613c79565b63ffffffff1611156119a7576040517f9bd92d0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b614e206119bc61012083016101008401613c79565b63ffffffff1611156119fa576040517fefe64dec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62061a80611a0e6060830160408401613c79565b63ffffffff161115611a4c576040517f615323f900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a5c6060820160408301613c79565b63ffffffff16611a726040830160208401613c94565b62ffffff161115611aaf576040517fb94549ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611abf60a0820160808301613c79565b63ffffffff16611ad56080830160608401613c79565b63ffffffff161115611b13576040517f8a2ebfa100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b2360c0820160a08301613c79565b63ffffffff16611b3960a0830160808401613c79565b63ffffffff161115611b77576040517f033821ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b8760c0820160a08301613c79565b63ffffffff16611b9d6080830160608401613c79565b63ffffffff1610611bda576040517f26b6e66400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620f4240611bee60c0830160a08401613c79565b63ffffffff16111561141b576040517fde7bffc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f90815260076020526040812054808203611c8a576040517ff050992300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8381165f9081526006602090815260408083208151808301835290547affffffffffffffffffffffffffffffffffffffffffffffffffffff811682527b01000000000000000000000000000000000000000000000000000000900464ffffffffff168184015260025482517fceb7f75900000000000000000000000000000000000000000000000000000000815292519195169263ceb7f7599260048082019391829003018187875af1925050508015611d94575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611d919181019061364c565b60015b611da057508051611ec1565b73ffffffffffffffffffffffffffffffffffffffff86165f90815260056020908152604091829020825161012081018452905460ff81161515825261010080820462ffffff1693830193909352640100000000810463ffffffff90811694830194909452680100000000000000008104841660608301526c010000000000000000000000008104841660808301527001000000000000000000000000000000008104841660a0830152740100000000000000000000000000000000000000008104841660c083015278010000000000000000000000000000000000000000000000008104841660e08301527c0100000000000000000000000000000000000000000000000000000000900490921690820152611ebd9082906114b8565b9150505b6040805180820182527affffffffffffffffffffffffffffffffffffffffffffffffffffff808416825264ffffffffff428116602080850191825273ffffffffffffffffffffffffffffffffffffffff8b165f9081526006909152948520935190519091167b01000000000000000000000000000000000000000000000000000000029116179055611f5384846117aa565b90505f6b033b2e3c9fd0803ce8000000611f6d86846136bd565b8873ffffffffffffffffffffffffffffffffffffffff16631b859e416040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fb6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fda919061364c565b611fe491906136d0565b611fee9190613714565b9050801561200d578060045f828254612007919061374c565b90915550505b73ffffffffffffffffffffffffffffffffffffffff87165f8181526007602090815260409182902085905581518481529081018590527f68ca32afbb6c97f78310c45d7fe5e6d900e815be910458a6b4290c6cb5cf31d0910160405180910390a25095945050505050565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f82156120fa57505f6111cb565b6111c86509184e72a00062ffffff84166136d0565b5f677fffffffffffffff821115612124575f5ffd5b5060401b90565b5f815f03612137575f5ffd5b5f8084121561214a57835f039350600190505b5f83121561215a575f9290920391155b5f61216585856124df565b905081156121a6576f80000000000000000000000000000000816fffffffffffffffffffffffffffffffff16111561219b575f5ffd5b5f0391506111cb9050565b6f7fffffffffffffffffffffffffffffff816fffffffffffffffffffffffffffffffff1611156121d4575f5ffd5b91506111cb9050565b5f600f83810b9083900b0260401d7fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113155b6111c8575f5ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000821215801561226c5750677fffffffffffffff8213155b612124575f5ffd5b5f6840000000000000000082600f0b1261228c575f5ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffc0000000000000000082600f0b12156122be57505f919050565b6111cb608083600f0b700171547652b82fe1777d0ffda0d23a7d1202901d61266a565b5f81600f0b5f036122f0575f5ffd5b5f82600f0b604085600f0b901b8161230a5761230a6136e7565b0590507fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113156111c8575f5ffd5b5f815f03612360575f5ffd5b5f61236b84846124df565b90506f7fffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff821611156111c8575f5ffd5b5f600f82810b9084900b037fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113156111c8575f5ffd5b5f600f83810b9083900b017fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061222b57506f7fffffffffffffffffffffffffffffff8113156111c8575f5ffd5b5f6111c861245561244f8561310f565b846121dd565b61266a565b5f815f0361246957505f6111cb565b5f83600f0b1215612478575f5ffd5b600f83900b6fffffffffffffffffffffffffffffffff8316810260401c90608084901c0277ffffffffffffffffffffffffffffffffffffffffffffffff8111156124c0575f5ffd5b60401b81198111156124d0575f5ffd5b019392505050565b80825d5050565b5f815f036124eb575f5ffd5b5f77ffffffffffffffffffffffffffffffffffffffffffffffff84116125265782604085901b8161251e5761251e6136e7565b04905061264e565b60c084811c640100000000811061253f576020918201911c5b620100008110612551576010918201911c5b6101008110612562576008918201911c5b60108110612572576004918201911c5b60048110612582576002918201911c5b60028110612591576001820191505b60bf820360018603901c6001018260ff0387901b816125b2576125b26136e7565b0492506fffffffffffffffffffffffffffffffff8311156125d1575f5ffd5b608085901c83026fffffffffffffffffffffffffffffffff8616840260c088901c604089901b82811015612606576001820391505b608084901b9290038281101561261d576001820391505b829003608084901c8214612632576001612643565b888181612641576126416136e7565b045b870196505050505050505b6fffffffffffffffffffffffffffffffff8111156111c8575f5ffd5b5f6840000000000000000082600f0b12612682575f5ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffc0000000000000000082600f0b12156126b457505f919050565b6f800000000000000000000000000000005f6780000000000000008416600f0b13156126f15770016a09e667f3bcc908b2fb1366ea957d3e0260801c5b5f8367400000000000000016600f0b131561271d577001306fe0a31b7152de8d5a46305c85edec0260801c5b5f8367200000000000000016600f0b1315612749577001172b83c7d517adcdf7c8c50eb14a791f0260801c5b5f8367100000000000000016600f0b13156127755770010b5586cf9890f6298b92b71842a983630260801c5b5f8367080000000000000016600f0b13156127a1577001059b0d31585743ae7c548eb68ca417fd0260801c5b5f8367040000000000000016600f0b13156127cd57700102c9a3e778060ee6f7caca4f7a29bde80260801c5b5f8367020000000000000016600f0b13156127f95770010163da9fb33356d84a66ae336dcdfa3f0260801c5b5f8367010000000000000016600f0b131561282557700100b1afa5abcbed6129ab13ec11dc95430260801c5b5f83668000000000000016600f0b13156128505770010058c86da1c09ea1ff19d294cf2f679b0260801c5b5f83664000000000000016600f0b131561287b577001002c605e2e8cec506d21bfc89a23a00f0260801c5b5f83662000000000000016600f0b13156128a657700100162f3904051fa128bca9c55c31e5df0260801c5b5f83661000000000000016600f0b13156128d1577001000b175effdc76ba38e31671ca9397250260801c5b5f83660800000000000016600f0b13156128fc57700100058ba01fb9f96d6cacd4b180917c3d0260801c5b5f83660400000000000016600f0b13156129275770010002c5cc37da9491d0985c348c68e7b30260801c5b5f83660200000000000016600f0b1315612952577001000162e525ee054754457d59952920260260801c5b5f83660100000000000016600f0b131561297d5770010000b17255775c040618bf4a4ade83fc0260801c5b5f836580000000000016600f0b13156129a7577001000058b91b5bc9ae2eed81e9b7d4cfab0260801c5b5f836540000000000016600f0b13156129d157700100002c5c89d5ec6ca4d7c8acc017b7c90260801c5b5f836520000000000016600f0b13156129fb5770010000162e43f4f831060e02d839a9d16d0260801c5b5f836510000000000016600f0b1315612a2557700100000b1721bcfc99d9f890ea069117630260801c5b5f836508000000000016600f0b1315612a4f5770010000058b90cf1e6d97f9ca14dbcc16280260801c5b5f836504000000000016600f0b1315612a79577001000002c5c863b73f016468f6bac5ca2b0260801c5b5f836502000000000016600f0b1315612aa357700100000162e430e5a18f6119e3c02282a50260801c5b5f836501000000000016600f0b1315612acd577001000000b1721835514b86e6d96efd1bfe0260801c5b5f8364800000000016600f0b1315612af657700100000058b90c0b48c6be5df846c5b2ef0260801c5b5f8364400000000016600f0b1315612b1f5770010000002c5c8601cc6b9e94213c72737a0260801c5b5f8364200000000016600f0b1315612b48577001000000162e42fff037df38aa2b219f060260801c5b5f8364100000000016600f0b1315612b715770010000000b17217fba9c739aa5819f44f90260801c5b5f8364080000000016600f0b1315612b9a577001000000058b90bfcdee5acd3c1cedc8230260801c5b5f8364040000000016600f0b1315612bc357700100000002c5c85fe31f35a6a30da1be500260801c5b5f8364020000000016600f0b1315612bec5770010000000162e42ff0999ce3541b9fffcf0260801c5b5f8364010000000016600f0b1315612c1557700100000000b17217f80f4ef5aadda455540260801c5b5f83638000000016600f0b1315612c3d5770010000000058b90bfbf8479bd5a81b51ad0260801c5b5f83634000000016600f0b1315612c65577001000000002c5c85fdf84bd62ae30a74cc0260801c5b5f83632000000016600f0b1315612c8d57700100000000162e42fefb2fed257559bdaa0260801c5b5f83631000000016600f0b1315612cb5577001000000000b17217f7d5a7716bba4a9ae0260801c5b5f83630800000016600f0b1315612cdd57700100000000058b90bfbe9ddbac5e109cce0260801c5b5f83630400000016600f0b1315612d055770010000000002c5c85fdf4b15de6f17eb0d0260801c5b5f83630200000016600f0b1315612d2d577001000000000162e42fefa494f1478fde050260801c5b5f83630100000016600f0b1315612d555770010000000000b17217f7d20cf927c8e94c0260801c5b5f836280000016600f0b1315612d7c577001000000000058b90bfbe8f71cb4e4b33d0260801c5b5f836240000016600f0b1315612da357700100000000002c5c85fdf477b662b269450260801c5b5f836220000016600f0b1315612dca5770010000000000162e42fefa3ae53369388c0260801c5b5f836210000016600f0b1315612df157700100000000000b17217f7d1d351a389d400260801c5b5f836208000016600f0b1315612e185770010000000000058b90bfbe8e8b2d3d4ede0260801c5b5f836204000016600f0b1315612e3f577001000000000002c5c85fdf4741bea6e77e0260801c5b5f836202000016600f0b1315612e6657700100000000000162e42fefa39fe95583c20260801c5b5f836201000016600f0b1315612e8d577001000000000000b17217f7d1cfb72b45e10260801c5b5f8361800016600f0b1315612eb357700100000000000058b90bfbe8e7cc35c3f00260801c5b5f8361400016600f0b1315612ed95770010000000000002c5c85fdf473e242ea380260801c5b5f8361200016600f0b1315612eff577001000000000000162e42fefa39f02b772c0260801c5b5f8361100016600f0b1315612f255770010000000000000b17217f7d1cf7d83c1a0260801c5b5f8361080016600f0b1315612f4b577001000000000000058b90bfbe8e7bdcbe2e0260801c5b5f8361040016600f0b1315612f7157700100000000000002c5c85fdf473dea871f0260801c5b5f8361020016600f0b1315612f975770010000000000000162e42fefa39ef44d910260801c5b5f8361010016600f0b1315612fbd57700100000000000000b17217f7d1cf79e9490260801c5b5f83608016600f0b1315612fe25770010000000000000058b90bfbe8e7bce5440260801c5b5f83604016600f0b1315613007577001000000000000002c5c85fdf473de6eca0260801c5b5f83602016600f0b131561302c57700100000000000000162e42fefa39ef366f0260801c5b5f83601016600f0b1315613051577001000000000000000b17217f7d1cf79afa0260801c5b5f83600816600f0b131561307657700100000000000000058b90bfbe8e7bcd6d0260801c5b5f83600416600f0b131561309b5770010000000000000002c5c85fdf473de6b20260801c5b5f83600216600f0b13156130c0577001000000000000000162e42fefa39ef3580260801c5b5f83600116600f0b13156130e55770010000000000000000b17217f7d1cf79ab0260801c5b600f83810b60401d603f03900b1c6f7fffffffffffffffffffffffffffffff8111156111cb575f5ffd5b5f5f82600f0b1361311e575f5ffd5b5f600f83900b68010000000000000000811261313c576040918201911d5b6401000000008112613150576020918201911d5b620100008112613162576010918201911d5b6101008112613173576008918201911d5b60108112613183576004918201911d5b60048112613193576002918201911d5b600281126131a2576001820191505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820160401b600f85900b607f8490031b6780000000000000005b5f8113156132025790800260ff81901c8281029390930192607f011c9060011d6131dd565b509095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461141b575f5ffd5b5f6020828403121561323e575f5ffd5b81356111c88161320d565b5f5f6020838503121561325a575f5ffd5b823567ffffffffffffffff811115613270575f5ffd5b8301601f81018513613280575f5ffd5b803567ffffffffffffffff811115613296575f5ffd5b8560208260051b84010111156132aa575f5ffd5b6020919091019590945092505050565b5f5f8284036101408112156132cd575f5ffd5b83356132d88161320d565b92506101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561330a575f5ffd5b506020830190509250929050565b604051610120810167ffffffffffffffff81118282101715613361577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405290565b5f5f8284036060811215613379575f5ffd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0820112156133ac575f5ffd5b506040805190810167ffffffffffffffff811182821017156133f5577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405260208401357affffffffffffffffffffffffffffffffffffffffffffffffffffff81168114613425575f5ffd5b8152604084013564ffffffffff8116811461343e575f5ffd5b6020820152919491935090915050565b801515811461141b575f5ffd5b80356111b88161344e565b62ffffff8116811461141b575f5ffd5b80356111b881613466565b63ffffffff8116811461141b575f5ffd5b80356111b881613481565b5f61012082840312156134ae575f5ffd5b6134b6613318565b90506134c18261345b565b81526134cf60208301613476565b60208201526134e060408301613492565b60408201526134f160608301613492565b606082015261350260808301613492565b608082015261351360a08301613492565b60a082015261352460c08301613492565b60c082015261353560e08301613492565b60e08201526135476101008301613492565b61010082015292915050565b5f5f6101408385031215613565575f5ffd5b82359150613576846020850161349d565b90509250929050565b5f6101208201905082511515825262ffffff602084015116602083015260408301516135b3604084018263ffffffff169052565b5060608301516135cb606084018263ffffffff169052565b5060808301516135e3608084018263ffffffff169052565b5060a08301516135fb60a084018263ffffffff169052565b5060c083015161361360c084018263ffffffff169052565b5060e083015161362b60e084018263ffffffff169052565b5061010083015161364561010084018263ffffffff169052565b5092915050565b5f6020828403121561365c575f5ffd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156111cb576111cb613690565b80820281158282048414176111cb576111cb613690565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f82613747577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b808201808211156111cb576111cb613690565b5f81356111cb81613481565b81356137768161344e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541660ff8215151681178355505060208201356137b481613466565b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ff1660089190911b63ffffff001617815561382f6137f66040840161375f565b82547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1660209190911b67ffffffff0000000016178255565b61387b61383e6060840161375f565b82547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1660409190911b6bffffffff000000000000000016178255565b6138cb61388a6080840161375f565b82547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff1660609190911b6fffffffff00000000000000000000000016178255565b61391f6138da60a0840161375f565b82547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1660809190911b73ffffffff0000000000000000000000000000000016178255565b61397761392e60c0840161375f565b82547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff1660a09190911b77ffffffff000000000000000000000000000000000000000016178255565b6139d361398660e0840161375f565b82547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7bffffffff00000000000000000000000000000000000000000000000016178255565b610ea56139e3610100840161375f565b82547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e09190911b7fffffffff0000000000000000000000000000000000000000000000000000000016178255565b73ffffffffffffffffffffffffffffffffffffffff8316815261014081018235613a598161344e565b801515602084015250613a6e60208401613476565b62ffffff8116604084015250613a8660408401613492565b63ffffffff8116606084015250613a9f60608401613492565b63ffffffff8116608084015250613ab860808401613492565b63ffffffff811660a084015250613ad160a08401613492565b63ffffffff811660c084015250613aea60c08401613492565b63ffffffff811660e084015250613b0360e08401613492565b63ffffffff811661010084015250613b1e6101008401613492565b63ffffffff8116610120840152509392505050565b5f60208284031215613b43575f5ffd5b81516111c88161344e565b5f6101208284031215613b5f575f5ffd5b6111c8838361349d565b8082025f82127f800000000000000000000000000000000000000000000000000000000000000084141615613ba057613ba0613690565b81810583148215176111cb576111cb613690565b8181035f83128015838313168383128216171561364557613645613690565b5f81600f0b7fffffffffffffffffffffffffffffffff800000000000000000000000000000008103613c0757613c07613690565b5f0392915050565b600f81810b9083900b016f7fffffffffffffffffffffffffffffff81137fffffffffffffffffffffffffffffffff80000000000000000000000000000000821217156111cb576111cb613690565b63ffffffff82811682821603908111156111cb576111cb613690565b5f60208284031215613c89575f5ffd5b81356111c881613481565b5f60208284031215613ca4575f5ffd5b81356111c88161346656fea2646970667358221220e67d3b84e0cdddc879cd26c699144d436214b4b23a8e7ce523755715c6b544e664736f6c634300081c0033000000000000000000000000461b62cb3a7e9df8f800ae058ae92f855f2c27ca000000000000000000000000f3f7669dceed2f985815011c19ed68f667267215000000000000000000000000970b2f2cec66f92de81dae6af363d1d135dd2f97000000000000000000000000b1c2db5d6ca03fce73dbd304d320bf76c55ae1b1","name":"IRCalculator","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"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/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"},{"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/libs/ABDKMath64x64.sol","source_code":"// SPDX-License-Identifier: BSD-4-Clause\n/*\n * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.\n * Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>\n */\npragma solidity ^0.8.0;\n\n/**\n * Smart contract library of mathematical functions operating with signed\n * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is\n * basically a simple fraction whose numerator is signed 128-bit integer and\n * denominator is 2^64.  As long as denominator is always the same, there is no\n * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are\n * represented by int128 type holding only the numerator.\n */\nlibrary ABDKMath64x64 {\n    /*\n     * Minimum value signed 64.64-bit fixed point number may have.\n     */\n    int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;\n\n    /*\n     * Maximum value signed 64.64-bit fixed point number may have.\n     */\n    int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\n\n    /**\n     * Convert signed 256-bit integer number into signed 64.64-bit fixed point\n     * number.  Revert on overflow.\n     *\n     * @param x signed 256-bit integer number\n     * @return signed 64.64-bit fixed point number\n     */\n    function fromInt(int256 x) internal pure returns (int128) {\n        unchecked {\n            require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);\n            return int128(x << 64);\n        }\n    }\n\n    /**\n     * Convert signed 64.64 fixed point number into signed 64-bit integer number\n     * rounding down.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64-bit integer number\n     */\n    function toInt(int128 x) internal pure returns (int64) {\n        unchecked {\n            return int64(x >> 64);\n        }\n    }\n\n    /**\n     * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point\n     * number.  Revert on overflow.\n     *\n     * @param x unsigned 256-bit integer number\n     * @return signed 64.64-bit fixed point number\n     */\n    function fromUInt(uint256 x) internal pure returns (int128) {\n        unchecked {\n            require(x <= 0x7FFFFFFFFFFFFFFF);\n            return int128(int256(x << 64));\n        }\n    }\n\n    /**\n     * Convert signed 64.64 fixed point number into unsigned 64-bit integer\n     * number rounding down.  Revert on underflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return unsigned 64-bit integer number\n     */\n    function toUInt(int128 x) internal pure returns (uint64) {\n        unchecked {\n            require(x >= 0);\n            return uint64(uint128(x >> 64));\n        }\n    }\n\n    /**\n     * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point\n     * number rounding down.  Revert on overflow.\n     *\n     * @param x signed 128.128-bin fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function from128x128(int256 x) internal pure returns (int128) {\n        unchecked {\n            int256 result = x >> 64;\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Convert signed 64.64 fixed point number into signed 128.128 fixed point\n     * number.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 128.128 fixed point number\n     */\n    function to128x128(int128 x) internal pure returns (int256) {\n        unchecked {\n            return int256(x) << 64;\n        }\n    }\n\n    /**\n     * Calculate x + y.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function add(int128 x, int128 y) internal pure returns (int128) {\n        unchecked {\n            int256 result = int256(x) + y;\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate x - y.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function sub(int128 x, int128 y) internal pure returns (int128) {\n        unchecked {\n            int256 result = int256(x) - y;\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate x * y rounding down.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function mul(int128 x, int128 y) internal pure returns (int128) {\n        unchecked {\n            int256 result = (int256(x) * y) >> 64;\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point\n     * number and y is signed 256-bit integer number.  Revert on overflow.\n     *\n     * @param x signed 64.64 fixed point number\n     * @param y signed 256-bit integer number\n     * @return signed 256-bit integer number\n     */\n    function muli(int128 x, int256 y) internal pure returns (int256) {\n        unchecked {\n            if (x == MIN_64x64) {\n                require(y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && y <= 0x1000000000000000000000000000000000000000000000000);\n                return -y << 63;\n            } else {\n                bool negativeResult = false;\n                if (x < 0) {\n                    x = -x;\n                    negativeResult = true;\n                }\n                if (y < 0) {\n                    y = -y; // We rely on overflow behavior here\n                    negativeResult = !negativeResult;\n                }\n                uint256 absoluteResult = mulu(x, uint256(y));\n                if (negativeResult) {\n                    require(absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000);\n                    return -int256(absoluteResult); // We rely on overflow behavior here\n                } else {\n                    require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n                    return int256(absoluteResult);\n                }\n            }\n        }\n    }\n\n    /**\n     * Calculate x * y rounding down, where x is signed 64.64 fixed point number\n     * and y is unsigned 256-bit integer number.  Revert on overflow.\n     *\n     * @param x signed 64.64 fixed point number\n     * @param y unsigned 256-bit integer number\n     * @return unsigned 256-bit integer number\n     */\n    function mulu(int128 x, uint256 y) internal pure returns (uint256) {\n        unchecked {\n            if (y == 0) return 0;\n\n            require(x >= 0);\n\n            uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;\n            uint256 hi = uint256(int256(x)) * (y >> 128);\n\n            require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n            hi <<= 64;\n\n            require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);\n            return hi + lo;\n        }\n    }\n\n    /**\n     * Calculate x / y rounding towards zero.  Revert on overflow or when y is\n     * zero.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function div(int128 x, int128 y) internal pure returns (int128) {\n        unchecked {\n            require(y != 0);\n            int256 result = (int256(x) << 64) / y;\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate x / y rounding towards zero, where x and y are signed 256-bit\n     * integer numbers.  Revert on overflow or when y is zero.\n     *\n     * @param x signed 256-bit integer number\n     * @param y signed 256-bit integer number\n     * @return signed 64.64-bit fixed point number\n     */\n    function divi(int256 x, int256 y) internal pure returns (int128) {\n        unchecked {\n            require(y != 0);\n\n            bool negativeResult = false;\n            if (x < 0) {\n                x = -x; // We rely on overflow behavior here\n                negativeResult = true;\n            }\n            if (y < 0) {\n                y = -y; // We rely on overflow behavior here\n                negativeResult = !negativeResult;\n            }\n            uint128 absoluteResult = divuu(uint256(x), uint256(y));\n            if (negativeResult) {\n                require(absoluteResult <= 0x80000000000000000000000000000000);\n                return -int128(absoluteResult); // We rely on overflow behavior here\n            } else {\n                require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n                return int128(absoluteResult); // We rely on overflow behavior here\n            }\n        }\n    }\n\n    /**\n     * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit\n     * integer numbers.  Revert on overflow or when y is zero.\n     *\n     * @param x unsigned 256-bit integer number\n     * @param y unsigned 256-bit integer number\n     * @return signed 64.64-bit fixed point number\n     */\n    function divu(uint256 x, uint256 y) internal pure returns (int128) {\n        unchecked {\n            require(y != 0);\n            uint128 result = divuu(x, y);\n            require(result <= uint128(MAX_64x64));\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate -x.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function neg(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x != MIN_64x64);\n            return -x;\n        }\n    }\n\n    /**\n     * Calculate |x|.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function abs(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x != MIN_64x64);\n            return x < 0 ? -x : x;\n        }\n    }\n\n    /**\n     * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is\n     * zero.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function inv(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x != 0);\n            int256 result = int256(0x100000000000000000000000000000000) / x;\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function avg(int128 x, int128 y) internal pure returns (int128) {\n        unchecked {\n            return int128((int256(x) + int256(y)) >> 1);\n        }\n    }\n\n    /**\n     * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.\n     * Revert on overflow or in case x * y is negative.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function gavg(int128 x, int128 y) internal pure returns (int128) {\n        unchecked {\n            int256 m = int256(x) * int256(y);\n            require(m >= 0);\n            require(m < 0x4000000000000000000000000000000000000000000000000000000000000000);\n            return int128(sqrtu(uint256(m)));\n        }\n    }\n\n    /**\n     * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number\n     * and y is unsigned 256-bit integer number.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @param y uint256 value\n     * @return signed 64.64-bit fixed point number\n     */\n    function pow(int128 x, uint256 y) internal pure returns (int128) {\n        unchecked {\n            bool negative = x < 0 && y & 1 == 1;\n\n            uint256 absX = uint128(x < 0 ? -x : x);\n            uint256 absResult;\n            absResult = 0x100000000000000000000000000000000;\n\n            if (absX <= 0x10000000000000000) {\n                absX <<= 63;\n                while (y != 0) {\n                    if (y & 0x1 != 0) {\n                        absResult = (absResult * absX) >> 127;\n                    }\n                    absX = (absX * absX) >> 127;\n\n                    if (y & 0x2 != 0) {\n                        absResult = (absResult * absX) >> 127;\n                    }\n                    absX = (absX * absX) >> 127;\n\n                    if (y & 0x4 != 0) {\n                        absResult = (absResult * absX) >> 127;\n                    }\n                    absX = (absX * absX) >> 127;\n\n                    if (y & 0x8 != 0) {\n                        absResult = (absResult * absX) >> 127;\n                    }\n                    absX = (absX * absX) >> 127;\n\n                    y >>= 4;\n                }\n\n                absResult >>= 64;\n            } else {\n                uint256 absXShift = 63;\n                if (absX < 0x1000000000000000000000000) {\n                    absX <<= 32;\n                    absXShift -= 32;\n                }\n                if (absX < 0x10000000000000000000000000000) {\n                    absX <<= 16;\n                    absXShift -= 16;\n                }\n                if (absX < 0x1000000000000000000000000000000) {\n                    absX <<= 8;\n                    absXShift -= 8;\n                }\n                if (absX < 0x10000000000000000000000000000000) {\n                    absX <<= 4;\n                    absXShift -= 4;\n                }\n                if (absX < 0x40000000000000000000000000000000) {\n                    absX <<= 2;\n                    absXShift -= 2;\n                }\n                if (absX < 0x80000000000000000000000000000000) {\n                    absX <<= 1;\n                    absXShift -= 1;\n                }\n\n                uint256 resultShift = 0;\n                while (y != 0) {\n                    require(absXShift < 64);\n\n                    if (y & 0x1 != 0) {\n                        absResult = (absResult * absX) >> 127;\n                        resultShift += absXShift;\n                        if (absResult > 0x100000000000000000000000000000000) {\n                            absResult >>= 1;\n                            resultShift += 1;\n                        }\n                    }\n                    absX = (absX * absX) >> 127;\n                    absXShift <<= 1;\n                    if (absX >= 0x100000000000000000000000000000000) {\n                        absX >>= 1;\n                        absXShift += 1;\n                    }\n\n                    y >>= 1;\n                }\n\n                require(resultShift < 64);\n                absResult >>= 64 - resultShift;\n            }\n            int256 result = negative ? -int256(absResult) : int256(absResult);\n            require(result >= MIN_64x64 && result <= MAX_64x64);\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate sqrt (x) rounding down.  Revert if x < 0.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function sqrt(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x >= 0);\n            return int128(sqrtu(uint256(int256(x)) << 64));\n        }\n    }\n\n    /**\n     * Calculate binary logarithm of x.  Revert if x <= 0.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function log_2(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x > 0);\n\n            int256 msb = 0;\n            int256 xc = x;\n            if (xc >= 0x10000000000000000) {\n                xc >>= 64;\n                msb += 64;\n            }\n            if (xc >= 0x100000000) {\n                xc >>= 32;\n                msb += 32;\n            }\n            if (xc >= 0x10000) {\n                xc >>= 16;\n                msb += 16;\n            }\n            if (xc >= 0x100) {\n                xc >>= 8;\n                msb += 8;\n            }\n            if (xc >= 0x10) {\n                xc >>= 4;\n                msb += 4;\n            }\n            if (xc >= 0x4) {\n                xc >>= 2;\n                msb += 2;\n            }\n            if (xc >= 0x2) msb += 1; // No need to shift xc anymore\n\n            int256 result = (msb - 64) << 64;\n            uint256 ux = uint256(int256(x)) << uint256(127 - msb);\n            for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {\n                ux *= ux;\n                uint256 b = ux >> 255;\n                ux >>= 127 + b;\n                result += bit * int256(b);\n            }\n\n            return int128(result);\n        }\n    }\n\n    /**\n     * Calculate natural logarithm of x.  Revert if x <= 0.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function ln(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x > 0);\n\n            return int128(int256((uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF) >> 128));\n        }\n    }\n\n    /**\n     * Calculate binary exponent of x.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function exp_2(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x < 0x400000000000000000); // Overflow\n\n            if (x < -0x400000000000000000) return 0; // Underflow\n\n            uint256 result = 0x80000000000000000000000000000000;\n\n            if (x & 0x8000000000000000 > 0) result = (result * 0x16A09E667F3BCC908B2FB1366EA957D3E) >> 128;\n            if (x & 0x4000000000000000 > 0) result = (result * 0x1306FE0A31B7152DE8D5A46305C85EDEC) >> 128;\n            if (x & 0x2000000000000000 > 0) result = (result * 0x1172B83C7D517ADCDF7C8C50EB14A791F) >> 128;\n            if (x & 0x1000000000000000 > 0) result = (result * 0x10B5586CF9890F6298B92B71842A98363) >> 128;\n            if (x & 0x800000000000000 > 0) result = (result * 0x1059B0D31585743AE7C548EB68CA417FD) >> 128;\n            if (x & 0x400000000000000 > 0) result = (result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8) >> 128;\n            if (x & 0x200000000000000 > 0) result = (result * 0x10163DA9FB33356D84A66AE336DCDFA3F) >> 128;\n            if (x & 0x100000000000000 > 0) result = (result * 0x100B1AFA5ABCBED6129AB13EC11DC9543) >> 128;\n            if (x & 0x80000000000000 > 0) result = (result * 0x10058C86DA1C09EA1FF19D294CF2F679B) >> 128;\n            if (x & 0x40000000000000 > 0) result = (result * 0x1002C605E2E8CEC506D21BFC89A23A00F) >> 128;\n            if (x & 0x20000000000000 > 0) result = (result * 0x100162F3904051FA128BCA9C55C31E5DF) >> 128;\n            if (x & 0x10000000000000 > 0) result = (result * 0x1000B175EFFDC76BA38E31671CA939725) >> 128;\n            if (x & 0x8000000000000 > 0) result = (result * 0x100058BA01FB9F96D6CACD4B180917C3D) >> 128;\n            if (x & 0x4000000000000 > 0) result = (result * 0x10002C5CC37DA9491D0985C348C68E7B3) >> 128;\n            if (x & 0x2000000000000 > 0) result = (result * 0x1000162E525EE054754457D5995292026) >> 128;\n            if (x & 0x1000000000000 > 0) result = (result * 0x10000B17255775C040618BF4A4ADE83FC) >> 128;\n            if (x & 0x800000000000 > 0) result = (result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB) >> 128;\n            if (x & 0x400000000000 > 0) result = (result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9) >> 128;\n            if (x & 0x200000000000 > 0) result = (result * 0x10000162E43F4F831060E02D839A9D16D) >> 128;\n            if (x & 0x100000000000 > 0) result = (result * 0x100000B1721BCFC99D9F890EA06911763) >> 128;\n            if (x & 0x80000000000 > 0) result = (result * 0x10000058B90CF1E6D97F9CA14DBCC1628) >> 128;\n            if (x & 0x40000000000 > 0) result = (result * 0x1000002C5C863B73F016468F6BAC5CA2B) >> 128;\n            if (x & 0x20000000000 > 0) result = (result * 0x100000162E430E5A18F6119E3C02282A5) >> 128;\n            if (x & 0x10000000000 > 0) result = (result * 0x1000000B1721835514B86E6D96EFD1BFE) >> 128;\n            if (x & 0x8000000000 > 0) result = (result * 0x100000058B90C0B48C6BE5DF846C5B2EF) >> 128;\n            if (x & 0x4000000000 > 0) result = (result * 0x10000002C5C8601CC6B9E94213C72737A) >> 128;\n            if (x & 0x2000000000 > 0) result = (result * 0x1000000162E42FFF037DF38AA2B219F06) >> 128;\n            if (x & 0x1000000000 > 0) result = (result * 0x10000000B17217FBA9C739AA5819F44F9) >> 128;\n            if (x & 0x800000000 > 0) result = (result * 0x1000000058B90BFCDEE5ACD3C1CEDC823) >> 128;\n            if (x & 0x400000000 > 0) result = (result * 0x100000002C5C85FE31F35A6A30DA1BE50) >> 128;\n            if (x & 0x200000000 > 0) result = (result * 0x10000000162E42FF0999CE3541B9FFFCF) >> 128;\n            if (x & 0x100000000 > 0) result = (result * 0x100000000B17217F80F4EF5AADDA45554) >> 128;\n            if (x & 0x80000000 > 0) result = (result * 0x10000000058B90BFBF8479BD5A81B51AD) >> 128;\n            if (x & 0x40000000 > 0) result = (result * 0x1000000002C5C85FDF84BD62AE30A74CC) >> 128;\n            if (x & 0x20000000 > 0) result = (result * 0x100000000162E42FEFB2FED257559BDAA) >> 128;\n            if (x & 0x10000000 > 0) result = (result * 0x1000000000B17217F7D5A7716BBA4A9AE) >> 128;\n            if (x & 0x8000000 > 0) result = (result * 0x100000000058B90BFBE9DDBAC5E109CCE) >> 128;\n            if (x & 0x4000000 > 0) result = (result * 0x10000000002C5C85FDF4B15DE6F17EB0D) >> 128;\n            if (x & 0x2000000 > 0) result = (result * 0x1000000000162E42FEFA494F1478FDE05) >> 128;\n            if (x & 0x1000000 > 0) result = (result * 0x10000000000B17217F7D20CF927C8E94C) >> 128;\n            if (x & 0x800000 > 0) result = (result * 0x1000000000058B90BFBE8F71CB4E4B33D) >> 128;\n            if (x & 0x400000 > 0) result = (result * 0x100000000002C5C85FDF477B662B26945) >> 128;\n            if (x & 0x200000 > 0) result = (result * 0x10000000000162E42FEFA3AE53369388C) >> 128;\n            if (x & 0x100000 > 0) result = (result * 0x100000000000B17217F7D1D351A389D40) >> 128;\n            if (x & 0x80000 > 0) result = (result * 0x10000000000058B90BFBE8E8B2D3D4EDE) >> 128;\n            if (x & 0x40000 > 0) result = (result * 0x1000000000002C5C85FDF4741BEA6E77E) >> 128;\n            if (x & 0x20000 > 0) result = (result * 0x100000000000162E42FEFA39FE95583C2) >> 128;\n            if (x & 0x10000 > 0) result = (result * 0x1000000000000B17217F7D1CFB72B45E1) >> 128;\n            if (x & 0x8000 > 0) result = (result * 0x100000000000058B90BFBE8E7CC35C3F0) >> 128;\n            if (x & 0x4000 > 0) result = (result * 0x10000000000002C5C85FDF473E242EA38) >> 128;\n            if (x & 0x2000 > 0) result = (result * 0x1000000000000162E42FEFA39F02B772C) >> 128;\n            if (x & 0x1000 > 0) result = (result * 0x10000000000000B17217F7D1CF7D83C1A) >> 128;\n            if (x & 0x800 > 0) result = (result * 0x1000000000000058B90BFBE8E7BDCBE2E) >> 128;\n            if (x & 0x400 > 0) result = (result * 0x100000000000002C5C85FDF473DEA871F) >> 128;\n            if (x & 0x200 > 0) result = (result * 0x10000000000000162E42FEFA39EF44D91) >> 128;\n            if (x & 0x100 > 0) result = (result * 0x100000000000000B17217F7D1CF79E949) >> 128;\n            if (x & 0x80 > 0) result = (result * 0x10000000000000058B90BFBE8E7BCE544) >> 128;\n            if (x & 0x40 > 0) result = (result * 0x1000000000000002C5C85FDF473DE6ECA) >> 128;\n            if (x & 0x20 > 0) result = (result * 0x100000000000000162E42FEFA39EF366F) >> 128;\n            if (x & 0x10 > 0) result = (result * 0x1000000000000000B17217F7D1CF79AFA) >> 128;\n            if (x & 0x8 > 0) result = (result * 0x100000000000000058B90BFBE8E7BCD6D) >> 128;\n            if (x & 0x4 > 0) result = (result * 0x10000000000000002C5C85FDF473DE6B2) >> 128;\n            if (x & 0x2 > 0) result = (result * 0x1000000000000000162E42FEFA39EF358) >> 128;\n            if (x & 0x1 > 0) result = (result * 0x10000000000000000B17217F7D1CF79AB) >> 128;\n\n            result >>= uint256(int256(63 - (x >> 64)));\n            require(result <= uint256(int256(MAX_64x64)));\n\n            return int128(int256(result));\n        }\n    }\n\n    /**\n     * Calculate natural exponent of x.  Revert on overflow.\n     *\n     * @param x signed 64.64-bit fixed point number\n     * @return signed 64.64-bit fixed point number\n     */\n    function exp(int128 x) internal pure returns (int128) {\n        unchecked {\n            require(x < 0x400000000000000000); // Overflow\n\n            if (x < -0x400000000000000000) return 0; // Underflow\n\n            return exp_2(int128((int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12) >> 128));\n        }\n    }\n\n    /**\n     * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit\n     * integer numbers.  Revert on overflow or when y is zero.\n     *\n     * @param x unsigned 256-bit integer number\n     * @param y unsigned 256-bit integer number\n     * @return unsigned 64.64-bit fixed point number\n     */\n    function divuu(uint256 x, uint256 y) private pure returns (uint128) {\n        unchecked {\n            require(y != 0);\n\n            uint256 result;\n\n            if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) result = (x << 64) / y;\n            else {\n                uint256 msb = 192;\n                uint256 xc = x >> 192;\n                if (xc >= 0x100000000) {\n                    xc >>= 32;\n                    msb += 32;\n                }\n                if (xc >= 0x10000) {\n                    xc >>= 16;\n                    msb += 16;\n                }\n                if (xc >= 0x100) {\n                    xc >>= 8;\n                    msb += 8;\n                }\n                if (xc >= 0x10) {\n                    xc >>= 4;\n                    msb += 4;\n                }\n                if (xc >= 0x4) {\n                    xc >>= 2;\n                    msb += 2;\n                }\n                if (xc >= 0x2) msb += 1; // No need to shift xc anymore\n\n                result = (x << (255 - msb)) / (((y - 1) >> (msb - 191)) + 1);\n                require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n\n                uint256 hi = result * (y >> 128);\n                uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n\n                uint256 xh = x >> 192;\n                uint256 xl = x << 64;\n\n                if (xl < lo) xh -= 1;\n                xl -= lo; // We rely on overflow behavior here\n                lo = hi << 128;\n                if (xl < lo) xh -= 1;\n                xl -= lo; // We rely on overflow behavior here\n\n                result += xh == hi >> 128 ? xl / y : 1;\n            }\n\n            require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n            return uint128(result);\n        }\n    }\n\n    /**\n     * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer\n     * number.\n     *\n     * @param x unsigned 256-bit integer number\n     * @return unsigned 128-bit integer number\n     */\n    function sqrtu(uint256 x) private pure returns (uint128) {\n        unchecked {\n            if (x == 0) return 0;\n            else {\n                uint256 xx = x;\n                uint256 r = 1;\n                if (xx >= 0x100000000000000000000000000000000) {\n                    xx >>= 128;\n                    r <<= 64;\n                }\n                if (xx >= 0x10000000000000000) {\n                    xx >>= 64;\n                    r <<= 32;\n                }\n                if (xx >= 0x100000000) {\n                    xx >>= 32;\n                    r <<= 16;\n                }\n                if (xx >= 0x10000) {\n                    xx >>= 16;\n                    r <<= 8;\n                }\n                if (xx >= 0x100) {\n                    xx >>= 8;\n                    r <<= 4;\n                }\n                if (xx >= 0x10) {\n                    xx >>= 4;\n                    r <<= 2;\n                }\n                if (xx >= 0x4) {\n                    r <<= 1;\n                }\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1;\n                r = (r + x / r) >> 1; // Seven iterations should be enough\n                uint256 r1 = x / r;\n                return uint128(r < r1 ? r : r1);\n            }\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":"@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/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/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/interfaces/externals/LlamaLend/IAggregatorStablePriceV3.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\ninterface IAggregatorStablePriceV3 {\n    event AddPricePair(uint256 indexed n, address indexed pool, bool is_inverse);\n    event RemovePricePair(uint256 indexed n);\n    event MovePricePair(uint256 indexed n_from, uint256 indexed n_to);\n    event SetAdmin(address indexed admin);\n\n    function MAX_PAIRS() external pure returns (uint256);\n    function MIN_LIQUIDITY() external pure returns (uint256);\n    function TVL_MA_TIME() external pure returns (uint256);\n\n    function price_pairs(uint256) external view returns (address pool, bool is_inverse);\n    function n_price_pairs() external view returns (uint256);\n    function last_timestamp() external view returns (uint256);\n    function last_tvl(uint256) external view returns (uint256);\n    function last_price() external view returns (uint256);\n    function admin() external view returns (address);\n\n    function set_admin(address _admin) external;\n    function sigma() external view returns (uint256);\n    function stablecoin() external view returns (address);\n    function add_price_pair(address _pool) external;\n    function remove_price_pair(uint256 n) external;\n    function ema_tvl() external view returns (uint256[] memory);\n    function price() external view returns (uint256);\n    function price_w() external returns (uint256);\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/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/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"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"contract IControlTower","name":"_controlTower","type":"address"},{"internalType":"contract IAggregatorStablePriceV3","name":"_USGOracle","type":"address"},{"internalType":"contract IUSG","name":"_USG","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"A1TooBig","type":"error"},{"inputs":[],"name":"A2TooBig","type":"error"},{"inputs":[],"name":"CallerNotMarketCreator","type":"error"},{"inputs":[],"name":"IRStartPriceLtOne","type":"error"},{"inputs":[],"name":"KTooBig","type":"error"},{"inputs":[],"name":"NotAMarket","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":"PInfBiggerThanPMax","type":"error"},{"inputs":[],"name":"PMaxBiggerThanOneDollar","type":"error"},{"inputs":[],"name":"PMinBiggerThanPInf","type":"error"},{"inputs":[],"name":"PMinBiggerThanPMax","type":"error"},{"inputs":[],"name":"RMaxTooBig","type":"error"},{"inputs":[],"name":"RMinBiggerThanRMax","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"market","type":"address"},{"indexed":false,"internalType":"uint256","name":"irAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newIndex","type":"uint256"}],"name":"CheckpointIR","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":"address","name":"market","type":"address"},{"components":[{"internalType":"bool","name":"isHEC","type":"bool"},{"internalType":"uint24","name":"rMin","type":"uint24"},{"internalType":"uint32","name":"rMax","type":"uint32"},{"internalType":"uint32","name":"pMin","type":"uint32"},{"internalType":"uint32","name":"pInf","type":"uint32"},{"internalType":"uint32","name":"pMax","type":"uint32"},{"internalType":"uint32","name":"a1","type":"uint32"},{"internalType":"uint32","name":"a2","type":"uint32"},{"internalType":"uint32","name":"k","type":"uint32"}],"indexed":false,"internalType":"struct IRParams","name":"_irParam","type":"tuple"}],"name":"SetIRParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IAggregatorStablePriceV3","name":"usgOracle","type":"address"}],"name":"SetUSGOracle","type":"event"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USG","outputs":[{"internalType":"contract IUSG","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USGOracle","outputs":[{"internalType":"contract IAggregatorStablePriceV3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"checkpointIR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"markets","type":"address[]"}],"name":"checkpointIRMulti","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"computeIRForMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controlTower","outputs":[{"internalType":"contract IControlTower","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"debtIndexes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getIRCheckpoint","outputs":[{"components":[{"internalType":"uint216","name":"ir","type":"uint216"},{"internalType":"uint40","name":"timestamp","type":"uint40"}],"internalType":"struct IRCheckpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"getIRParams","outputs":[{"components":[{"internalType":"bool","name":"isHEC","type":"bool"},{"internalType":"uint24","name":"rMin","type":"uint24"},{"internalType":"uint32","name":"rMax","type":"uint32"},{"internalType":"uint32","name":"pMin","type":"uint32"},{"internalType":"uint32","name":"pInf","type":"uint32"},{"internalType":"uint32","name":"pMax","type":"uint32"},{"internalType":"uint32","name":"a1","type":"uint32"},{"internalType":"uint32","name":"a2","type":"uint32"},{"internalType":"uint32","name":"k","type":"uint32"}],"internalType":"struct IRParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"indexDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"},{"components":[{"internalType":"bool","name":"isHEC","type":"bool"},{"internalType":"uint24","name":"rMin","type":"uint24"},{"internalType":"uint32","name":"rMax","type":"uint32"},{"internalType":"uint32","name":"pMin","type":"uint32"},{"internalType":"uint32","name":"pInf","type":"uint32"},{"internalType":"uint32","name":"pMax","type":"uint32"},{"internalType":"uint32","name":"a1","type":"uint32"},{"internalType":"uint32","name":"a2","type":"uint32"},{"internalType":"uint32","name":"k","type":"uint32"}],"internalType":"struct IRParams","name":"_irParam","type":"tuple"}],"name":"initializeMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"irCheckpoints","outputs":[{"internalType":"uint216","name":"ir","type":"uint216"},{"internalType":"uint40","name":"timestamp","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"irParams","outputs":[{"internalType":"bool","name":"isHEC","type":"bool"},{"internalType":"uint24","name":"rMin","type":"uint24"},{"internalType":"uint32","name":"rMax","type":"uint32"},{"internalType":"uint32","name":"pMin","type":"uint32"},{"internalType":"uint32","name":"pInf","type":"uint32"},{"internalType":"uint32","name":"pMax","type":"uint32"},{"internalType":"uint32","name":"a1","type":"uint32"},{"internalType":"uint32","name":"a2","type":"uint32"},{"internalType":"uint32","name":"k","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintIR","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintableInterests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"market","type":"address"}],"name":"newDebtIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IAggregatorStablePriceV3","name":"_USGOracle","type":"address"}],"name":"setUSGOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"USGPrice","type":"uint256"},{"components":[{"internalType":"bool","name":"isHEC","type":"bool"},{"internalType":"uint24","name":"rMin","type":"uint24"},{"internalType":"uint32","name":"rMax","type":"uint32"},{"internalType":"uint32","name":"pMin","type":"uint32"},{"internalType":"uint32","name":"pInf","type":"uint32"},{"internalType":"uint32","name":"pMax","type":"uint32"},{"internalType":"uint32","name":"a1","type":"uint32"},{"internalType":"uint32","name":"a2","type":"uint32"},{"internalType":"uint32","name":"k","type":"uint32"}],"internalType":"struct IRParams","name":"irParam","type":"tuple"}],"name":"simulateIR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"oldIndex","type":"uint256"},{"components":[{"internalType":"uint216","name":"ir","type":"uint216"},{"internalType":"uint40","name":"timestamp","type":"uint40"}],"internalType":"struct IRCheckpoint","name":"_checkpoint","type":"tuple"}],"name":"simulateNewDebtIndex","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":"market","type":"address"},{"components":[{"internalType":"bool","name":"isHEC","type":"bool"},{"internalType":"uint24","name":"rMin","type":"uint24"},{"internalType":"uint32","name":"rMax","type":"uint32"},{"internalType":"uint32","name":"pMin","type":"uint32"},{"internalType":"uint32","name":"pInf","type":"uint32"},{"internalType":"uint32","name":"pMax","type":"uint32"},{"internalType":"uint32","name":"a1","type":"uint32"},{"internalType":"uint32","name":"a2","type":"uint32"},{"internalType":"uint32","name":"k","type":"uint32"}],"internalType":"struct IRParams","name":"_irParam","type":"tuple"}],"name":"updateIRParams","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000461b62cb3a7e9df8f800ae058ae92f855f2c27ca000000000000000000000000f3f7669dceed2f985815011c19ed68f667267215000000000000000000000000970b2f2cec66f92de81dae6af363d1d135dd2f97000000000000000000000000b1c2db5d6ca03fce73dbd304d320bf76c55ae1b1"}